diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 3c10ecdd..5f38a3fb 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -35,9 +35,6 @@ jobs: - name: Run tests run: cargo tarpaulin --release --workspace --all-features --out xml - - name: Log costs - run: cat *.costs - - name: Cleanup coverage reports run: rm -f cobertura.xml diff --git a/Cargo.lock b/Cargo.lock index aa30851c..48c264d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -956,11 +956,11 @@ dependencies = [ [[package]] name = "chia-sdk-client" -version = "0.27.0" -source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +version = "0.27.2" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=1199e568df1d8a77a824e166d674a1e913bef211#1199e568df1d8a77a824e166d674a1e913bef211" dependencies = [ "chia-protocol 0.26.0", - "chia-sdk-types 0.27.0", + "chia-sdk-types 0.27.2", "chia-ssl 0.26.0", "chia-traits 0.26.0", "futures-util", @@ -988,8 +988,8 @@ dependencies = [ [[package]] name = "chia-sdk-coinset" -version = "0.27.0" -source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +version = "0.27.2" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=1199e568df1d8a77a824e166d674a1e913bef211#1199e568df1d8a77a824e166d674a1e913bef211" dependencies = [ "chia-protocol 0.26.0", "hex", @@ -1012,8 +1012,8 @@ dependencies = [ [[package]] name = "chia-sdk-derive" -version = "0.27.0" -source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +version = "0.27.2" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=1199e568df1d8a77a824e166d674a1e913bef211#1199e568df1d8a77a824e166d674a1e913bef211" dependencies = [ "convert_case", "quote", @@ -1052,18 +1052,19 @@ dependencies = [ [[package]] name = "chia-sdk-driver" -version = "0.27.0" -source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +version = "0.27.2" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=1199e568df1d8a77a824e166d674a1e913bef211#1199e568df1d8a77a824e166d674a1e913bef211" dependencies = [ "bech32", "bigdecimal", + "bip39", "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-sdk-signer 0.27.2", + "chia-sdk-types 0.27.2", "chia-secp 0.26.0", "chia-sha2 0.26.0", "chia-traits 0.26.0", @@ -1072,11 +1073,14 @@ dependencies = [ "clvm-utils 0.26.0", "clvmr 0.14.0", "flate2", + "getrandom 0.2.15", "hex", "hex-literal", "indexmap 2.10.0", "num-bigint", "once_cell", + "rand 0.8.5", + "rand_chacha 0.3.1", "thiserror 2.0.12", ] @@ -1100,13 +1104,13 @@ dependencies = [ [[package]] name = "chia-sdk-signer" -version = "0.27.0" -source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +version = "0.27.2" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=1199e568df1d8a77a824e166d674a1e913bef211#1199e568df1d8a77a824e166d674a1e913bef211" dependencies = [ "chia-bls 0.26.0", "chia-consensus 0.26.0", "chia-protocol 0.26.0", - "chia-sdk-types 0.27.0", + "chia-sdk-types 0.27.2", "chia-secp 0.26.0", "chia-sha2 0.26.0", "clvm-traits 0.26.0", @@ -1151,8 +1155,8 @@ dependencies = [ [[package]] name = "chia-sdk-test" -version = "0.27.0" -source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +version = "0.27.2" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=1199e568df1d8a77a824e166d674a1e913bef211#1199e568df1d8a77a824e166d674a1e913bef211" dependencies = [ "anyhow", "bip39", @@ -1160,17 +1164,21 @@ dependencies = [ "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-sdk-signer 0.27.2", + "chia-sdk-types 0.27.2", "chia-secp 0.26.0", + "chia-sha2 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", + "prettytable-rs", "rand 0.8.5", "rand_chacha 0.3.1", + "serde", + "serde_json", "thiserror 2.0.12", ] @@ -1197,15 +1205,15 @@ dependencies = [ [[package]] name = "chia-sdk-types" -version = "0.27.0" -source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +version = "0.27.2" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=1199e568df1d8a77a824e166d674a1e913bef211#1199e568df1d8a77a824e166d674a1e913bef211" 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-sdk-derive 0.27.2", "chia-secp 0.26.0", "chia-sha2 0.26.0", "clvm-traits 0.26.0", @@ -1233,8 +1241,8 @@ dependencies = [ [[package]] name = "chia-sdk-utils" -version = "0.27.0" -source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +version = "0.27.2" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=1199e568df1d8a77a824e166d674a1e913bef211#1199e568df1d8a77a824e166d674a1e913bef211" dependencies = [ "bech32", "chia-protocol 0.26.0", @@ -1417,18 +1425,18 @@ dependencies = [ [[package]] name = "chia-wallet-sdk" -version = "0.27.0" -source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=2a056f03b92077fc0ce808ca2e7c01d707d04c43#2a056f03b92077fc0ce808ca2e7c01d707d04c43" +version = "0.27.2" +source = "git+https://github.com/xch-dev/chia-wallet-sdk.git?rev=1199e568df1d8a77a824e166d674a1e913bef211#1199e568df1d8a77a824e166d674a1e913bef211" 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", + "chia-sdk-client 0.27.2", + "chia-sdk-coinset 0.27.2", + "chia-sdk-driver 0.27.2", + "chia-sdk-signer 0.27.2", + "chia-sdk-test 0.27.2", + "chia-sdk-types 0.27.2", + "chia-sdk-utils 0.27.2", "clvm-traits 0.26.0", "clvm-utils 0.26.0", "clvmr 0.14.0", @@ -4427,11 +4435,10 @@ dependencies = [ "anyhow", "axum", "bech32", - "bip39", "chia 0.26.0", "chia-puzzle-types 0.26.0", "chia-puzzles", - "chia-wallet-sdk 0.27.0", + "chia-wallet-sdk 0.27.2", "clap", "clvm-traits 0.26.0", "clvmr 0.14.0", @@ -4441,7 +4448,6 @@ dependencies = [ "futures-util", "getrandom 0.3.2", "hex", - "hex-literal", "openssl", "openssl-sys", "prettytable-rs", diff --git a/Cargo.toml b/Cargo.toml index e4d55453..8e9c5268 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,6 @@ 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" @@ -32,7 +30,7 @@ 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 = { git = "https://github.com/xch-dev/chia-wallet-sdk.git", rev = "2a056f03b92077fc0ce808ca2e7c01d707d04c43", features=["offer-compression"] } +chia-wallet-sdk = { git = "https://github.com/xch-dev/chia-wallet-sdk.git", rev="1199e568df1d8a77a824e166d674a1e913bef211", features=["offer-compression", "action-layer"] } sage-api = { version = "0.10.3", git = "https://github.com/xch-dev/sage.git" } chia-puzzles = "0.20.1" diff --git a/puzzles/actions/reward_distributor/add_incentives.clsp b/puzzles/actions/reward_distributor/add_incentives.clsp deleted file mode 100644 index 3fcc1d01..00000000 --- a/puzzles/actions/reward_distributor/add_incentives.clsp +++ /dev/null @@ -1,60 +0,0 @@ -; add_incentives.clsp by yakuhito -;; Adds incentives for the current epoch - -(mod ( - FEE_PAYOUT_PUZZLE_HASH - FEE_BPS ; * amount / 10000 will be given to the validator - rest is distributed to mirrors - ( - Ephemeral_State . ; not used - (@ - Current_State - ( - total_reserves - active_shares - (cumulative_payout . remaining_rewards) - (@ Round_Time_Info (last_update . epoch_end)) - ) - ) - ) ; Truth - ( - amount . - manager_fee - ) -) - (include condition_codes.clib) - - (if (all (> epoch_end last_update) (> amount 0) (= manager_fee (/ (* amount FEE_BPS) 10000))) - (c - (list - Ephemeral_State ; new ephemeral state - (+ total_reserves (- amount manager_fee)) - active_shares - (c - cumulative_payout - (+ remaining_rewards (- amount manager_fee)) - ) - Round_Time_Info - ) ; new state - (list - (list - CREATE_PUZZLE_ANNOUNCEMENT - (concat 'i' - (sha256 2 - (sha256 1 amount) - (sha256 1 epoch_end) - ) ; (sha256tree (amount . epoch_end)) - ) - ) - ; condition prepended with -42 -> condition will be returned by the reserve - (list -42 - CREATE_COIN - FEE_PAYOUT_PUZZLE_HASH - manager_fee - (list FEE_PAYOUT_PUZZLE_HASH) - ) - ) ; conditions - ) - ; else - (x) - ) -) \ No newline at end of file diff --git a/puzzles/actions/reward_distributor/add_incentives.clsp.hex b/puzzles/actions/reward_distributor/add_incentives.clsp.hex deleted file mode 100644 index a9a979a9..00000000 --- a/puzzles/actions/reward_distributor/add_incentives.clsp.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ffff03ffff22ffff15ff8206f7ff8204f780ffff15ff4fff8080ffff09ff6fffff05ffff14ffff12ff4fff0b80ffff0182271080808080ffff01ff04ffff04ff27ffff04ffff10ff57ffff11ff4fff6f8080ffff04ff81b7ffff04ffff04ff820277ffff10ff820377ffff11ff4fff6f808080ffff04ff8202f7ff808080808080ffff04ffff04ff06ffff04ffff0effff0169ffff0bffff0102ffff0bffff0101ff4f80ffff0bffff0101ff8206f7808080ff808080ffff04ffff04ffff0181d6ffff04ff04ffff04ff05ffff04ff6fffff04ffff04ff05ff8080ff808080808080ff80808080ffff01ff088080ff0180ffff04ffff01ff333eff018080 diff --git a/puzzles/actions/reward_distributor/commit_incentives.clsp b/puzzles/actions/reward_distributor/commit_incentives.clsp deleted file mode 100644 index b56b4a89..00000000 --- a/puzzles/actions/reward_distributor/commit_incentives.clsp +++ /dev/null @@ -1,142 +0,0 @@ -; commit_incentives.clsp by yakuhito -;; Add incentives for a future epoch - -(mod ( - REWARD_SLOT_1ST_CURRY_HASH ; after 1st curry - COMMITMENT_SLOT_1ST_CURRY_HASH ; after 1st curry - EPOCH_SECONDS - ( - Ephemeral_State . ; not used - (@ - Current_State - ( - total_reserves - active_shares - Reward_Info - (@ Round_Time_Info (last_update . epoch_end)) - ) - ) - ) ; Truth - ( - slot_epoch_time - slot_next_epoch_initialized - slot_total_rewards - epoch_start - clawback_ph . - rewards_to_add - ) -) - (include condition_codes.clib) - (include curry.clib) - (include slots.clib) - - (defun create_precommitment_slot_and_announce (COMMITMENT_SLOT_1ST_CURRY_HASH value_hash hint base_conditions) - (c - (list CREATE_PUZZLE_ANNOUNCEMENT (concat 'c' value_hash)) - (c - (create_slot_with_hint_inline COMMITMENT_SLOT_1ST_CURRY_HASH value_hash hint) - base_conditions - ) - ) - ) - - (defun get_epoch_reward_slot_data_hash (slot_epoch_time slot_next_epoch_initialized slot_total_rewards) - (sha256 2 - (sha256 1 slot_epoch_time) - (sha256 2 - (sha256 1 slot_next_epoch_initialized) - (sha256 1 slot_total_rewards) - ) - ) ; (sha256tree (epoch_time next_epoch_initialized . total_rewards)) - ) - - (defun initialize_empty_slots (REWARD_SLOT_1ST_CURRY_HASH EPOCH_SECONDS start_epoch_time end_epoch_time) - (if (= start_epoch_time end_epoch_time) - ; optimization: if adding EPOCH_SECONDS to start_epoch_time will not get to end_epoch_time, - ; this thing will run infinitely (good luck getting that into the mempool) - () - ; else - (c - (create_slot_with_hint_inline REWARD_SLOT_1ST_CURRY_HASH - (get_epoch_reward_slot_data_hash start_epoch_time 1 0) - (sha256 1 start_epoch_time) - ) - (initialize_empty_slots - REWARD_SLOT_1ST_CURRY_HASH - EPOCH_SECONDS - (+ start_epoch_time EPOCH_SECONDS) - end_epoch_time - ) - ) - ) - ) - - (if (all - (not (> epoch_end epoch_start)) ; we're adding incentives to a future epoch - (> rewards_to_add 0) - ) - (c - (list - Ephemeral_State ; new ephemeral state - (+ total_reserves rewards_to_add) - active_shares - Reward_Info - Round_Time_Info - ) ; new state - (create_precommitment_slot_and_announce - COMMITMENT_SLOT_1ST_CURRY_HASH - (sha256 2 - (sha256 1 epoch_start) - (sha256 2 - (sha256 1 clawback_ph) - (sha256 1 rewards_to_add) - ) - ) - clawback_ph - (c - (spend_slot_inline REWARD_SLOT_1ST_CURRY_HASH - (get_epoch_reward_slot_data_hash slot_epoch_time slot_next_epoch_initialized slot_total_rewards) - ) - (if (= epoch_start slot_epoch_time) - ; slot already initialized - just add rewards - (list - (create_slot_with_hint_inline REWARD_SLOT_1ST_CURRY_HASH - (get_epoch_reward_slot_data_hash - slot_epoch_time slot_next_epoch_initialized (+ slot_total_rewards rewards_to_add) - ) - (sha256 1 slot_epoch_time) - ) - ) - ; else - initialize slots up until slot_epoch_time - (if slot_next_epoch_initialized - (x) - ; else - (c - (create_slot_with_hint_inline REWARD_SLOT_1ST_CURRY_HASH - (get_epoch_reward_slot_data_hash - slot_epoch_time 1 slot_total_rewards - ) - (sha256 1 slot_epoch_time) - ) ; update current latest slot's right neighbor from 0 - (c - (create_slot_with_hint_inline REWARD_SLOT_1ST_CURRY_HASH - (get_epoch_reward_slot_data_hash epoch_start 0 rewards_to_add) - (sha256 1 epoch_start) - ) ; create the new latest slot with desired amount - (initialize_empty_slots - REWARD_SLOT_1ST_CURRY_HASH - EPOCH_SECONDS - (+ slot_epoch_time EPOCH_SECONDS) - epoch_start - ) ; initialize all slots in between - ) - ) - ) - ) - ) - ) ; conditions - ) - ; else - (x) - ) -) \ No newline at end of file diff --git a/puzzles/actions/reward_distributor/commit_incentives.clsp.hex b/puzzles/actions/reward_distributor/commit_incentives.clsp.hex deleted file mode 100644 index 23e8afb5..00000000 --- a/puzzles/actions/reward_distributor/commit_incentives.clsp.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ffff03ffff22ffff20ffff15ff820defff8205df8080ffff15ff820fdfff808080ffff01ff04ffff04ff4fffff04ffff10ff81afff820fdf80ffff04ff82016fffff04ff8202efffff04ff8205efff808080808080ffff02ff12ffff04ff02ffff04ff0bffff04ffff0bffff0102ffff0bffff0101ff8205df80ffff0bffff0102ffff0bffff0101ff820bdf80ffff0bffff0101ff820fdf808080ffff04ff820bdfffff04ffff04ffff02ff3effff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff819fffff04ff82015fffff04ff8202dfff808080808080ff8080808080ffff02ffff03ffff09ff8205dfff819f80ffff01ff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff819fffff04ff82015fffff04ffff10ff8202dfff820fdf80ff808080808080ffff04ffff0bffff0101ff819f80ff808080808080ff8080ffff01ff02ffff03ff82015fffff01ff0880ffff01ff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff819fffff04ffff0101ffff04ff8202dfff808080808080ffff04ffff0bffff0101ff819f80ff808080808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff8205dfffff04ff80ffff04ff820fdfff808080808080ffff04ffff0bffff0101ff8205df80ff808080808080ffff02ff2effff04ff02ffff04ff05ffff04ff17ffff04ffff10ff819fff1780ffff04ff8205dfff80808080808080808080ff018080ff018080ff8080808080808080ffff01ff088080ff0180ffff04ffff01ffffff333eff42ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffffff04ffff04ff18ffff04ffff0effff0163ff0b80ff808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ff0bffff04ff17ff808080808080ff2f8080ff04ff10ffff04ffff0bff81bcffff0bff2cffff0bff2cff81dcff0580ffff0bff2cffff0bff81fcffff0bff2cffff0bff2cff81dcffff0bffff0101ff0b8080ffff0bff2cff81dcff819c808080ff819c808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ffff0bffff0102ffff0bffff0101ff0580ffff0bffff0102ffff0bffff0101ff0b80ffff0bffff0101ff17808080ffff02ffff03ffff09ff17ff2f80ff80ffff01ff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff17ffff01ff01ff8080808080ffff04ffff0bffff0101ff1780ff808080808080ffff02ff2effff04ff02ffff04ff05ffff04ff0bffff04ffff10ff17ff0b80ffff04ff2fff808080808080808080ff0180ff04ff14ffff04ffff0112ffff04ff80ffff04ffff0bff81bcffff0bff2cffff0bff2cff81dcff0580ffff0bff2cffff0bff81fcffff0bff2cffff0bff2cff81dcffff0bffff0101ff0b8080ffff0bff2cff81dcff819c808080ff819c808080ff8080808080ff018080 diff --git a/puzzles/actions/reward_distributor/initiate_payout.clsp b/puzzles/actions/reward_distributor/initiate_payout.clsp deleted file mode 100644 index d98987f8..00000000 --- a/puzzles/actions/reward_distributor/initiate_payout.clsp +++ /dev/null @@ -1,85 +0,0 @@ -; initiate_payout.clsp by yakuhito -;; Initiates a payout for a mirror. - -(mod ( - ENTRY_SLOT_1ST_CURRY_HASH ; after 1st curry - PAYOUT_THRESHOLD ; to prevent spam, payout needs to be >= PAYOUT_THRESHOLD - ( - Ephemeral_State . ; not used - (@ - Current_State - ( - total_reserves . - (@ Current_State_Rest ( - active_shares - (@ Reward_Info (cumulative_payout . remaining_rewards)) - Round_Time_Info - )) - ) - ) - ) ; Truth - ( - entry_payout_amount - entry_payout_puzzle_hash - entry_initial_cumulative_payout . - entry_shares - ) -) - (include condition_codes.clib) - (include curry.clib) - (include slots.clib) - - (defun get_slot_data_hash (payout_puzzle_hash cumulative_payout shares) - (sha256 2 - (sha256 1 payout_puzzle_hash) - (sha256 2 - (sha256 1 cumulative_payout) - (sha256 1 shares) - ) - ) ; slot value = (payout_puzzle_hash initial_cumulative_payout . shares) - ) - - (if (all - (= (* (- cumulative_payout entry_initial_cumulative_payout) entry_shares) entry_payout_amount) - (not (> PAYOUT_THRESHOLD entry_payout_amount)) - ) - (c - (c - Ephemeral_State ; new ephemeral state - (c - (- total_reserves entry_payout_amount) - Current_State_Rest - ) ; new state - ) - (list - (spend_slot_inline ENTRY_SLOT_1ST_CURRY_HASH - (get_slot_data_hash entry_payout_puzzle_hash entry_initial_cumulative_payout entry_shares) - ) - - (create_slot_with_hint_inline ENTRY_SLOT_1ST_CURRY_HASH - (get_slot_data_hash entry_payout_puzzle_hash cumulative_payout entry_shares) - entry_payout_puzzle_hash - ) - - (list CREATE_PUZZLE_ANNOUNCEMENT - (concat 'p' - (sha256 2 - (sha256 1 entry_payout_puzzle_hash) - (sha256 1 entry_payout_amount) - ) ; (sha256tree (c entry_payout_puzzle_hash entry_payout_amount)) - ) - ) - - ; leading -42 -> condition will be returned by the reserve - (list -42 - CREATE_COIN - entry_payout_puzzle_hash - entry_payout_amount - (list entry_payout_puzzle_hash) - ) - ) ; conditions - ) - ; esle - (x) - ) -) \ No newline at end of file diff --git a/puzzles/actions/reward_distributor/initiate_payout.clsp.hex b/puzzles/actions/reward_distributor/initiate_payout.clsp.hex deleted file mode 100644 index 631f4b58..00000000 --- a/puzzles/actions/reward_distributor/initiate_payout.clsp.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ffff03ffff22ffff09ffff12ffff11ff820277ff82016f80ff8201ef80ff4f80ffff20ffff15ff0bff4f808080ffff01ff04ffff04ff27ffff04ffff11ff57ff4f80ff778080ffff04ffff02ff1effff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff81afffff04ff82016fffff04ff8201efff808080808080ff8080808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff81afffff04ff820277ffff04ff8201efff808080808080ffff04ff81afff808080808080ffff04ffff04ff18ffff04ffff0effff0170ffff0bffff0102ffff0bffff0101ff81af80ffff0bffff0101ff4f808080ff808080ffff04ffff04ffff0181d6ffff04ff10ffff04ff81afffff04ff4fffff04ffff04ff81afff8080ff808080808080ff808080808080ffff01ff088080ff0180ffff04ffff01ffffff333eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff10ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ffff0bffff0102ffff0bffff0101ff0580ffff0bffff0102ffff0bffff0101ff0b80ffff0bffff0101ff17808080ff04ff14ffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ff8080808080ff018080 diff --git a/puzzles/actions/reward_distributor/manager/add_entry.clsp b/puzzles/actions/reward_distributor/manager/add_entry.clsp deleted file mode 100644 index 91b231af..00000000 --- a/puzzles/actions/reward_distributor/manager/add_entry.clsp +++ /dev/null @@ -1,71 +0,0 @@ -; add_entry.clsp by yakuhito -;; Adds a reward entry to the reward distributor. The entry starts accumulating rewards right away. - -(mod ( - SINGLETON_MOD_HASH - MANAGER_SINGLETON_STRUCT_HASH ; (sha256 SINGLETON_STRUCT) for manager singleton - ENTRY_SLOT_1ST_CURRY_HASH ; after 1st curry - MAX_SECONDS_OFFSET ; at most this amount of seconds can pass since last update - ; /\ this prevents the reward distributor from 'stealing' earned rewards before MAX_SECONDS_OFFSET by - ; adding a mirror with a gazillion shares during long periods of non-sync - ( - Ephemeral_State . ; not used - (@ - Current_State - ( - total_reserves - active_shares - (@ Reward_Info (cumulative_payout . remaining_rewards)) - (@ Round_Time_Info (last_update . epoch_end)) - ) - ) - ) ; Truth - ( - manager_singleton_inner_puzzle_hash - entry_payout_puzzle_hash . - entry_shares - ) -) - (include condition_codes.clib) - (include curry.clib) - (include slots.clib) - - (c - (list - Ephemeral_State - total_reserves - (+ active_shares entry_shares) - Reward_Info - Round_Time_Info - ) ; new state - (list - ; manager actually wants us to add this entry - (list RECEIVE_MESSAGE - 18 ; puzzle hash - puzzle hash - (concat 'a' (sha256 2 - (sha256 1 entry_payout_puzzle_hash) - (sha256 1 entry_shares) - )) ; message = 'a' + (sha265tree (entry_payout_puzzle_hash . entry_shares)) - (curry_hashes_inline SINGLETON_MOD_HASH - MANAGER_SINGLETON_STRUCT_HASH - manager_singleton_inner_puzzle_hash - ) - ) - - (create_slot_with_hint_inline ENTRY_SLOT_1ST_CURRY_HASH - (sha256 2 - (sha256 1 entry_payout_puzzle_hash) - (sha256 2 - (sha256 1 cumulative_payout) - (sha256 1 entry_shares) - ) - ) ; slot value = (payout_puzzle_hash initial_cumulative_payout . shares) - entry_payout_puzzle_hash - ) - - ; make sure the reward info is up to date - (list ASSERT_BEFORE_SECONDS_ABSOLUTE (+ last_update MAX_SECONDS_OFFSET)) - ) ; conditions - ) - -) \ No newline at end of file diff --git a/puzzles/actions/reward_distributor/manager/add_entry.clsp.hex b/puzzles/actions/reward_distributor/manager/add_entry.clsp.hex deleted file mode 100644 index 9b5d84d3..00000000 --- a/puzzles/actions/reward_distributor/manager/add_entry.clsp.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff04ffff04ff819fffff04ff82015fffff04ffff10ff8202dfff8203bf80ffff04ff8205dfffff04ff820bdfff808080808080ffff04ffff04ff1cffff04ffff0112ffff04ffff0effff0161ffff0bffff0102ffff0bffff0101ff8202bf80ffff0bffff0101ff8203bf808080ffff04ffff0bff56ffff0bff0affff0bff0aff66ff0580ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ff0b80ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ff82013f80ffff0bff0aff66ff46808080ff46808080ff46808080ff8080808080ffff04ffff02ff1effff04ff02ffff04ff17ffff04ffff0bffff0102ffff0bffff0101ff8202bf80ffff0bffff0102ffff0bffff0101ff8209df80ffff0bffff0101ff8203bf808080ffff04ff8202bfff808080808080ffff04ffff04ff08ffff04ffff10ff8213dfff2f80ff808080ff8080808080ffff04ffff01ffff55ff3343ff02ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff14ffff04ffff0bff56ffff0bff0affff0bff0aff66ff0580ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ffff0bffff0101ff0b8080ffff0bff0aff66ff46808080ff46808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ff018080 diff --git a/puzzles/actions/reward_distributor/manager/remove_entry.clsp b/puzzles/actions/reward_distributor/manager/remove_entry.clsp deleted file mode 100644 index f424e3a8..00000000 --- a/puzzles/actions/reward_distributor/manager/remove_entry.clsp +++ /dev/null @@ -1,91 +0,0 @@ -; remove_entry.clsp by yakuhito -;; Stops rewarding a specific entry. - -(mod ( - SINGLETON_MOD_HASH - MANAGER_SINGLETON_STRUCT_HASH ; (sha256 SINGLETON_STRUCT) for manager singleton - ENTRY_SLOT_1ST_CURRY_HASH ; after 1st curry - MAX_SECONDS_OFFSET ; at most this amount of seconds can pass since last update - ; /\ this prevents the reward distributor from 'stealing' earned rewards while not - ; dropping the remove mirror tx from the mempool after each block - ( - Ephemeral_State . ; not used - (@ - Current_State - ( - total_reserves - active_shares . - (@ Current_State_Rest - ( - (@ Reward_Info (cumulative_payout . remaining_rewards)) - (@ Round_Time_Info (last_update . epoch_end)) - ) - ) - ) - ) - ) ; Truth - ( - manager_singleton_inner_puzzle_hash - entry_payout_amount - entry_payout_puzzle_hash - entry_initial_cumulative_payout . - entry_shares - ) -) - (include condition_codes.clib) - (include curry.clib) - (include slots.clib) - - (if (= entry_payout_amount (* (- cumulative_payout entry_initial_cumulative_payout) entry_shares)) - (c - (c - Ephemeral_State ; new ephemeral state - (c - (- total_reserves entry_payout_amount) - (c - (- active_shares entry_shares) - Current_State_Rest - ) - ) ; new state - ) - (list - ; manager actually wants us to remove this entry - (list RECEIVE_MESSAGE - 18 ; puzzle hash - puzzle hash - (concat 'r' (sha256 2 - (sha256 1 entry_payout_puzzle_hash) - (sha256 1 entry_shares) - )) ; message = 'r' + (sha265tree (entry_payout_puzzle_hash . entry_shares)) - (curry_hashes_inline SINGLETON_MOD_HASH - MANAGER_SINGLETON_STRUCT_HASH - manager_singleton_inner_puzzle_hash - ) - ) - - ; make sure the reward info is up to date - (list ASSERT_BEFORE_SECONDS_ABSOLUTE (+ last_update MAX_SECONDS_OFFSET)) - - ; spend entry reward slot without recreating it - (spend_slot_inline ENTRY_SLOT_1ST_CURRY_HASH - (sha256 2 - (sha256 1 entry_payout_puzzle_hash) - (sha256 2 - (sha256 1 entry_initial_cumulative_payout) - (sha256 1 entry_shares) - ) - ) ; slot value = (payout_puzzle_hash initial_cumulative_payout . shares) - ) - - ; leading -42 -> condition will be returned by the reserve - (list -42 - CREATE_COIN - entry_payout_puzzle_hash - entry_payout_amount - (list entry_payout_puzzle_hash) - ) - ) ; conditions - ) - ; else - (x) - ) -) \ No newline at end of file diff --git a/puzzles/actions/reward_distributor/manager/remove_entry.clsp.hex b/puzzles/actions/reward_distributor/manager/remove_entry.clsp.hex deleted file mode 100644 index d5e23401..00000000 --- a/puzzles/actions/reward_distributor/manager/remove_entry.clsp.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ffff03ffff09ff8202bfffff12ffff11ff8209dfff820bbf80ff820fbf8080ffff01ff04ffff04ff819fffff04ffff11ff82015fff8202bf80ffff04ffff11ff8202dfff820fbf80ff8203df808080ffff04ffff04ff1cffff04ffff0112ffff04ffff0effff0172ffff0bffff0102ffff0bffff0101ff8205bf80ffff0bffff0101ff820fbf808080ffff04ffff0bff56ffff0bff1affff0bff1aff66ff0580ffff0bff1affff0bff76ffff0bff1affff0bff1aff66ff0b80ffff0bff1affff0bff76ffff0bff1affff0bff1aff66ff82013f80ffff0bff1aff66ff46808080ff46808080ff46808080ff8080808080ffff04ffff04ff08ffff04ffff10ff8213dfff2f80ff808080ffff04ffff02ff1effff04ff02ffff04ff17ffff04ffff0bffff0102ffff0bffff0101ff8205bf80ffff0bffff0102ffff0bffff0101ff820bbf80ffff0bffff0101ff820fbf808080ff8080808080ffff04ffff04ffff0181d6ffff04ff14ffff04ff8205bfffff04ff8202bfffff04ffff04ff8205bfff8080ff808080808080ff808080808080ffff01ff088080ff0180ffff04ffff01ffff55ff3343ffff4202ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff12ffff04ffff0112ffff04ff80ffff04ffff0bff56ffff0bff1affff0bff1aff66ff0580ffff0bff1affff0bff76ffff0bff1affff0bff1aff66ffff0bffff0101ff0b8080ffff0bff1aff66ff46808080ff46808080ff8080808080ff018080 diff --git a/puzzles/actions/reward_distributor/new_epoch.clsp b/puzzles/actions/reward_distributor/new_epoch.clsp deleted file mode 100644 index 1a3b5c54..00000000 --- a/puzzles/actions/reward_distributor/new_epoch.clsp +++ /dev/null @@ -1,88 +0,0 @@ -; new_epoch.clsp by yakuhito -;; Starts a new epoch - -(mod ( - REWARD_SLOT_1ST_CURRY_HASH ; after 1st curry - FEE_PAYOUT_PUZZLE_HASH - FEE_BPS ; * epoch_total_rewards / 10000 will be given to the validator - rest is distributed to mirrors - EPOCH_SECONDS - ( - Ephemeral_State . ; not used - (@ Current_State - ( - total_reserves - active_shares - (cumulative_payout . remaining_rewards) - (last_update . epoch_end) - ) - ) ; truth - ) - ( - slot_epoch_time - slot_next_epoch_initialized - slot_total_rewards - epoch_total_rewards . - fee - ) -) - (include condition_codes.clib) - (include curry.clib) - (include slots.clib) - - (defun-inline slot_oracle (SLOT_1ST_CURRY_HASH slot_value_hash hint) - (list - (spend_slot_inline SLOT_1ST_CURRY_HASH slot_value_hash) - (create_slot_with_hint_inline SLOT_1ST_CURRY_HASH slot_value_hash hint) - ) - ) - - (if (all (= last_update epoch_end) - (= (/ (* epoch_total_rewards FEE_BPS) 10000) fee) - (any - (all (= slot_epoch_time epoch_end) (= epoch_total_rewards slot_total_rewards)) ; slot contains info about next epoch - (all (> epoch_end slot_epoch_time) (not slot_next_epoch_initialized) (= epoch_total_rewards 0)) ; slot is for previous epoch; next epoch is 0 - ) - ) - (c - (list - Ephemeral_State ; new ephemeral state - (- total_reserves fee) - active_shares - (c - cumulative_payout - (+ remaining_rewards (- epoch_total_rewards fee)) - ) - (c epoch_end (+ epoch_end EPOCH_SECONDS)) - ) ; new state - (c - (list - CREATE_PUZZLE_ANNOUNCEMENT - (concat 'e' - (sha256 1 epoch_end) ; (sha256tree epoch_end) - ) - ) - (c - ; condition prepended with -42 -> condition will be returned by the reserve - (list -42 - CREATE_COIN - FEE_PAYOUT_PUZZLE_HASH - fee - (list FEE_PAYOUT_PUZZLE_HASH) - ) - (slot_oracle REWARD_SLOT_1ST_CURRY_HASH - (sha256 2 - (sha256 1 slot_epoch_time) - (sha256 2 - (sha256 1 slot_next_epoch_initialized) - (sha256 1 slot_total_rewards) - ) - ) ; (sha256tree (epoch_time next_epoch_initialized . total_rewards)) - (sha256 1 slot_epoch_time) - ) - ) - ) ; conditions - ) - ; else - (x) - ) -) \ No newline at end of file diff --git a/puzzles/actions/reward_distributor/new_epoch.clsp.hex b/puzzles/actions/reward_distributor/new_epoch.clsp.hex deleted file mode 100644 index e7f22589..00000000 --- a/puzzles/actions/reward_distributor/new_epoch.clsp.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ffff03ffff22ffff09ff8213dfff821bdf80ffff09ffff05ffff14ffff12ff820bbfff1780ffff018227108080ff820fbf80ffff21ffff22ffff09ff82013fff821bdf80ffff09ff820bbfff8205bf8080ffff22ffff15ff821bdfff82013f80ffff20ff8202bf80ffff09ff820bbfff8080808080ffff01ff04ffff04ff819fffff04ffff11ff82015fff820fbf80ffff04ff8202dfffff04ffff04ff8209dfffff10ff820ddfffff11ff820bbfff820fbf808080ffff04ffff04ff821bdfffff10ff821bdfff2f8080ff808080808080ffff04ffff04ff14ffff04ffff0effff0165ffff0bffff0101ff821bdf8080ff808080ffff04ffff04ffff0181d6ffff04ff08ffff04ff0bffff04ff820fbfffff04ffff04ff0bff8080ff808080808080ffff04ffff02ff1effff04ff02ffff04ff05ffff04ffff0bffff0102ffff0bffff0101ff82013f80ffff0bffff0102ffff0bffff0101ff8202bf80ffff0bffff0101ff8205bf808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff05ffff04ffff0bffff0102ffff0bffff0101ff82013f80ffff0bffff0102ffff0bffff0101ff8202bf80ffff0bffff0101ff8205bf808080ffff04ffff0bffff0101ff82013f80ff808080808080ff808080808080ffff01ff088080ff0180ffff04ffff01ffff33ff3e42ffff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff08ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ff04ff1cffff04ffff0112ffff04ff80ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ff8080808080ff018080 diff --git a/puzzles/actions/reward_distributor/nft/stake.clsp b/puzzles/actions/reward_distributor/nft/stake.clsp deleted file mode 100644 index 057815e4..00000000 --- a/puzzles/actions/reward_distributor/nft/stake.clsp +++ /dev/null @@ -1,132 +0,0 @@ -; stake.clsp by yakuhito -;; Stakes an NFT to add an entry to the reward distributor. - -(mod ( - (@ DID_SINGLETON_STRUCT (SINGLETON_MOD_HASH DID_LAUNCHER_ID . SINGLETON_LAUNCHER_HASH)) - NFT_STATE_LAYER_MOD_HASH - NFT_OWNERSHIP_LAYER_MOD_HASH - OFFER_MOD_HASH - NONCE_MOD_HASH - MY_P2_PUZZLE_HASH - ENTRY_SLOT_1ST_CURRY_HASH ; after 1st curry - MAX_SECONDS_OFFSET ; at most this amount of seconds can pass since last update - ; /\ this prevents someone from 'stealing' earned rewards before MAX_SECONDS_OFFSET by - ; adding a mirror with a gazillion shares during long periods of non-sync - ( - Ephemeral_State . ; not used - (@ - Current_State - ( - total_reserves - active_shares - (@ Reward_Info (cumulative_payout . remaining_rewards)) - (@ Round_Time_Info (last_update . epoch_end)) - ) - ) - ) ; Truth - ( - my_id - nft_metadata_hash - nft_metadata_updater_hash_hash - nft_transfer_porgram_hash - nft_launcher_proof . - entry_custody_puzzle_hash - ) -) - (include condition_codes.clib) - (include sha256tree.clib) - (include curry.clib) - (include slots.clib) - - (defun notarized_payment (ph) - (list ph 1 (list ph)) - ) - - (defun nft_lancher_id (did_coin_id (@ nft_launcher_proof ((proof_puzzle_hash . proof_amount) . nft_launcher_proof_rest))) - (if nft_launcher_proof - (coinid - (nft_lancher_id did_coin_id nft_launcher_proof_rest) - proof_puzzle_hash - proof_amount - ) - ; else - did_coin_id - ) - ) - - (defun-inline nft_lancher_id_stager (((did_parent_info did_inner_ph did_amount) . nft_launcher_proof)) - (nft_lancher_id - (coinid - did_parent_info - (curry_hashes SINGLETON_MOD_HASH - (sha256tree DID_SINGLETON_STRUCT) - did_inner_ph - ) - did_amount - ) - nft_launcher_proof - ) - ) - - (defun add_announcement_assert_and_create_security_condition (ann conditions) - (c - (list ASSERT_PUZZLE_ANNOUNCEMENT ann) - (c - (list CREATE_PUZZLE_ANNOUNCEMENT ann) - conditions - ) - ) - ) - - (c - (list - (+ Ephemeral_State 1) - total_reserves - (+ active_shares 1) - Reward_Info - Round_Time_Info - ) ; new state - (add_announcement_assert_and_create_security_condition - (sha256 - (curry_hashes SINGLETON_MOD_HASH - (sha256tree - (c SINGLETON_MOD_HASH (c (nft_lancher_id_stager nft_launcher_proof) SINGLETON_LAUNCHER_HASH)) - ) - (curry_hashes NFT_STATE_LAYER_MOD_HASH - (sha256 1 NFT_STATE_LAYER_MOD_HASH) - nft_metadata_hash - nft_metadata_updater_hash_hash - (curry_hashes NFT_OWNERSHIP_LAYER_MOD_HASH - (sha256 1 NFT_OWNERSHIP_LAYER_MOD_HASH) - (sha256_one) - nft_transfer_porgram_hash - OFFER_MOD_HASH - ) - ) - ) ; NFT puzzle hash - (sha256tree - (list - (sha256tree (c Ephemeral_State my_id)) ; nonce - (notarized_payment (curry_hashes NONCE_MOD_HASH - (sha256 1 entry_custody_puzzle_hash) - MY_P2_PUZZLE_HASH - )) - ) - ) - ) - (list - (list ASSERT_MY_COIN_ID my_id) - - (create_slot_with_hint ENTRY_SLOT_1ST_CURRY_HASH - (sha256tree - (c entry_custody_puzzle_hash (c cumulative_payout 1)) - ) ; slot value = (payout_puzzle_hash initial_cumulative_payout . shares) - entry_custody_puzzle_hash - ) - - ; make sure the reward info is up to date - (list ASSERT_BEFORE_SECONDS_ABSOLUTE (+ last_update MAX_SECONDS_OFFSET)) - ) - ) ; conditions - ) -) \ No newline at end of file diff --git a/puzzles/actions/reward_distributor/nft/stake.clsp.hex b/puzzles/actions/reward_distributor/nft/stake.clsp.hex deleted file mode 100644 index 01ababce..00000000 --- a/puzzles/actions/reward_distributor/nft/stake.clsp.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff04ffff04ffff10ff8209ffffff010180ffff04ff8215ffffff04ffff10ff822dffffff010180ffff04ff825dffffff04ff82bdffff808080808080ffff02ff3cffff04ff02ffff04ffff0bffff02ff3affff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ffff04ff09ffff04ffff02ff36ffff04ff02ffff04ffff30ff83047bffffff02ff3affff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff05ff80808080ffff04ff830a7bffff808080808080ff83167bff80ffff04ff83037bffff8080808080ff1d8080ff80808080ffff04ffff02ff3affff04ff02ffff04ff0bffff04ffff0bffff0101ff0b80ffff04ff822bffffff04ff825bffffff04ffff02ff3affff04ff02ffff04ff17ffff04ffff0bffff0101ff1780ffff04ff8192ffff04ff82bbffffff04ff2fff8080808080808080ff8080808080808080ff808080808080ffff02ff3effff04ff02ffff04ffff04ffff02ff3effff04ff02ffff04ffff04ff8209ffff8213ff80ff80808080ffff04ffff02ff2effff04ff02ffff04ffff02ff3affff04ff02ffff04ff5fffff04ffff0bffff0101ff8301fbff80ffff04ff81bfff808080808080ff80808080ff808080ff8080808080ffff04ffff04ffff04ff28ffff04ff8213ffff808080ffff04ffff02ff2affff04ff02ffff04ff82017fffff04ffff02ff3effff04ff02ffff04ffff04ff8301fbffffff04ff829dffffff01018080ff80808080ffff04ff8301fbffff808080808080ffff04ffff04ff10ffff04ffff10ff83013dffff8202ff80ff808080ff80808080ff808080808080ffff04ffff01ffffff55ff463fffff333eff02ff04ffff04ff38ffff04ff05ff808080ffff04ffff04ff34ffff04ff05ff808080ff0b8080ffffffff02ffff03ff05ffff01ff0bff81f2ffff02ff26ffff04ff02ffff04ff09ffff04ffff02ff22ffff04ff02ffff04ff0dff80808080ff808080808080ffff0181d280ff0180ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff24ffff04ffff02ff3affff04ff02ffff04ff05ffff04ffff0bffff0101ff0b80ff8080808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ff0bff81b2ffff02ff26ffff04ff02ffff04ff05ffff04ffff02ff22ffff04ff02ffff04ff07ff80808080ff808080808080ffffff0bff2cffff0bff2cff81d2ff0580ffff0bff2cff0bff81928080ff02ffff03ff0bffff01ff30ffff02ff36ffff04ff02ffff04ff05ffff04ff1bff8080808080ff23ff3380ffff010580ff0180ffff04ff05ffff04ffff0101ffff04ffff04ff05ff8080ff80808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080 diff --git a/puzzles/actions/reward_distributor/nft/unstake.clsp b/puzzles/actions/reward_distributor/nft/unstake.clsp deleted file mode 100644 index cf90cc9c..00000000 --- a/puzzles/actions/reward_distributor/nft/unstake.clsp +++ /dev/null @@ -1,123 +0,0 @@ -; unstake.clsp by yakuhito -;; Removes an entry from the reward distributor, returning the NFT to the user. - -(mod ( - SINGLETON_MOD_HASH - SINGLETON_LAUNCHER_HASH - NFT_STATE_LAYER_MOD_HASH - NFT_OWNERSHIP_LAYER_MOD_HASH - NONCE_MOD_HASH - MY_P2_PUZZLE_HASH - ENTRY_SLOT_1ST_CURRY_HASH ; after 1st curry - MAX_SECONDS_OFFSET ; at most this amount of seconds can pass since last update - ; /\ this prevents the reward distributor from 'stealing' earned rewards while not - ; dropping the remove mirror tx from the mempool after each block - ( - Ephemeral_State . ; not used - (@ - Current_State - ( - total_reserves - active_shares . - (@ Current_State_Rest - ( - (@ Reward_Info (cumulative_payout . remaining_rewards)) - (@ Round_Time_Info (last_update . epoch_end)) - ) - ) - ) - ) - ) ; Truth - ( - nft_launcher_id - nft_parent_id - nft_metadata_hash - nft_metadata_updater_hash_hash - nft_transfer_porgram_hash - entry_initial_cumulative_payout . - entry_custody_puzzle_hash - ) -) - (include condition_codes.clib) - (include sha256tree.clib) - (include curry.clib) - (include slots.clib) - - (c - (c - Ephemeral_State ; new ephemeral state - (c - (- total_reserves (- cumulative_payout entry_initial_cumulative_payout)) - (c - (- active_shares 1) - Current_State_Rest - ) - ) ; new state - ) - (list - ; remove entry - (list SEND_MESSAGE - 23 ; sender puzzle hash, receiver coin id - (sha256tree (c ; this is the leading 'q . ' in the delegated puzzle - 1 - (list - (list - CREATE_COIN - entry_custody_puzzle_hash - 1 - (list entry_custody_puzzle_hash) - ) - ) - )) ; message = delegated puzzle hash - (coinid - nft_parent_id - (curry_hashes SINGLETON_MOD_HASH - (sha256tree - (c SINGLETON_MOD_HASH (c nft_launcher_id SINGLETON_LAUNCHER_HASH)) - ) - (curry_hashes NFT_STATE_LAYER_MOD_HASH - (sha256 1 NFT_STATE_LAYER_MOD_HASH) - nft_metadata_hash - nft_metadata_updater_hash_hash - (curry_hashes NFT_OWNERSHIP_LAYER_MOD_HASH - (sha256 1 NFT_OWNERSHIP_LAYER_MOD_HASH) - (sha256_one) - nft_transfer_porgram_hash - (curry_hashes NONCE_MOD_HASH - (sha256 1 entry_custody_puzzle_hash) - MY_P2_PUZZLE_HASH - ) - ) - ) - ) ; NFT puzzle hash - 1 - ) - ) - - ; owner actually wants us to remove this entry - (list RECEIVE_MESSAGE - 18 ; puzzle hash - puzzle hash - nft_launcher_id ; message - entry_custody_puzzle_hash ; sender - ) - - ; make sure the reward info is up to date - (list ASSERT_BEFORE_SECONDS_ABSOLUTE (+ last_update MAX_SECONDS_OFFSET)) - - ; spend entry reward slot without recreating it - (spend_slot ENTRY_SLOT_1ST_CURRY_HASH - (sha256tree - (c entry_custody_puzzle_hash (c entry_initial_cumulative_payout 1)) - ) ; slot value = (payout_puzzle_hash initial_cumulative_payout . shares) - ) - - ; leading -42 -> condition will be returned by the reserve - (list -42 - CREATE_COIN - entry_custody_puzzle_hash - (- cumulative_payout entry_initial_cumulative_payout) - (list entry_custody_puzzle_hash) - ) - ) ; conditions - ) -) \ No newline at end of file diff --git a/puzzles/actions/reward_distributor/nft/unstake.clsp.hex b/puzzles/actions/reward_distributor/nft/unstake.clsp.hex deleted file mode 100644 index bb814a31..00000000 --- a/puzzles/actions/reward_distributor/nft/unstake.clsp.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff04ffff04ff8209ffffff04ffff11ff8215ffffff11ff829dffff8302fbff8080ffff04ffff11ff822dffffff010180ff823dff808080ffff04ffff04ff2cffff04ffff0117ffff04ffff02ff2effff04ff02ffff04ffff04ffff0101ffff04ffff04ff18ffff04ff8303fbffffff04ffff0101ffff04ffff04ff8303fbffff8080ff8080808080ff808080ff80808080ffff04ffff30ff822bffffff02ff3affff04ff02ffff04ff05ffff04ffff02ff2effff04ff02ffff04ffff04ff05ffff04ff8213ffff0b8080ff80808080ffff04ffff02ff3affff04ff02ffff04ff17ffff04ffff0bffff0101ff1780ffff04ff825bffffff04ff82bbffffff04ffff02ff3affff04ff02ffff04ff2fffff04ffff0bffff0101ff2f80ffff04ff818affff04ff83017bffffff04ffff02ff3affff04ff02ffff04ff5fffff04ffff0bffff0101ff8303fbff80ffff04ff81bfff808080808080ff8080808080808080ff8080808080808080ff808080808080ffff010180ff8080808080ffff04ffff04ff14ffff04ffff0112ffff04ff8213ffffff04ff8303fbffff8080808080ffff04ffff04ff10ffff04ffff10ff83013dffff8202ff80ff808080ffff04ffff02ff3effff04ff02ffff04ff82017fffff04ffff02ff2effff04ff02ffff04ffff04ff8303fbffffff04ff8302fbffffff01018080ff80808080ff8080808080ffff04ffff04ffff0181d6ffff04ff18ffff04ff8303fbffffff04ffff11ff829dffff8302fbff80ffff04ffff04ff8303fbffff8080ff808080808080ff80808080808080ffff04ffff01ffffff5533ff43ff4202ffffff02ffff03ff05ffff01ff0bff81eaffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff12ffff04ff02ffff04ff0dff80808080ff808080808080ffff0181ca80ff0180ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff0bff81aaffff02ff16ffff04ff02ffff04ff05ffff04ffff02ff12ffff04ff02ffff04ff07ff80808080ff808080808080ffff0bff3cffff0bff3cff81caff0580ffff0bff3cff0bff818a8080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff2cffff04ffff0112ffff04ff80ffff04ffff02ff3affff04ff02ffff04ff05ffff04ffff0bffff0101ff0b80ff8080808080ff8080808080ff018080 diff --git a/puzzles/actions/reward_distributor/sync.clsp b/puzzles/actions/reward_distributor/sync.clsp deleted file mode 100644 index 13d7ecf9..00000000 --- a/puzzles/actions/reward_distributor/sync.clsp +++ /dev/null @@ -1,63 +0,0 @@ -; sync.clsp by yakuhito -;; Syncs reward distribution for the current epoch - -(mod ( - ( - Ephemeral_State . ; not used - (@ Current_State - ( - total_reserves - active_shares - (cumulative_payout . remaining_rewards) - (@ Round_Time_Info (last_update . epoch_end)) - ) - ) ; Truth - ) - ( - update_time - ) -) - (include condition_codes.clib) - - (defun calculate_new_distribution (active_shares cumulative_payout remaining_rewards cumulative_payout_delta) - (c - (+ cumulative_payout cumulative_payout_delta) ; new cumulative_payout - (- remaining_rewards (* cumulative_payout_delta active_shares)) ; new remaining rewards - ) - ) - - (if (all (not (> update_time epoch_end)) (> update_time last_update)) - (c - (list - Ephemeral_State ; new ephemeral state - total_reserves - active_shares - (calculate_new_distribution - active_shares - cumulative_payout - remaining_rewards - (if (> active_shares 0) - (/ (* remaining_rewards (- update_time last_update)) (* active_shares (- epoch_end last_update))) - ; else - 0 - ) ; cumulative_payout_delta - ) - (c update_time epoch_end) - ) ; new state - (list - (list ASSERT_SECONDS_ABSOLUTE update_time) - (list - CREATE_PUZZLE_ANNOUNCEMENT - (concat 's' - (sha256 2 - (sha256 1 update_time) - (sha256 1 epoch_end) - ) ; (sha256tree (update_time . epoch_end)) - ) - ) - ) ; conditions - ) - ; else - (x) - ) -) \ No newline at end of file diff --git a/puzzles/actions/reward_distributor/sync.clsp.hex b/puzzles/actions/reward_distributor/sync.clsp.hex deleted file mode 100644 index aa552b31..00000000 --- a/puzzles/actions/reward_distributor/sync.clsp.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff02ffff03ffff22ffff20ffff15ff13ff8201bd8080ffff15ff13ff82013d8080ffff01ff04ffff04ff09ffff04ff15ffff04ff2dffff04ffff02ff0effff04ff02ffff04ff2dffff04ff819dffff04ff81ddffff04ffff02ffff03ffff15ff2dff8080ffff01ff05ffff14ffff12ff81ddffff11ff13ff82013d8080ffff12ff2dffff11ff8201bdff82013d80808080ff8080ff0180ff80808080808080ffff04ffff04ff13ff8201bd80ff808080808080ffff04ffff04ff04ffff04ff13ff808080ffff04ffff04ff0affff04ffff0effff0173ffff0bffff0102ffff0bffff0101ff1380ffff0bffff0101ff8201bd808080ff808080ff80808080ffff01ff088080ff0180ffff04ffff01ff51ff3eff04ffff10ff0bff2f80ffff11ff17ffff12ff2fff05808080ff018080 diff --git a/puzzles/actions/reward_distributor/withdraw_incentives.clsp b/puzzles/actions/reward_distributor/withdraw_incentives.clsp deleted file mode 100644 index 2f311dad..00000000 --- a/puzzles/actions/reward_distributor/withdraw_incentives.clsp +++ /dev/null @@ -1,80 +0,0 @@ -; withdraw_incentives.clsp by yakuhito -;; Withdraw incentives from a future epoch - -(mod ( - REWARD_SLOT_1ST_CURRY_HASH ; after 1st curry - COMMITMENT_SLOT_1ST_CURRY_HASH ; after 1st curry - WITHDRAWAL_SHARE_BPS ; / 10000 * committed_value will actually be sent to the recipient - ( - Ephemeral_State . ; not used - (@ Current_State (total_reserves . Current_State_Rest)) - ) ; Truth - ( - reward_slot_epoch_time - reward_slot_next_epoch_initialized - reward_slot_total_rewards - clawback_ph - committed_value . - withdrawal_share - ) -) - (include condition_codes.clib) - (include curry.clib) - (include slots.clib) - - (defun get_slot_data_hash (first second third) - (sha256 2 - (sha256 1 first) - (sha256 2 - (sha256 1 second) - (sha256 1 third) - ) - ) ; e.g., (sha256tree (epoch_time next_epoch_time . total_rewards)) - ) - - (c - (c - Ephemeral_State ; new ephemeral state - (c - (- total_reserves - (if (= withdrawal_share (/ (* WITHDRAWAL_SHARE_BPS committed_value) 10000)) withdrawal_share (x)) - ) - Current_State_Rest - ) ; new state - ) - (list - ; this also ensures that the wihdrawal doesn't affect the current round - (list ASSERT_BEFORE_SECONDS_ABSOLUTE reward_slot_epoch_time) - - ; update epoch reward (lower total rewards) - (spend_slot_inline REWARD_SLOT_1ST_CURRY_HASH - (get_slot_data_hash reward_slot_epoch_time reward_slot_next_epoch_initialized reward_slot_total_rewards) - ) - - (create_slot_with_hint_inline REWARD_SLOT_1ST_CURRY_HASH - (get_slot_data_hash - reward_slot_epoch_time - reward_slot_next_epoch_initialized - (- reward_slot_total_rewards withdrawal_share) - ) - (sha256 1 reward_slot_epoch_time) - ) - - ; spend commitment slot, which functions as a ticket - (spend_slot_inline COMMITMENT_SLOT_1ST_CURRY_HASH - (get_slot_data_hash reward_slot_epoch_time clawback_ph committed_value) - ) - - ; make sure the clawback owner wants to go ahead - (list RECEIVE_MESSAGE - 18 ; puzzle hash - puzzle hash - () ; message - clawback_ph - ) - - ; conditions with '-42' will be outputed by the reserve coin - (list -42 CREATE_COIN clawback_ph withdrawal_share (list clawback_ph)) - ) ; conditions - ) - -) \ No newline at end of file diff --git a/puzzles/actions/reward_distributor/withdraw_incentives.clsp.hex b/puzzles/actions/reward_distributor/withdraw_incentives.clsp.hex deleted file mode 100644 index 5f3986cc..00000000 --- a/puzzles/actions/reward_distributor/withdraw_incentives.clsp.hex +++ /dev/null @@ -1 +0,0 @@ -ff02ffff01ff04ffff04ff4fffff04ffff11ff81afffff02ffff03ffff09ff820fdfffff05ffff14ffff12ff17ff820bdf80ffff01822710808080ffff01820fdfffff01ff088080ff018080ff81ef8080ffff04ffff04ff10ffff04ff819fff808080ffff04ffff02ff3effff04ff02ffff04ff05ffff04ffff02ff2effff04ff02ffff04ff819fffff04ff82015fffff04ff8202dfff808080808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff05ffff04ffff02ff2effff04ff02ffff04ff819fffff04ff82015fffff04ffff11ff8202dfff820fdf80ff808080808080ffff04ffff0bffff0101ff819f80ff808080808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ff819fffff04ff8205dfffff04ff820bdfff808080808080ff8080808080ffff04ffff04ff14ffff04ffff0112ffff04ff80ffff04ff8205dfff8080808080ffff04ffff04ffff0181d6ffff04ff18ffff04ff8205dfffff04ff820fdfffff04ffff04ff8205dfff8080ff808080808080ff8080808080808080ffff04ffff01ffffff5533ff4342ffff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff18ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ffff0bffff0102ffff0bffff0101ff0580ffff0bffff0102ffff0bffff0101ff0b80ffff0bffff0101ff17808080ff04ff1cffff04ffff0112ffff04ff80ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ff8080808080ff018080 diff --git a/puzzles/default_puzzles/revocable_cat_maker.clsp b/puzzles/default_puzzles/revocable_cat_maker.clsp new file mode 100644 index 00000000..53267863 --- /dev/null +++ b/puzzles/default_puzzles/revocable_cat_maker.clsp @@ -0,0 +1,29 @@ +; revocable_cat_maker.clsp by yakuhito +;; Given an inner puzzle and a user-supplied solution, CAT makers return the full puzzle of a CAT +;; with the given inner puzzle. This allows the registry to support intermediary layers in +;; future CATs, such as the recently-proposed revocation layer. + +;; The revocable CAT maker assumes the revocation layer is the only layer separating the CAT outer puzzle +;; from the inner puzzle. + +;; Note: Truths (Inner_Puzzle_Hash) are trusted and should be verified by the outer puzzle. + +(mod ( + (CAT_MOD_HASH REVOCATION_LAYER_MOD_HASH . HIDDEN_PUZZLE_HASH_HASH) + TAIL_HASH_HASH ; (sha256 1 TAIL_HASH) + Inner_Puzzle_Hash + ; Note: other CAT makers may have more arguments here + ; Puzzles using the maker should prepend Inner_Puzzle_Hash to a user-supplied input +) + (include curry.clib) + + (curry_hashes_inline CAT_MOD_HASH + (sha256 1 CAT_MOD_HASH) + TAIL_HASH_HASH + (curry_hashes_inline REVOCATION_LAYER_MOD_HASH + (sha256 1 REVOCATION_LAYER_MOD_HASH) + HIDDEN_PUZZLE_HASH_HASH + (sha256 1 Inner_Puzzle_Hash) + ) ; CAT layer inner puzzle + ) +) \ No newline at end of file diff --git a/puzzles/default_puzzles/revocable_cat_maker.clsp.hex b/puzzles/default_puzzles/revocable_cat_maker.clsp.hex new file mode 100644 index 00000000..55742874 --- /dev/null +++ b/puzzles/default_puzzles/revocable_cat_maker.clsp.hex @@ -0,0 +1 @@ +ff02ffff01ff0bff16ffff0bff04ffff0bff04ff1aff0980ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bffff0101ff098080ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1aff0b80ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bff16ffff0bff04ffff0bff04ff1aff1580ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bffff0101ff158080ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1aff1d80ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bffff0101ff178080ffff0bff04ff1aff12808080ff12808080ff12808080ff1280808080ffff0bff04ff1aff12808080ff12808080ff12808080ff12808080ffff04ffff01ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff018080 diff --git a/puzzles/singleton/action.clsp b/puzzles/singleton/action.clsp index 177e6332..0a4a286b 100644 --- a/puzzles/singleton/action.clsp +++ b/puzzles/singleton/action.clsp @@ -10,7 +10,7 @@ ;; (it is persistent) ;; ephemeral_state is not persistent - it's () for the first action of any new spend ;; but passed from the previous action in the same spend -;; new_conditions will be directly aded to this puzzle's output conditions +;; new_conditions will be directly added to this puzzle's output conditions ;; but the finalizer puzzle is able to filter them after all actions are run ;; Warning: This puzzle's finalizer likely assumes the singleton's amount is 1 (like the default one does). @@ -41,7 +41,7 @@ (@ pending_selectors_and_proofs ((selector . proof) . remaining_pending_selectors_and_proofs)) ) (if pending_selectors_and_proofs - (if + (if (if proof (= MERKLE_ROOT (simplify_merkle_proof (sha256tree (a selector puzzles)) proof)) ; else diff --git a/puzzles/singleton/finalizer.clsp b/puzzles/singleton/finalizer.clsp index 1526636d..7036c7e4 100644 --- a/puzzles/singleton/finalizer.clsp +++ b/puzzles/singleton/finalizer.clsp @@ -8,6 +8,7 @@ (mod ( ACTION_LAYER_MOD_HASH HINT + ; 2nd curry FINALIZER_SELF_HASH Merkle_Root Initial_State ; not used for this puzzle @@ -45,4 +46,4 @@ ) (flatten_list Conditions) ) -) \ No newline at end of file +) diff --git a/puzzles/singleton/reserve_finalizer.clsp b/puzzles/singleton/reserve_finalizer.clsp index 447a564d..83e2dc3f 100644 --- a/puzzles/singleton/reserve_finalizer.clsp +++ b/puzzles/singleton/reserve_finalizer.clsp @@ -12,11 +12,12 @@ ACTION_LAYER_MOD_HASH RESERVE_FULL_PUZZLE_HASH RESERVE_INNER_PUZZLE_HASH - RESERVE_AMOUNT_FROM_STATE_PROGRAM + RESERVE_AMOUNT_FROM_STATE_PROGRAM ; default is 02 - i.e., (f State) HINT + ; 2nd curry FINALIZER_SELF_HASH Merkle_Root - Initial_State ; not used for this puzzle + Initial_State ; used to extract current reserve amount ((Last_Ephemeral_State . New_State) . Conditions) ; last action output (reserve_parent_id) ; my_solution ) @@ -91,4 +92,4 @@ ) (add_message_to_reserve (parse_conditions Conditions () ())) ) -) \ No newline at end of file +) diff --git a/puzzles/singleton/slot.clsp b/puzzles/singleton/slot.clsp index 3ef51581..01b7561b 100644 --- a/puzzles/singleton/slot.clsp +++ b/puzzles/singleton/slot.clsp @@ -1,23 +1,28 @@ ; slot.clsp by yakuhito ;; A singleton slot coin is created to store values that may be read at a later spend ;; To read the values, the singleton will spend the slot coin - so the values are only readable once -;; Might be helpful to think of this as a one-time ticket +;; Might be helpful to think of this as a one-time ticket + +;; Double currying allows the controller singleton to only care about the 1st curry hash, which means it +;; only needs that and VALUE_HASH to build the full slot puzzle hash. This leads to more cost saved. +;; NONCE is used to differentiate between slot types - it avoids situations where slots representing +;; two separate things but that hold the same value format (e.g., list of 3 numbers) can be confused. ;; Warning: Slots do not assure uniqueness - a double-linked sorted list structure on top is required for that ;; An attacker might intentionally omit a given slot to trick the dApp that it doesn't exist ;; For example, a naive handle reigstration app might be tricked into registering the same handle twice -;; Warning 2: This puzzle assumes the controller singleton has an amount of 1. - (mod ( ; 1st curry - SINGLETON_STRUCT ; owner/controller singleton + (@ CONTROLLER_SINGLETON_INFO ( + SINGLETON_MOD_HASH . + SINGLETON_STRUCT_HASH ; treehash of owner/controller singleton struct + )) NONCE ; different nonces will hold different data types ; 2nd curry VALUE_HASH ; info about this coin's parent (previous singleton coin) - parent_parent_info - parent_inner_puzzle_hash + (parent_parent_info parent_inner_puzzle_hash parent_amount) . ; lineage proof ; info about this coin's spender (current singleton coin - the one consuming the value) spender_inner_puzzle_hash ) @@ -26,17 +31,26 @@ (include sha256tree.clib) (include curry.clib) - (defun singleton_full_puzzle_hash (SINGLETON_STRUCT inner_puzzle_hash) - (curry_hashes_inline (f SINGLETON_STRUCT) - (sha256tree SINGLETON_STRUCT) + (defun singleton_full_puzzle_hash ((SINGLETON_MOD_HASH . SINGLETON_STRUCT_HASH) inner_puzzle_hash) + (curry_hashes_inline SINGLETON_MOD_HASH + SINGLETON_STRUCT_HASH inner_puzzle_hash ) ) (list (list ASSERT_MY_PARENT_ID - (coinid parent_parent_info (singleton_full_puzzle_hash SINGLETON_STRUCT parent_inner_puzzle_hash) 1) + (coinid + parent_parent_info + (singleton_full_puzzle_hash CONTROLLER_SINGLETON_INFO parent_inner_puzzle_hash) + parent_amount + ) + ) + (list + RECEIVE_MESSAGE + 18 ; puzzle-puzzle + () + (singleton_full_puzzle_hash CONTROLLER_SINGLETON_INFO spender_inner_puzzle_hash) ) - (list RECEIVE_MESSAGE 18 () (singleton_full_puzzle_hash SINGLETON_STRUCT spender_inner_puzzle_hash)) ; puzzle-puzzle ) ) diff --git a/puzzles/singleton/slot.clsp.hex b/puzzles/singleton/slot.clsp.hex index 11062c1e..adf16500 100644 --- a/puzzles/singleton/slot.clsp.hex +++ b/puzzles/singleton/slot.clsp.hex @@ -1 +1 @@ -ff02ffff01ff04ffff04ff08ffff04ffff30ff2fffff02ff1effff04ff02ffff04ff05ffff04ff5fff8080808080ffff010180ff808080ffff04ffff04ff14ffff04ffff0112ffff04ff80ffff04ffff02ff1effff04ff02ffff04ff05ffff04ff81bfff8080808080ff8080808080ff808080ffff04ffff01ffff47ff4302ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff16ffff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff0bff2affff0bff1cffff0bff1cff32ff0980ffff0bff1cffff0bff3affff0bff1cffff0bff1cff32ffff02ff16ffff04ff02ffff04ff05ff8080808080ffff0bff1cffff0bff3affff0bff1cffff0bff1cff32ff0b80ffff0bff1cff32ff22808080ff22808080ff22808080ff018080 +ff02ffff01ff04ffff04ff08ffff04ffff30ff4fffff02ff1effff04ff02ffff04ff05ffff04ff81afff8080808080ff82016f80ff808080ffff04ffff04ff0cffff04ffff0112ffff04ff80ffff04ffff02ff1effff04ff02ffff04ff05ffff04ff3fff8080808080ff8080808080ff808080ffff04ffff01ffff4743ff02ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff0bff56ffff0bff0affff0bff0aff66ff0980ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ff0d80ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ff0b80ffff0bff0aff66ff46808080ff46808080ff46808080ff018080 diff --git a/src/benchmarker.rs b/src/benchmarker.rs deleted file mode 100644 index 40a913c3..00000000 --- a/src/benchmarker.rs +++ /dev/null @@ -1,86 +0,0 @@ -#[allow(dead_code)] -#[cfg(test)] -pub mod tests { - use std::{collections::HashMap, fs::File}; - - use chia::{ - bls::{SecretKey, Signature}, - consensus::spendbundle_conditions::get_conditions_from_spendbundle, - protocol::SpendBundle, - }; - use chia_wallet_sdk::{driver::SpendContext, test::Simulator, types::TESTNET11_CONSTANTS}; - use prettytable::{row, Table}; - - pub struct Benchmark { - pub title: String, - pub data_keys: Vec, - pub data: HashMap>, - } - - impl Benchmark { - pub fn new(title: String) -> Self { - Self { - title, - data_keys: Vec::new(), - data: HashMap::new(), - } - } - - pub fn add_spends( - &mut self, - ctx: &mut SpendContext, - sim: &mut Simulator, - key: &str, - keys: &[SecretKey], - ) -> anyhow::Result<()> { - let sb = SpendBundle::new(ctx.take(), Signature::default()); - let sb_conds = get_conditions_from_spendbundle( - ctx, - &sb, - u64::MAX, - sim.height(), - &TESTNET11_CONSTANTS, - )?; - - let key = key.to_string(); - if !self.data_keys.contains(&key) { - self.data_keys.push(key.clone()); - } - self.data.entry(key).or_default().push(sb_conds.cost); - - sim.spend_coins(sb.coin_spends, keys)?; - Ok(()) - } - - pub fn print_summary(&self, filename: Option<&str>) { - let mut table = Table::new(); - table.add_row(row![format!("Cost statistics for {}", self.title)]); - table.add_row(row!["label", "avg", "n", "min", "max", "median"]); - for key in &self.data_keys { - let data = &self.data[key]; - - let total = data.iter().sum::(); - let avg = format!("{:.1}", total as f64 / data.len() as f64); - - let mut sorted = data.clone(); - sorted.sort(); - let data_min = sorted[0]; - let data_max = sorted[sorted.len() - 1]; - - let data_median = if sorted.len() % 2 == 0 { - (sorted[sorted.len() / 2] + sorted[sorted.len() / 2 - 1]) as f64 / 2.0 - } else { - sorted[sorted.len() / 2] as f64 - }; - - table.add_row(row![key, avg, data.len(), data_min, data_max, data_median]); - } - - table.printstd(); - if let Some(filename) = filename { - let mut file = File::create(filename).unwrap(); - table.print(&mut file).unwrap(); - } - } - } -} diff --git a/src/cat_nft_metadata.rs b/src/cat_nft_metadata.rs deleted file mode 100644 index 177bf0cf..00000000 --- a/src/cat_nft_metadata.rs +++ /dev/null @@ -1,121 +0,0 @@ -use std::fmt::Debug; - -use chia::protocol::Bytes32; -use clvm_traits::{ClvmDecoder, ClvmEncoder, FromClvm, FromClvmError, Raw, ToClvm, ToClvmError}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CatNftMetadata { - pub ticker: String, - pub name: String, - pub description: String, - pub precision: u8, - pub image_uris: Vec, - pub image_hash: Bytes32, - pub metadata_uris: Vec, - pub metadata_hash: Option, - pub license_uris: Vec, - pub license_hash: Option, -} - -impl Default for CatNftMetadata { - fn default() -> Self { - Self { - ticker: "???".to_string(), - name: "Unknown CAT".to_string(), - description: "(no description provided)".to_string(), - precision: 3, - image_uris: Vec::default(), - image_hash: Bytes32::default(), - metadata_uris: Vec::default(), - metadata_hash: None, - license_uris: Vec::default(), - license_hash: None, - } - } -} - -impl CatNftMetadata { - pub fn pretty_print(&self, prefix: &str) { - println!("{}Ticker: {}", prefix, self.ticker); - println!("{}Name: {}", prefix, self.name); - println!("{}Description: {}", prefix, self.description); - println!("{}Precision: {}", prefix, self.precision); - println!("{}Image URIs: {}", prefix, self.image_uris.join(", ")); - println!("{}Image Hash: {}", prefix, self.image_hash); - - if !self.metadata_uris.is_empty() { - println!("{}Metadata URIs: {}", prefix, self.metadata_uris.join(", ")); - if let Some(metadata_hash) = self.metadata_hash { - println!("{}Metadata Hash: {}", prefix, metadata_hash); - } else { - println!("{}Metadata Hash: None", prefix); - } - } - - if !self.license_uris.is_empty() { - println!("{}License URIs: {}", prefix, self.license_uris.join(", ")); - if let Some(license_hash) = self.license_hash { - println!("{}License Hash: {}", prefix, license_hash); - } else { - println!("{}License Hash: None", prefix); - } - } - } -} - -impl> FromClvm for CatNftMetadata { - fn from_clvm(decoder: &D, node: N) -> Result { - let items: Vec<(String, Raw)> = FromClvm::from_clvm(decoder, node)?; - let mut metadata = Self::default(); - - for (key, Raw(ptr)) in items { - match key.as_str() { - "t" => metadata.ticker = FromClvm::from_clvm(decoder, ptr)?, - "n" => metadata.name = FromClvm::from_clvm(decoder, ptr)?, - "d" => metadata.description = FromClvm::from_clvm(decoder, ptr)?, - "p" => metadata.precision = FromClvm::from_clvm(decoder, ptr)?, - "u" => metadata.image_uris = FromClvm::from_clvm(decoder, ptr)?, - "h" => metadata.image_hash = FromClvm::from_clvm(decoder, ptr)?, - "mu" => metadata.metadata_uris = FromClvm::from_clvm(decoder, ptr)?, - "mh" => metadata.metadata_hash = FromClvm::from_clvm(decoder, ptr)?, - "lu" => metadata.license_uris = FromClvm::from_clvm(decoder, ptr)?, - "lh" => metadata.license_hash = FromClvm::from_clvm(decoder, ptr)?, - _ => (), - } - } - - Ok(metadata) - } -} - -impl> ToClvm for CatNftMetadata { - fn to_clvm(&self, encoder: &mut E) -> Result { - let mut items: Vec<(&str, Raw)> = vec![ - ("t", Raw(self.ticker.to_clvm(encoder)?)), - ("n", Raw(self.name.to_clvm(encoder)?)), - ]; - - if !self.description.is_empty() { - items.push(("d", Raw(self.description.to_clvm(encoder)?))); - } - - if self.precision != 3 { - items.push(("p", Raw(self.precision.to_clvm(encoder)?))); - } - - items.push(("u", Raw(self.image_uris.to_clvm(encoder)?))); - items.push(("h", Raw(self.image_hash.to_clvm(encoder)?))); - - if !self.metadata_uris.is_empty() { - items.push(("mu", Raw(self.metadata_uris.to_clvm(encoder)?))); - items.push(("mh", Raw(self.metadata_hash.to_clvm(encoder)?))); - } - - if !self.license_uris.is_empty() { - items.push(("lu", Raw(self.license_uris.to_clvm(encoder)?))); - items.push(("lh", Raw(self.license_hash.to_clvm(encoder)?))); - } - - items.to_clvm(encoder) - } -} diff --git a/src/cli/catalog/broadcast_catalog_state_update.rs b/src/cli/catalog/broadcast_catalog_state_update.rs index 497298b8..c2f087b2 100644 --- a/src/cli/catalog/broadcast_catalog_state_update.rs +++ b/src/cli/catalog/broadcast_catalog_state_update.rs @@ -1,12 +1,20 @@ use chia::clvm_utils::ToTreeHash; use chia::protocol::Bytes32; +use chia_wallet_sdk::{ + driver::{ + CatalogRegistryConstants, CatalogRegistryState, DelegatedStateAction, MedievalVault, + SingletonInfo, + }, + types::{ + puzzles::{DefaultCatMakerArgs, StateSchedulerLayerSolution}, + Mod, + }, +}; use clvmr::NodePtr; use crate::{ get_constants, hex_string_to_bytes32, multisig_broadcast_thing_finish, - multisig_broadcast_thing_start, parse_amount, quick_sync_catalog, CatalogRegistryConstants, - CatalogRegistryState, CliError, DefaultCatMakerArgs, DelegatedStateAction, MedievalVault, - StateSchedulerLayerSolution, + multisig_broadcast_thing_start, parse_amount, quick_sync_catalog, CliError, }; pub async fn catalog_broadcast_state_update( @@ -40,7 +48,9 @@ pub async fn catalog_broadcast_state_update( println!("You'll update the CATalog state to:"); let new_cat_maker_puzzle_hash: Bytes32 = - DefaultCatMakerArgs::curry_tree_hash(new_payment_asset_id.tree_hash().into()).into(); + DefaultCatMakerArgs::new(new_payment_asset_id.tree_hash().into()) + .curry_tree_hash() + .into(); let new_state = CatalogRegistryState { cat_maker_puzzle_hash: new_cat_maker_puzzle_hash, registration_price: new_payment_asset_amount, diff --git a/src/cli/catalog/catalog_api_client.rs b/src/cli/catalog/catalog_api_client.rs index e268f3fc..7fbc86bb 100644 --- a/src/cli/catalog/catalog_api_client.rs +++ b/src/cli/catalog/catalog_api_client.rs @@ -1,8 +1,11 @@ use chia::protocol::Bytes32; +use chia_puzzle_types::LineageProof; use reqwest::Client; use std::time::Duration; -use crate::{hex_string_to_bytes32, CatalogSlotValue, CliError, Slot, SlotInfo, SlotProof}; +use crate::{hex_string_to_bytes32, CliError}; +use chia_wallet_sdk::driver::Slot; +use chia_wallet_sdk::types::puzzles::{CatalogSlotValue, SlotInfo}; use super::CatalogNeighborResponse; @@ -86,18 +89,20 @@ impl CatalogApiClient { hex_string_to_bytes32(&neighbors_resp.left_parent_parent_info)?; let left_parent_inner_puzzle_hash = hex_string_to_bytes32(&neighbors_resp.left_parent_inner_puzzle_hash)?; - let left_proof = SlotProof { - parent_parent_info: left_parent_parent_info, + let left_proof = LineageProof { + parent_parent_coin_info: left_parent_parent_info, parent_inner_puzzle_hash: left_parent_inner_puzzle_hash, + parent_amount: neighbors_resp.left_parent_amount, }; let right_parent_parent_info = hex_string_to_bytes32(&neighbors_resp.right_parent_parent_info)?; let right_parent_inner_puzzle_hash = hex_string_to_bytes32(&neighbors_resp.right_parent_inner_puzzle_hash)?; - let right_proof = SlotProof { - parent_parent_info: right_parent_parent_info, + let right_proof = LineageProof { + parent_parent_coin_info: right_parent_parent_info, parent_inner_puzzle_hash: right_parent_inner_puzzle_hash, + parent_amount: neighbors_resp.right_parent_amount, }; let left_info = SlotInfo::::from_value(launcher_id, 0, left_value); diff --git a/src/cli/catalog/continue_launch.rs b/src/cli/catalog/continue_launch.rs index 3e6d6fa2..e4a8bec5 100644 --- a/src/cli/catalog/continue_launch.rs +++ b/src/cli/catalog/continue_launch.rs @@ -8,8 +8,9 @@ use chia::{ use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, driver::{ - decode_offer, CatLayer, DriverError, Layer, Offer, Puzzle, SingleCatSpend, Spend, - SpendContext, + create_security_coin, decode_offer, spend_security_coin, spend_settlement_cats, CatLayer, + CatalogRegisterAction, CatalogRegistryConstants, DriverError, Layer, Offer, PrecommitCoin, + PrecommitLayer, Puzzle, SingleCatSpend, Spend, SpendContext, }, types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, }; @@ -17,12 +18,12 @@ use clvm_traits::clvm_quote; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ - 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, + assets_xch_and_cat, assets_xch_only, hex_string_to_bytes32, load_catalog_premine_csv, + no_assets, parse_amount, sync_catalog, wait_for_coin, yes_no_prompt, CatalogPremineRecord, + CliError, Db, SageClient, }; +use chia_wallet_sdk::driver::CatalogPrecommitValue; +use chia_wallet_sdk::types::puzzles::CatNftMetadata; pub fn initial_cat_inner_puzzle_ptr( ctx: &mut SpendContext, @@ -31,10 +32,11 @@ pub fn initial_cat_inner_puzzle_ptr( CatalogPrecommitValue::<()>::initial_inner_puzzle( ctx, cat.owner, - CatNftMetadata { + &CatNftMetadata { ticker: cat.code.clone(), name: cat.name.clone(), description: "".to_string(), + hidden_puzzle_hash: None, precision: cat.precision, image_uris: cat.image_uris.clone(), image_hash: cat.image_hash, @@ -237,7 +239,7 @@ pub async fn catalog_continue_launch( &offer, payment_asset_id, constants.launcher_id, - vec![(cat_destination_puzzle_hash, cat_amount)], + &[(cat_destination_puzzle_hash, cat_amount)], )?; let created_cat = created_cats[0]; @@ -496,7 +498,7 @@ pub async fn catalog_continue_launch( tail_hash, left_slot, right_slot, - precommit_coin, + &precommit_coin, Spend { puzzle: eve_nft_inner_puzzle, solution: NodePtr::NIL, diff --git a/src/cli/catalog/initiate_launch.rs b/src/cli/catalog/initiate_launch.rs index 4fe50e4b..8f4bc79b 100644 --- a/src/cli/catalog/initiate_launch.rs +++ b/src/cli/catalog/initiate_launch.rs @@ -5,10 +5,8 @@ use crate::{ utils::{yes_no_prompt, CliError}, Db, }, - get_coinset_client, get_prefix, launch_catalog_registry, load_catalog_state_schedule_csv, - no_assets, parse_amount, print_medieval_vault_configuration, wait_for_coin, - CatalogRegistryConstants, CatalogRegistryState, DefaultCatMakerArgs, MedievalVaultHint, - MedievalVaultInfo, SageClient, StateSchedulerInfo, + get_coinset_client, get_prefix, load_catalog_state_schedule_csv, no_assets, parse_amount, + print_medieval_vault_configuration, wait_for_coin, SageClient, }; use chia::{ bls::PublicKey, @@ -18,8 +16,14 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Cat, DriverError, Launcher, Offer, SpendContext}, - types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, + driver::{ + decode_offer, launch_catalog_registry, Cat, CatalogRegistryConstants, CatalogRegistryState, + DriverError, Launcher, MedievalVaultHint, MedievalVaultInfo, Offer, SingletonInfo, + SpendContext, StateSchedulerInfo, + }, + types::{ + puzzles::DefaultCatMakerArgs, Conditions, Mod, MAINNET_CONSTANTS, TESTNET11_CONSTANTS, + }, utils::Address, }; use clvmr::NodePtr; @@ -251,9 +255,10 @@ pub async fn catalog_initiate_launch( ( ps.block_height, CatalogRegistryState { - cat_maker_puzzle_hash: DefaultCatMakerArgs::curry_tree_hash( + cat_maker_puzzle_hash: DefaultCatMakerArgs::new( ps.asset_id.tree_hash().into(), ) + .curry_tree_hash() .into(), registration_price: ps.registration_price, }, diff --git a/src/cli/catalog/listen.rs b/src/cli/catalog/listen.rs index aa7eec31..f00c0d9c 100644 --- a/src/cli/catalog/listen.rs +++ b/src/cli/catalog/listen.rs @@ -8,17 +8,15 @@ use axum::http::{HeaderValue, Method}; use axum::response::{IntoResponse, Response}; use axum::{http::StatusCode, routing::get, Json, Router}; use chia_wallet_sdk::coinset::ChiaRpcClient; -use chia_wallet_sdk::driver::SpendContext; +use chia_wallet_sdk::driver::{CatalogRegistryConstants, SpendContext}; +use chia_wallet_sdk::types::puzzles::CatalogSlotValue; use clvmr::Allocator; use futures_util::StreamExt; use serde::{Deserialize, Serialize}; use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; use tower_http::cors::CorsLayer; -use crate::{ - get_coinset_client, hex_string_to_bytes32, sync_catalog, CatalogRegistryConstants, - CatalogSlotValue, CliError, Db, -}; +use crate::{get_coinset_client, hex_string_to_bytes32, sync_catalog, CliError, Db}; #[derive(Debug, Deserialize)] struct WebSocketMessage { @@ -42,8 +40,10 @@ pub struct CatalogNeighborResponse { pub left_parent_parent_info: String, pub left_parent_inner_puzzle_hash: String, + pub left_parent_amount: u64, pub right_parent_parent_info: String, pub right_parent_inner_puzzle_hash: String, + pub right_parent_amount: u64, } #[derive(Clone)] @@ -150,12 +150,14 @@ async fn get_neighbors( left_left_asset_id: hex::encode(left.info.value.neighbors.left_value.to_bytes()), right_right_asset_id: hex::encode(right.info.value.neighbors.right_value.to_bytes()), - left_parent_parent_info: hex::encode(left.proof.parent_parent_info.to_bytes()), + left_parent_parent_info: hex::encode(left.proof.parent_parent_coin_info.to_bytes()), left_parent_inner_puzzle_hash: hex::encode(left.proof.parent_inner_puzzle_hash.to_bytes()), - right_parent_parent_info: hex::encode(right.proof.parent_parent_info.to_bytes()), + left_parent_amount: left.proof.parent_amount, + right_parent_parent_info: hex::encode(right.proof.parent_parent_coin_info.to_bytes()), right_parent_inner_puzzle_hash: hex::encode( right.proof.parent_inner_puzzle_hash.to_bytes(), ), + right_parent_amount: right.proof.parent_amount, }; Ok(Json(response)) diff --git a/src/cli/catalog/quick_sync.rs b/src/cli/catalog/quick_sync.rs index fc3ae859..22076527 100644 --- a/src/cli/catalog/quick_sync.rs +++ b/src/cli/catalog/quick_sync.rs @@ -1,10 +1,10 @@ use chia::protocol::CoinSpend; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::SpendContext, + driver::{CatalogRegistry, CatalogRegistryConstants, SpendContext}, }; -use crate::{mempool_catalog_maybe, CatalogRegistry, CatalogRegistryConstants, CliError}; +use crate::{mempool_catalog_maybe, CliError}; pub async fn quick_sync_catalog( client: &CoinsetClient, diff --git a/src/cli/catalog/register.rs b/src/cli/catalog/register.rs index fdcc9fdb..fb26f8f2 100644 --- a/src/cli/catalog/register.rs +++ b/src/cli/catalog/register.rs @@ -5,18 +5,24 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, CatLayer, Layer, Offer, Puzzle, Spend, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, CatLayer, CatalogPrecommitValue, + CatalogRefundAction, CatalogRegisterAction, CatalogRegistryConstants, Layer, Offer, + PrecommitCoin, PrecommitLayer, Puzzle, Slot, Spend, SpendContext, + }, + test::print_spend_bundle_to_file, + types::{ + puzzles::{CatNftMetadata, CatalogSlotValue, DefaultCatMakerArgs}, + Mod, + }, utils::Address, }; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ - 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, - CliError, Db, DefaultCatMakerArgs, PrecommitCoin, PrecommitLayer, SageClient, Slot, + assets_xch_only, get_coinset_client, get_constants, get_prefix, hex_string_to_bytes, + hex_string_to_bytes32, no_assets, parse_amount, quick_sync_catalog, sync_catalog, + wait_for_coin, yes_no_prompt, CatalogApiClient, CliError, Db, SageClient, }; #[allow(clippy::too_many_arguments)] @@ -36,6 +42,7 @@ pub fn initial_metadata_from_arguments( ticker, name, description, + hidden_puzzle_hash: None, precision, image_uris: image_uris_str.split(',').map(|s| s.to_string()).collect(), image_hash: hex_string_to_bytes32(&image_hash_str)?, @@ -129,7 +136,7 @@ pub async fn catalog_register( let registered_asset_id: Bytes32 = ctx.tree_hash(tail_ptr).into(); if !refund - && DefaultCatMakerArgs::curry_tree_hash(payment_asset_id.tree_hash().into()) + && DefaultCatMakerArgs::new(payment_asset_id.tree_hash().into()).curry_tree_hash() != catalog.info.state.cat_maker_puzzle_hash.into() { yes_no_prompt("CAT maker puzzle hash doesn't correspond to the given payment asset ID. Registration will NOT work unless the price singleton changes the registry's state. Continue at your own risk?")?; @@ -151,7 +158,7 @@ pub async fn catalog_register( let initial_nft_puzzle_ptr = CatalogPrecommitValue::<()>::initial_inner_puzzle( &mut ctx, recipient_puzzle_hash, - initial_metadata.clone(), + &initial_metadata, )?; let precommit_value = CatalogPrecommitValue::with_default_cat_maker( @@ -283,13 +290,11 @@ pub async fn catalog_register( create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; let sec_conds = if refund { - let slot: Option> = if DefaultCatMakerArgs::curry_tree_hash( + let slot: Option> = if DefaultCatMakerArgs::new( payment_asset_id.tree_hash().into(), - ) == catalog - .info - .state - .cat_maker_puzzle_hash - .into() + ) + .curry_tree_hash() + == catalog.info.state.cat_maker_puzzle_hash.into() && payment_cat_amount == catalog.info.state.registration_price { if local { @@ -346,7 +351,7 @@ pub async fn catalog_register( &mut catalog, registered_asset_id, slot.as_ref().map(|s| s.info.value.neighbors), - precommit_coin, + &precommit_coin, slot, )? .reserve_fee(1) @@ -373,7 +378,7 @@ pub async fn catalog_register( registered_asset_id, left_slot, right_slot, - precommit_coin, + &precommit_coin, Spend { puzzle: initial_nft_puzzle_ptr, solution: NodePtr::NIL, diff --git a/src/cli/catalog/sign_catalog_state_update.rs b/src/cli/catalog/sign_catalog_state_update.rs index 85ba67ba..988b6df2 100644 --- a/src/cli/catalog/sign_catalog_state_update.rs +++ b/src/cli/catalog/sign_catalog_state_update.rs @@ -1,9 +1,12 @@ use chia::{clvm_utils::ToTreeHash, protocol::Bytes32}; +use chia_wallet_sdk::{ + driver::{CatalogRegistryConstants, CatalogRegistryState, MedievalVault}, + types::{puzzles::DefaultCatMakerArgs, Mod}, +}; use crate::{ get_constants, hex_string_to_bytes32, multisig_sign_thing_finish, multisig_sign_thing_start, - parse_amount, quick_sync_catalog, CatalogRegistryConstants, CatalogRegistryState, CliError, - DefaultCatMakerArgs, MedievalVault, + parse_amount, quick_sync_catalog, CliError, }; pub async fn catalog_sign_state_update( @@ -18,10 +21,9 @@ pub async fn catalog_sign_state_update( let new_payment_asset_amount = parse_amount(&new_payment_asset_amount_str, true)?; let new_state = CatalogRegistryState { - cat_maker_puzzle_hash: DefaultCatMakerArgs::curry_tree_hash( - new_payment_asset_id.tree_hash().into(), - ) - .into(), + cat_maker_puzzle_hash: DefaultCatMakerArgs::new(new_payment_asset_id.tree_hash().into()) + .curry_tree_hash() + .into(), registration_price: new_payment_asset_amount, }; diff --git a/src/cli/catalog/sync.rs b/src/cli/catalog/sync.rs index 37d2b6c4..77d4dfb8 100644 --- a/src/cli/catalog/sync.rs +++ b/src/cli/catalog/sync.rs @@ -8,15 +8,18 @@ use chia::{ use chia_puzzle_types::Memos; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{DriverError, Layer, Puzzle, SingletonLayer, SpendContext}, - types::{Condition, Conditions}, + driver::{ + CatalogRegistry, CatalogRegistryConstants, CatalogRegistryInfo, CatalogRegistryState, + DriverError, Layer, Puzzle, SingletonLayer, Slot, SpendContext, + }, + types::{ + puzzles::{CatalogSlotValue, SlotInfo}, + Condition, Conditions, + }, }; use clvmr::NodePtr; -use crate::{ - CatalogRegistry, CatalogRegistryConstants, CatalogRegistryInfo, CatalogRegistryState, - CatalogSlotValue, CliError, Db, Slot, SlotInfo, SlotProof, -}; +use crate::{CliError, Db}; pub async fn sync_catalog( client: &CoinsetClient, @@ -132,9 +135,10 @@ pub async fn sync_catalog( CatalogRegistryInfo::new(initial_state, constants), ); - let slot_proof = SlotProof { - parent_parent_info: lineage_proof.parent_parent_coin_info, + let slot_proof = LineageProof { + parent_parent_coin_info: lineage_proof.parent_parent_coin_info, parent_inner_puzzle_hash: lineage_proof.parent_inner_puzzle_hash, + parent_amount: lineage_proof.parent_amount, }; let left_slot_value = CatalogSlotValue::initial_left_end(); let right_slot_value = CatalogSlotValue::initial_right_end(); diff --git a/src/cli/catalog/unroll_state_scheduler.rs b/src/cli/catalog/unroll_state_scheduler.rs index aca3f04a..76be1dd2 100644 --- a/src/cli/catalog/unroll_state_scheduler.rs +++ b/src/cli/catalog/unroll_state_scheduler.rs @@ -1,15 +1,16 @@ use chia::protocol::{Bytes32, SpendBundle}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Offer, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, CatalogRegistryConstants, + CatalogRegistryState, DelegatedStateAction, Offer, SpendContext, + }, types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, }; use crate::{ - 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, + assets_xch_only, get_coinset_client, no_assets, parse_amount, sync_multisig_singleton, + wait_for_coin, yes_no_prompt, CliError, Db, MultisigSingleton, SageClient, }; use super::sync_catalog; diff --git a/src/cli/catalog/verify_deployment.rs b/src/cli/catalog/verify_deployment.rs index 6ca02854..49456e85 100644 --- a/src/cli/catalog/verify_deployment.rs +++ b/src/cli/catalog/verify_deployment.rs @@ -6,20 +6,25 @@ 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::types::Mod; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Layer, Puzzle, SingletonLayer, SpendContext}, - types::{Condition, Conditions}, + driver::{ + CatalogRegistry, CatalogRegistryConstants, CatalogRegistryInfo, CatalogRegistryState, + Layer, Puzzle, SingletonLayer, Slot, SpendContext, UniquenessPrelauncher, + }, + types::{ + puzzles::{CatalogSlotValue, DefaultCatMakerArgs, SlotInfo, ANY_METADATA_UPDATER_HASH}, + Condition, Conditions, + }, }; use clvmr::serde::node_from_bytes; use clvmr::NodePtr; use crate::{ get_coinset_client, initial_cat_inner_puzzle_ptr, load_catalog_premine_csv, - load_catalog_state_schedule_csv, print_medieval_vault_configuration, CatalogRegistry, - CatalogRegistryConstants, CatalogRegistryInfo, CatalogRegistryState, CatalogSlotValue, - CliError, DefaultCatMakerArgs, MultisigSingleton, Slot, SlotInfo, UniquenessPrelauncher, - ANY_METADATA_UPDATER_HASH, + load_catalog_state_schedule_csv, print_medieval_vault_configuration, CliError, + MultisigSingleton, }; use crate::sync_multisig_singleton; @@ -169,10 +174,9 @@ pub async fn catalog_verify_deployment(testnet11: bool) -> Result<(), CliError> if hinted_launcher_id != catalog_constants.launcher_id || initial_state.registration_price != 1 || initial_state.cat_maker_puzzle_hash - != DefaultCatMakerArgs::curry_tree_hash( - initial_registration_asset_id.tree_hash().into(), - ) - .into() + != DefaultCatMakerArgs::new(initial_registration_asset_id.tree_hash().into()) + .curry_tree_hash() + .into() || launcher_coin_record.coin.puzzle_hash != SINGLETON_LAUNCHER_HASH.into() || catalog_cc.amount != 1 || catalog_cc.puzzle_hash != catalog_info.inner_puzzle_hash().into() @@ -318,7 +322,9 @@ pub async fn catalog_verify_deployment(testnet11: bool) -> Result<(), CliError> if record.block_height != block || record.registration_price != state.registration_price || state.cat_maker_puzzle_hash - != DefaultCatMakerArgs::curry_tree_hash(record.asset_id.tree_hash().into()).into() + != DefaultCatMakerArgs::new(record.asset_id.tree_hash().into()) + .curry_tree_hash() + .into() { price_schedule_ok = false; break; diff --git a/src/cli/database.rs b/src/cli/database.rs index 10cef3bd..8f30022b 100644 --- a/src/cli/database.rs +++ b/src/cli/database.rs @@ -1,5 +1,10 @@ use chia::{clvm_utils::ToTreeHash, protocol::Bytes32}; -use chia_wallet_sdk::{coinset::CoinRecord, driver::DriverError}; +use chia_puzzle_types::LineageProof; +use chia_wallet_sdk::{ + coinset::CoinRecord, + driver::{DriverError, RewardDistributorConstants, Slot, XchandlesConstants}, + types::puzzles::SlotInfo, +}; use clvm_traits::{FromClvm, ToClvm}; use clvmr::{ serde::{node_from_bytes, node_to_bytes}, @@ -11,8 +16,6 @@ use sqlx::{ }; use std::time::Duration; -use crate::{RewardDistributorConstants, Slot, SlotInfo, SlotProof, XchandlesConstants}; - use super::CliError; pub struct Db { pool: Pool, @@ -35,9 +38,10 @@ impl Db { slot_value_hash BLOB NOT NULL, spent_block_height INTEGER NOT NULL, slot_value BLOB NOT NULL, - parent_parent_info BLOB NOT NULL, + parent_parent_coin_info BLOB NOT NULL, parent_inner_puzzle_hash BLOB NOT NULL, - PRIMARY KEY (singleton_launcher_id, nonce, slot_value_hash, parent_parent_info) + parent_amount INTEGER NOT NULL, + PRIMARY KEY (singleton_launcher_id, nonce, slot_value_hash, parent_parent_coin_info, parent_amount) ) ", ) @@ -145,10 +149,10 @@ impl Db { " INSERT INTO slots ( singleton_launcher_id, nonce, slot_value_hash, spent_block_height, - slot_value, parent_parent_info, parent_inner_puzzle_hash + slot_value, parent_parent_coin_info, parent_inner_puzzle_hash, parent_amount ) - VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7) - ON CONFLICT(singleton_launcher_id, nonce, slot_value_hash, parent_parent_info) DO UPDATE SET spent_block_height = excluded.spent_block_height + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8) + ON CONFLICT(singleton_launcher_id, nonce, slot_value_hash, parent_parent_coin_info, parent_amount) DO UPDATE SET spent_block_height = excluded.spent_block_height ", ) .bind(slot.info.launcher_id.to_vec()) @@ -156,8 +160,9 @@ impl Db { .bind(slot.info.value_hash.to_vec()) .bind(spent_block_height) .bind(slot_value_bytes) - .bind(slot.proof.parent_parent_info.to_vec()) + .bind(slot.proof.parent_parent_coin_info.to_vec()) .bind(slot.proof.parent_inner_puzzle_hash.to_vec()) + .bind(slot.proof.parent_amount as i64) .execute(&self.pool) .await .map_err(CliError::Sqlx)?; @@ -171,18 +176,21 @@ impl Db { { let launcher_id = column_to_bytes32(row.get::<&[u8], _>("singleton_launcher_id"))?; let nonce = row.get::("nonce") as u64; - let parent_parent_info = column_to_bytes32(row.get::<&[u8], _>("parent_parent_info"))?; + let parent_parent_coin_info = + column_to_bytes32(row.get::<&[u8], _>("parent_parent_coin_info"))?; let parent_inner_puzzle_hash = column_to_bytes32(row.get::<&[u8], _>("parent_inner_puzzle_hash"))?; + let parent_amount = row.get::("parent_amount") as u64; let value = node_from_bytes(allocator, row.get::<&[u8], _>("slot_value"))?; let value = SV::from_clvm(allocator, value) .map_err(|err| CliError::Driver(DriverError::FromClvm(err)))?; Ok(Slot::new( - SlotProof { - parent_parent_info, + LineageProof { + parent_parent_coin_info, parent_inner_puzzle_hash, + parent_amount, }, SlotInfo::::from_value(launcher_id, nonce, value), )) diff --git a/src/cli/multisig/broadcast_rekey.rs b/src/cli/multisig/broadcast_rekey.rs index b8b01414..3fdf891d 100644 --- a/src/cli/multisig/broadcast_rekey.rs +++ b/src/cli/multisig/broadcast_rekey.rs @@ -1,6 +1,8 @@ +use chia_wallet_sdk::driver::MedievalVault; + use crate::{ get_constants, hex_string_to_pubkey, multisig_broadcast_thing_finish, - multisig_broadcast_thing_start, print_medieval_vault_configuration, CliError, MedievalVault, + multisig_broadcast_thing_start, print_medieval_vault_configuration, CliError, }; pub async fn multisig_broadcast_rekey( diff --git a/src/cli/multisig/broadcast_thing.rs b/src/cli/multisig/broadcast_thing.rs index e2e07fe0..6712e4d0 100644 --- a/src/cli/multisig/broadcast_thing.rs +++ b/src/cli/multisig/broadcast_thing.rs @@ -4,15 +4,16 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{decode_offer, Offer, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, MedievalVault, Offer, SpendContext, + }, types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, }; use crate::{ - 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, + assets_xch_only, get_coinset_client, hex_string_to_bytes32, hex_string_to_signature, no_assets, + parse_amount, print_medieval_vault_configuration, sync_multisig_singleton, wait_for_coin, + yes_no_prompt, CliError, MultisigSingleton, SageClient, StateSchedulerHintedState, }; pub async fn multisig_broadcast_thing_start( diff --git a/src/cli/multisig/launch.rs b/src/cli/multisig/launch.rs index 4cc9ce70..96c25f5a 100644 --- a/src/cli/multisig/launch.rs +++ b/src/cli/multisig/launch.rs @@ -1,13 +1,16 @@ use chia::{bls::PublicKey, protocol::SpendBundle}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Launcher, Offer, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, Launcher, MedievalVaultHint, + Offer, SpendContext, + }, + types::puzzles::P2MOfNDelegateDirectArgs, }; use crate::{ - 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, + assets_xch_only, get_coinset_client, get_constants, no_assets, parse_amount, + print_medieval_vault_configuration, wait_for_coin, yes_no_prompt, CliError, SageClient, }; pub async fn multisig_launch( diff --git a/src/cli/multisig/sign_rekey.rs b/src/cli/multisig/sign_rekey.rs index 17548a81..6482457a 100644 --- a/src/cli/multisig/sign_rekey.rs +++ b/src/cli/multisig/sign_rekey.rs @@ -1,6 +1,8 @@ +use chia_wallet_sdk::driver::MedievalVault; + use crate::{ get_constants, hex_string_to_pubkey, multisig_sign_thing_finish, multisig_sign_thing_start, - print_medieval_vault_configuration, CliError, MedievalVault, + print_medieval_vault_configuration, CliError, }; pub async fn multisig_sign_rekey( diff --git a/src/cli/multisig/sign_thing.rs b/src/cli/multisig/sign_thing.rs index af3acf0c..f6306c0e 100644 --- a/src/cli/multisig/sign_thing.rs +++ b/src/cli/multisig/sign_thing.rs @@ -2,6 +2,7 @@ use chia::bls::sign; use chia::bls::PublicKey; use chia::protocol::Bytes; use chia_wallet_sdk::coinset::CoinsetClient; +use chia_wallet_sdk::driver::MedievalVault; use chia_wallet_sdk::driver::SpendContext; use chia_wallet_sdk::prelude::AggSig; use chia_wallet_sdk::prelude::AggSigKind; @@ -12,8 +13,7 @@ use clvmr::NodePtr; use crate::{ get_alias_map, get_coinset_client, get_constants, hex_string_to_bytes32, hex_string_to_pubkey, hex_string_to_secret_key, print_medieval_vault_configuration, prompt_for_value, - sync_multisig_singleton, yes_no_prompt, CliError, MedievalVault, MultisigSingleton, - StateSchedulerHintedState, + sync_multisig_singleton, yes_no_prompt, CliError, MultisigSingleton, StateSchedulerHintedState, }; pub async fn multisig_sign_thing_start( diff --git a/src/cli/multisig/sync.rs b/src/cli/multisig/sync.rs index f4b41e58..bbdb7395 100644 --- a/src/cli/multisig/sync.rs +++ b/src/cli/multisig/sync.rs @@ -7,15 +7,17 @@ use chia::{ LineageProof, Proof, }, }; -use chia_wallet_sdk::coinset::{ChiaRpcClient, CoinsetClient}; -use chia_wallet_sdk::driver::SpendContext; +use chia_wallet_sdk::driver::{ + MedievalVaultHint, MedievalVaultInfo, SingletonInfo, SpendContext, StateSchedulerInfo, +}; +use chia_wallet_sdk::{ + coinset::{ChiaRpcClient, CoinsetClient}, + driver::{MedievalVault, StateScheduler}, +}; use clvm_traits::{FromClvm, ToClvm}; use clvmr::{serde::node_from_bytes, Allocator, NodePtr}; -use crate::{ - get_alias_map, CliError, MedievalVault, MedievalVaultHint, MedievalVaultInfo, StateScheduler, - StateSchedulerInfo, -}; +use crate::{get_alias_map, CliError}; pub enum MultisigSingleton where @@ -106,10 +108,10 @@ where println!("\nFollowing state scheduler on-chain..."); } - let mut state_scheduler = StateScheduler::::from_launcher_spend(ctx, launcher_spend)? + let mut state_scheduler = StateScheduler::::from_launcher_spend(ctx, &launcher_spend)? .ok_or(CliError::Custom( - "Failed to parse state scheduler".to_string(), - ))?; + "Failed to parse state scheduler".to_string(), + ))?; loop { let coin_record = client @@ -163,7 +165,7 @@ where (eve_vault, Some(state_scheduler_info)) } else { - let eve_vault = MedievalVault::from_launcher_spend(ctx, launcher_spend)?.ok_or( + let eve_vault = MedievalVault::from_launcher_spend(ctx, &launcher_spend)?.ok_or( CliError::Custom("Singleton not a state scheduler nor a vault".to_string()), )?; @@ -197,7 +199,7 @@ where .coin_solution .ok_or(CliError::CoinNotSpent(vault_record.coin.parent_coin_info))?; - if let Some(vault) = MedievalVault::from_parent_spend(ctx, vault_parent_spend)? { + if let Some(vault) = MedievalVault::from_parent_spend(ctx, &vault_parent_spend)? { return Ok((MultisigSingleton::Vault(vault), state_scheduler_info)); } } diff --git a/src/cli/multisig/view.rs b/src/cli/multisig/view.rs index d2eeb955..fd873b60 100644 --- a/src/cli/multisig/view.rs +++ b/src/cli/multisig/view.rs @@ -1,9 +1,9 @@ -use chia_wallet_sdk::driver::SpendContext; +use chia_wallet_sdk::driver::{CatalogRegistryState, SpendContext, XchandlesRegistryState}; use clvm_traits::{FromClvm, ToClvm}; use crate::{ get_coinset_client, hex_string_to_bytes32, print_medieval_vault_configuration, - sync_multisig_singleton, CatalogRegistryState, CliError, XchandlesRegistryState, + sync_multisig_singleton, CliError, }; #[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] diff --git a/src/cli/reward_distributor/add_rewards.rs b/src/cli/reward_distributor/add_rewards.rs index 2d086131..3e0b0bd9 100644 --- a/src/cli/reward_distributor/add_rewards.rs +++ b/src/cli/reward_distributor/add_rewards.rs @@ -1,16 +1,18 @@ use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, CatSpend, Offer, Spend, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, CatSpend, Offer, + RewardDistributorAddIncentivesAction, RewardDistributorSyncAction, Spend, SpendContext, + }, types::{puzzles::SettlementPayment, Conditions}, }; use clvmr::NodePtr; use crate::{ - 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, + assets_xch_and_cat, get_coinset_client, get_constants, get_last_onchain_timestamp, + hex_string_to_bytes32, no_assets, parse_amount, sync_distributor, wait_for_coin, yes_no_prompt, + CliError, Db, SageClient, }; pub async fn reward_distributor_add_rewards( diff --git a/src/cli/reward_distributor/broadcast_entry_update.rs b/src/cli/reward_distributor/broadcast_entry_update.rs index cad740ee..b597d10b 100644 --- a/src/cli/reward_distributor/broadcast_entry_update.rs +++ b/src/cli/reward_distributor/broadcast_entry_update.rs @@ -1,12 +1,16 @@ use chia::protocol::Bytes32; use chia::{clvm_utils::ToTreeHash, protocol::Bytes}; +use chia_wallet_sdk::driver::{ + MedievalVault, RewardDistributorAddEntryAction, RewardDistributorRemoveEntryAction, + RewardDistributorSyncAction, SingletonInfo, +}; +use chia_wallet_sdk::types::puzzles::StateSchedulerLayerSolution; use clvmr::{Allocator, NodePtr}; use crate::{ 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, + Db, }; pub async fn reward_distributor_broadcast_entry_update( diff --git a/src/cli/reward_distributor/clawback_rewards.rs b/src/cli/reward_distributor/clawback_rewards.rs index 9d36cf47..598a7e29 100644 --- a/src/cli/reward_distributor/clawback_rewards.rs +++ b/src/cli/reward_distributor/clawback_rewards.rs @@ -2,7 +2,10 @@ use chia::protocol::{Coin, SpendBundle}; use chia_puzzle_types::Memos; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Offer, Spend, SpendContext, StandardLayer}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, Offer, + RewardDistributorWithdrawIncentivesAction, Spend, SpendContext, StandardLayer, + }, types::Conditions, utils::Address, }; @@ -10,11 +13,10 @@ use clvm_traits::clvm_quote; use clvmr::NodePtr; use crate::{ - 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, no_assets, parse_amount, spend_security_coin, spend_to_coin_spend, - sync_distributor, wait_for_coin, yes_no_prompt, CliError, Db, - RewardDistributorWithdrawIncentivesAction, SageClient, + assets_xch_only, find_commitment_slots, find_reward_slot, get_coin_public_key, + get_coinset_client, get_constants, hex_string_to_bytes32, hex_string_to_signature, no_assets, + parse_amount, spend_to_coin_spend, sync_distributor, wait_for_coin, yes_no_prompt, CliError, + Db, SageClient, }; pub async fn reward_distributor_clawback_rewards( diff --git a/src/cli/reward_distributor/commit_rewards.rs b/src/cli/reward_distributor/commit_rewards.rs index b8040436..e1eb7a7d 100644 --- a/src/cli/reward_distributor/commit_rewards.rs +++ b/src/cli/reward_distributor/commit_rewards.rs @@ -1,16 +1,18 @@ use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, CatSpend, Offer, Spend, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, CatSpend, Offer, + RewardDistributorCommitIncentivesAction, Spend, SpendContext, + }, types::puzzles::SettlementPayment, utils::Address, }; use clvmr::NodePtr; use crate::{ - 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, + assets_xch_and_cat, find_reward_slot, get_coinset_client, get_constants, hex_string_to_bytes32, + no_assets, parse_amount, sync_distributor, wait_for_coin, yes_no_prompt, CliError, Db, SageClient, }; diff --git a/src/cli/reward_distributor/initiate_payout.rs b/src/cli/reward_distributor/initiate_payout.rs index 347af80a..fee72d30 100644 --- a/src/cli/reward_distributor/initiate_payout.rs +++ b/src/cli/reward_distributor/initiate_payout.rs @@ -1,15 +1,17 @@ use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Offer, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, Offer, + RewardDistributorInitiatePayoutAction, RewardDistributorSyncAction, SpendContext, + }, types::Conditions, }; use crate::{ - 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, + assets_xch_only, find_entry_slots, get_coinset_client, get_constants, + get_last_onchain_timestamp, hex_string_to_bytes32, no_assets, parse_amount, sync_distributor, + wait_for_coin, yes_no_prompt, CliError, Db, SageClient, }; pub async fn reward_distributor_initiate_payout( diff --git a/src/cli/reward_distributor/launch.rs b/src/cli/reward_distributor/launch.rs index 1c3b1de9..49f772d9 100644 --- a/src/cli/reward_distributor/launch.rs +++ b/src/cli/reward_distributor/launch.rs @@ -1,14 +1,16 @@ use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Offer, SpendContext}, + driver::{ + decode_offer, launch_dig_reward_distributor, Offer, RewardDistributorConstants, + RewardDistributorType, SpendContext, + }, utils::Address, }; use crate::{ - assets_xch_and_cat, get_coinset_client, get_constants, hex_string_to_bytes32, - launch_dig_reward_distributor, no_assets, parse_amount, wait_for_coin, yes_no_prompt, CliError, - Db, RewardDistributorConstants, RewardDistributorType, SageClient, + assets_xch_and_cat, get_coinset_client, get_constants, hex_string_to_bytes32, no_assets, + parse_amount, wait_for_coin, yes_no_prompt, CliError, Db, SageClient, }; #[allow(clippy::too_many_arguments)] diff --git a/src/cli/reward_distributor/new_epoch.rs b/src/cli/reward_distributor/new_epoch.rs index 6af9b8f6..e280fde2 100644 --- a/src/cli/reward_distributor/new_epoch.rs +++ b/src/cli/reward_distributor/new_epoch.rs @@ -1,13 +1,15 @@ use crate::{ - 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, + assets_xch_only, find_reward_slot, get_coinset_client, get_constants, hex_string_to_bytes32, + no_assets, parse_amount, sync_distributor, wait_for_coin, yes_no_prompt, CliError, Db, + SageClient, }; use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Offer, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, Offer, + RewardDistributorNewEpochAction, RewardDistributorSyncAction, SpendContext, + }, }; pub async fn reward_distributor_new_epoch( diff --git a/src/cli/reward_distributor/sign_entry_update.rs b/src/cli/reward_distributor/sign_entry_update.rs index fd7e9ccc..f7c3e4e6 100644 --- a/src/cli/reward_distributor/sign_entry_update.rs +++ b/src/cli/reward_distributor/sign_entry_update.rs @@ -2,11 +2,12 @@ use chia::{ clvm_utils::ToTreeHash, protocol::{Bytes, Bytes32}, }; +use chia_wallet_sdk::driver::MedievalVault; use clvmr::Allocator; use crate::{ get_constants, hex_string_to_bytes32, multisig_sign_thing_finish, multisig_sign_thing_start, - CliError, Db, MedievalVault, + CliError, Db, }; pub async fn reward_distributor_sign_entry_update( diff --git a/src/cli/reward_distributor/stake.rs b/src/cli/reward_distributor/stake.rs index fb3c4e78..db240041 100644 --- a/src/cli/reward_distributor/stake.rs +++ b/src/cli/reward_distributor/stake.rs @@ -2,17 +2,22 @@ use chia::protocol::SpendBundle; use chia_puzzle_types::{standard::StandardArgs, LineageProof}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, HashedPtr, Layer, Offer, Puzzle, SingletonLayer, SpendContext}, - types::Conditions, + driver::{ + create_security_coin, decode_offer, spend_security_coin, spend_settlement_nft, HashedPtr, + Layer, Offer, Puzzle, RewardDistributorStakeAction, RewardDistributorSyncAction, + SingletonLayer, SpendContext, + }, + types::{ + puzzles::{IntermediaryCoinProof, NftLauncherProof}, + Conditions, + }, utils::Address, }; use crate::{ - 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, + assets_xch_and_nft, get_coinset_client, get_constants, get_last_onchain_timestamp, get_prefix, + hex_string_to_bytes32, hex_string_to_pubkey, no_assets, parse_amount, sync_distributor, + wait_for_coin, yes_no_prompt, CliError, Db, SageClient, }; pub async fn reward_distributor_stake( diff --git a/src/cli/reward_distributor/sync.rs b/src/cli/reward_distributor/sync.rs index 90f6eb90..cd03ec12 100644 --- a/src/cli/reward_distributor/sync.rs +++ b/src/cli/reward_distributor/sync.rs @@ -1,14 +1,16 @@ use chia::protocol::SpendBundle; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Offer, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, Offer, + RewardDistributorSyncAction, SpendContext, + }, }; use crate::{ - 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, + assets_xch_only, get_coinset_client, get_constants, get_last_onchain_timestamp, + hex_string_to_bytes32, no_assets, parse_amount, sync_distributor, wait_for_coin, yes_no_prompt, + CliError, Db, SageClient, }; pub async fn reward_distributor_sync( diff --git a/src/cli/reward_distributor/sync_distributor.rs b/src/cli/reward_distributor/sync_distributor.rs index 575620e2..d633fdf2 100644 --- a/src/cli/reward_distributor/sync_distributor.rs +++ b/src/cli/reward_distributor/sync_distributor.rs @@ -7,18 +7,18 @@ use chia_puzzle_types::cat::CatSolution; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, driver::{ - Cat, CatInfo, CatLayer, CatSpend, DriverError, HashedPtr, Layer, Puzzle, SingletonLayer, - Spend, SpendContext, + Cat, CatInfo, CatLayer, CatSpend, DriverError, HashedPtr, Layer, Puzzle, Reserve, + RewardDistributor, RewardDistributorConstants, SingletonLayer, Slot, Spend, SpendContext, + }, + types::puzzles::{ + P2DelegatedBySingletonLayerArgs, RewardDistributorCommitmentSlotValue, + RewardDistributorEntrySlotValue, RewardDistributorRewardSlotValue, + RewardDistributorSlotNonce, SlotInfo, }, }; use clvmr::NodePtr; -use crate::{ - CliError, Db, P2DelegatedBySingletonLayerArgs, Reserve, RewardDistributor, - RewardDistributorCommitmentSlotValue, RewardDistributorConstants, - RewardDistributorEntrySlotValue, RewardDistributorRewardSlotValue, RewardDistributorSlotNonce, - Slot, SlotInfo, SlotProof, -}; +use crate::{CliError, Db}; pub async fn sync_distributor( client: &CoinsetClient, @@ -139,7 +139,7 @@ pub async fn sync_distributor( ctx, constants, initial_state, - distributor_eve_coin_spend, + &distributor_eve_coin_spend, reserve.coin.parent_coin_info, reserve.proof, )? @@ -233,6 +233,7 @@ pub async fn mempool_distributor_maybe( 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; + let mut distributor_counter = 0; loop { let Some(distributor_spend) = mempool_item .spend_bundle @@ -246,7 +247,11 @@ pub async fn mempool_distributor_maybe( let Some(new_distributor) = RewardDistributor::from_spend( ctx, distributor_spend, - Some(distributor.reserve.child(1).proof), + Some(if distributor_counter > 0 { + distributor.reserve.child(1).proof + } else { + distributor.reserve.proof + }), distributor.info.constants, )? else { @@ -254,6 +259,7 @@ pub async fn mempool_distributor_maybe( }; distributor = new_distributor; parent_id_to_look_for = distributor.coin.coin_id(); + distributor_counter += 1; } let reserve_spend = mempool_item @@ -379,9 +385,10 @@ pub async fn find_reward_slot( 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, + LineageProof { + parent_parent_coin_info: distributor_spent.coin.parent_coin_info, parent_inner_puzzle_hash: puzzle.inner_puzzle.tree_hash().into(), + parent_amount: distributor_spent.coin.amount, }, slot_info, ); diff --git a/src/cli/reward_distributor/unstake.rs b/src/cli/reward_distributor/unstake.rs index 2b6958c2..ef652302 100644 --- a/src/cli/reward_distributor/unstake.rs +++ b/src/cli/reward_distributor/unstake.rs @@ -1,5 +1,5 @@ use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, + clvm_utils::TreeHash, protocol::{Bytes32, Coin, SpendBundle}, }; use chia_puzzle_types::{ @@ -10,10 +10,14 @@ use chia_puzzle_types::{ use chia_wallet_sdk::{ coinset::ChiaRpcClient, driver::{ - decode_offer, HashedPtr, Nft, Offer, Puzzle, Spend, SpendContext, SpendWithConditions, - StandardLayer, + decode_offer, Nft, Offer, Puzzle, RewardDistributorStakeAction, + RewardDistributorSyncAction, RewardDistributorUnstakeAction, Spend, SpendContext, + SpendWithConditions, StandardLayer, + }, + types::{ + puzzles::{NonceWrapperArgs, SettlementPayment}, + Conditions, Mod, }, - types::{puzzles::SettlementPayment, Conditions}, utils::Address, }; @@ -21,8 +25,7 @@ use crate::{ 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, 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, + CliError, Db, SageClient, }; pub async fn reward_distributor_unstake( @@ -84,14 +87,11 @@ pub async fn reward_distributor_unstake( .ok_or(CliError::SlotNotFound("Entry"))?; println!("Fetching locked NFT..."); - let locked_nft_hint: Bytes32 = CurriedProgram { - program: NONCE_WRAPPER_PUZZLE_HASH, - args: NonceWrapperArgs:: { - nonce: custody_puzzle_hash, - inner_puzzle: RewardDistributorStakeActionArgs::my_p2_puzzle_hash(launcher_id).into(), - }, + let locked_nft_hint: Bytes32 = NonceWrapperArgs:: { + nonce: custody_puzzle_hash, + inner_puzzle: RewardDistributorStakeAction::my_p2_puzzle_hash(launcher_id).into(), } - .tree_hash() + .curry_tree_hash() .into(); let possible_locked_nft_coins = client @@ -115,7 +115,7 @@ pub async fn reward_distributor_unstake( let parent_puzzle = Puzzle::parse(&ctx, parent_puzzle); let parent_solution = ctx.alloc(&parent_coin_spend.solution)?; - if let Ok(Some(nft)) = Nft::::parse_child( + if let Ok(Some(nft)) = Nft::parse_child( &mut ctx, parent_coin_spend.coin, parent_puzzle, diff --git a/src/cli/reward_distributor/view.rs b/src/cli/reward_distributor/view.rs index b11cf10e..a39d38cb 100644 --- a/src/cli/reward_distributor/view.rs +++ b/src/cli/reward_distributor/view.rs @@ -1,8 +1,10 @@ use crate::{ get_coinset_client, get_prefix, hex_string_to_bytes32, sync_distributor, CliError, Db, - RewardDistributorType, }; -use chia_wallet_sdk::{driver::SpendContext, utils::Address}; +use chia_wallet_sdk::{ + driver::{RewardDistributorType, SpendContext}, + utils::Address, +}; pub async fn reward_distributor_view( launcher_id_str: String, diff --git a/src/cli/verifications/broadcast_launch.rs b/src/cli/verifications/broadcast_launch.rs index 17c43615..28da14ef 100644 --- a/src/cli/verifications/broadcast_launch.rs +++ b/src/cli/verifications/broadcast_launch.rs @@ -4,8 +4,11 @@ use chia::{ }; use chia_puzzle_types::LineageProof; use chia_wallet_sdk::{ - driver::{decode_offer, Launcher, Offer}, - types::Conditions, + driver::{ + decode_offer, spend_settlement_cats, Launcher, MedievalVault, Offer, SingletonInfo, + Verification, VerificationAsserter, VerificationLauncherKVList, VerifiedData, + }, + types::{puzzles::CatNftMetadata, Conditions}, utils::Address, }; use clvm_traits::clvm_quote; @@ -13,9 +16,7 @@ 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, spend_settlement_cats, - yes_no_prompt, CatNftMetadata, CliError, MedievalVault, Verification, VerificationAsserter, - VerificationLauncherKVList, VerifiedData, + multisig_broadcast_thing_finish, multisig_broadcast_thing_start, yes_no_prompt, CliError, }; #[allow(clippy::too_many_arguments)] @@ -63,7 +64,7 @@ pub async fn verifications_broadcast_launch( let (launch_conds, _coin) = launcher.spend( &mut ctx, - Verification::inner_puzzle_hash(launcher_id, verified_data.clone()).into(), + Verification::inner_puzzle_hash(launcher_id, &verified_data).into(), &VerificationLauncherKVList { revocation_singleton_launcher_id: launcher_id, verified_data: verified_data.clone(), @@ -159,7 +160,7 @@ pub async fn verifications_broadcast_launch( &offer, *asset_id, recipient_puzzle_hash, - vec![(recipient_puzzle_hash, total_cat_amount)], + &[(recipient_puzzle_hash, total_cat_amount)], )?; conds = conds.extend(assert_cond); } diff --git a/src/cli/verifications/broadcast_revocation.rs b/src/cli/verifications/broadcast_revocation.rs index bfadac0a..c876c120 100644 --- a/src/cli/verifications/broadcast_revocation.rs +++ b/src/cli/verifications/broadcast_revocation.rs @@ -1,9 +1,12 @@ +use chia_wallet_sdk::{ + driver::{MedievalVault, SingletonInfo, Verification, VerifiedData}, + types::puzzles::StateSchedulerLayerSolution, +}; use clvmr::NodePtr; use crate::{ get_constants, get_latest_data_for_asset_id, hex_string_to_bytes32, multisig_broadcast_thing_finish, multisig_broadcast_thing_start, sync_verifications, CliError, - MedievalVault, StateSchedulerLayerSolution, Verification, VerifiedData, }; pub async fn verifications_broadcast_revocation( @@ -59,7 +62,7 @@ pub async fn verifications_broadcast_revocation( let delegated_solution_ptr = ctx.alloc(&StateSchedulerLayerSolution { other_singleton_inner_puzzle_hash: Verification::inner_puzzle_hash( verifications[0].info.revocation_singleton_launcher_id, - verifications[0].info.verified_data.clone(), + &verifications[0].info.verified_data, ) .into(), inner_solution: NodePtr::NIL, diff --git a/src/cli/verifications/create_offer.rs b/src/cli/verifications/create_offer.rs index 2c374b33..5b4fc445 100644 --- a/src/cli/verifications/create_offer.rs +++ b/src/cli/verifications/create_offer.rs @@ -4,16 +4,18 @@ use chia::{ }; use chia_puzzle_types::Memos; use chia_wallet_sdk::{ - driver::{decode_offer, encode_offer, Offer, SpendContext}, + driver::{ + create_security_coin, decode_offer, encode_offer, spend_security_coin, Offer, SpendContext, + VerificationAsserter, VerifiedData, + }, types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, }; use clvm_traits::{clvm_list, clvm_quote}; use clvmr::serde::node_to_bytes; use crate::{ - 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, + assets_xch_and_cat, get_coinset_client, get_latest_data_for_asset_id, hex_string_to_bytes32, + no_assets, parse_amount, yes_no_prompt, CliError, SageClient, }; pub async fn verifications_create_offer( diff --git a/src/cli/verifications/sign_launch.rs b/src/cli/verifications/sign_launch.rs index bb4d3987..0daad0e4 100644 --- a/src/cli/verifications/sign_launch.rs +++ b/src/cli/verifications/sign_launch.rs @@ -1,10 +1,11 @@ -use chia_wallet_sdk::driver::Launcher; +use chia_wallet_sdk::driver::{ + Launcher, MedievalVault, SingletonInfo, Verification, VerificationLauncherKVList, VerifiedData, +}; use clvm_traits::clvm_quote; use crate::{ get_constants, get_latest_data_for_asset_id, hex_string_to_bytes32, multisig_sign_thing_finish, - multisig_sign_thing_start, CliError, MedievalVault, Verification, VerificationLauncherKVList, - VerifiedData, + multisig_sign_thing_start, CliError, }; pub async fn verifications_sign_launch( @@ -47,7 +48,7 @@ pub async fn verifications_sign_launch( let (launch_conds, _coin) = launcher.spend( &mut ctx, - Verification::inner_puzzle_hash(launcher_id, verified_data.clone()).into(), + Verification::inner_puzzle_hash(launcher_id, &verified_data).into(), &VerificationLauncherKVList { revocation_singleton_launcher_id: launcher_id, verified_data, diff --git a/src/cli/verifications/sign_revocation.rs b/src/cli/verifications/sign_revocation.rs index cd8bbf76..e2433975 100644 --- a/src/cli/verifications/sign_revocation.rs +++ b/src/cli/verifications/sign_revocation.rs @@ -1,6 +1,8 @@ +use chia_wallet_sdk::driver::{MedievalVault, VerifiedData}; + use crate::{ get_constants, get_latest_data_for_asset_id, hex_string_to_bytes32, multisig_sign_thing_finish, - multisig_sign_thing_start, sync_verifications, CliError, MedievalVault, VerifiedData, + multisig_sign_thing_start, sync_verifications, CliError, }; pub async fn verifications_sign_revocation( diff --git a/src/cli/verifications/sync_data.rs b/src/cli/verifications/sync_data.rs index 8e1fec84..28384e6a 100644 --- a/src/cli/verifications/sync_data.rs +++ b/src/cli/verifications/sync_data.rs @@ -5,12 +5,13 @@ use chia::{ use chia_puzzles::SINGLETON_LAUNCHER_HASH; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{Nft, Puzzle, SpendContext}, + driver::{ + CatalogRegistry, CatalogRegistryConstants, Nft, Puzzle, SpendContext, UniquenessPrelauncher, + }, + types::puzzles::CatNftMetadata, }; -use crate::{ - CatNftMetadata, CatalogRegistry, CatalogRegistryConstants, CliError, UniquenessPrelauncher, -}; +use crate::CliError; pub async fn get_latest_data_for_asset_id( ctx: &mut SpendContext, @@ -86,9 +87,7 @@ pub async fn get_latest_data_for_asset_id( let puzzle_ptr = ctx.alloc(&coin_spend.puzzle_reveal)?; let puzzle = Puzzle::parse(ctx, puzzle_ptr); let solution_ptr = ctx.alloc(&coin_spend.solution)?; - if let Ok(Some(nft)) = - Nft::::parse_child(ctx, nft_record.coin, puzzle, solution_ptr) - { + if let Ok(Some(nft)) = Nft::parse_child(ctx, nft_record.coin, puzzle, solution_ptr) { next_nft_record = client .get_coin_record_by_name(nft.coin.coin_id()) .await? @@ -104,5 +103,6 @@ pub async fn get_latest_data_for_asset_id( hex::encode(asset_id) )))?; - Ok(latest_nft.info.metadata) + ctx.extract::(latest_nft.info.metadata.ptr()) + .map_err(CliError::Driver) } diff --git a/src/cli/verifications/sync_verifications.rs b/src/cli/verifications/sync_verifications.rs index f8da5089..970d7d6a 100644 --- a/src/cli/verifications/sync_verifications.rs +++ b/src/cli/verifications/sync_verifications.rs @@ -3,11 +3,14 @@ use chia_puzzle_types::singleton::LauncherSolution; use chia_puzzles::SINGLETON_LAUNCHER_HASH; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{DriverError, Layer, Puzzle, SingletonLayer, SpendContext}, + driver::{ + DriverError, Layer, Puzzle, SingletonLayer, SpendContext, Verification, + VerificationLauncherKVList, + }, }; use clvmr::NodePtr; -use crate::{CliError, Verification, VerificationLauncherKVList}; +use crate::CliError; pub async fn sync_verifications( ctx: &mut SpendContext, diff --git a/src/cli/verifications/view.rs b/src/cli/verifications/view.rs index 252a21c4..cc86f2de 100644 --- a/src/cli/verifications/view.rs +++ b/src/cli/verifications/view.rs @@ -1,9 +1,9 @@ use chia::protocol::Bytes32; -use chia_wallet_sdk::driver::SpendContext; +use chia_wallet_sdk::driver::{SpendContext, VerifiedData}; use crate::{ get_coinset_client, get_latest_data_for_asset_id, hex_string_to_bytes32, sync_verifications, - CliError, VerifiedData, + CliError, }; pub async fn verifications_view( diff --git a/src/cli/xchandles/continue_launch.rs b/src/cli/xchandles/continue_launch.rs index 36c9b5fe..a4585f3d 100644 --- a/src/cli/xchandles/continue_launch.rs +++ b/src/cli/xchandles/continue_launch.rs @@ -7,20 +7,24 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::{decode_offer, CatLayer, Layer, Offer, Puzzle, SingleCatSpend, Spend, SpendContext}, - types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, spend_settlement_cats, CatLayer, + CatalogPrecommitValue, Layer, Offer, PrecommitCoin, PrecommitLayer, Puzzle, SingleCatSpend, + Spend, SpendContext, XchandlesPrecommitValue, XchandlesRegisterAction, + }, + types::{ + puzzles::{XchandlesFactorPricingPuzzleArgs, XchandlesPricingSolution}, + Conditions, Mod, MAINNET_CONSTANTS, TESTNET11_CONSTANTS, + }, utils::Address, }; use clvm_traits::clvm_quote; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ - 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, + assets_xch_and_cat, assets_xch_only, get_last_onchain_timestamp, hex_string_to_bytes32, + load_xchandles_premine_csv, no_assets, parse_amount, sync_xchandles, wait_for_coin, + yes_no_prompt, CliError, Db, SageClient, XchandlesPremineRecord, }; fn precommit_value_for_handle( @@ -33,14 +37,17 @@ fn precommit_value_for_handle( Ok(XchandlesPrecommitValue::for_normal_registration( payment_asset_id.tree_hash(), - XchandlesFactorPricingPuzzleArgs::curry_tree_hash(1, registration_period), - XchandlesPricingSolution { + XchandlesFactorPricingPuzzleArgs { + base_price: 1, + registration_period, + } + .curry_tree_hash(), + &XchandlesPricingSolution { buy_time: start_time, current_expiration: 0, handle: handle.handle.clone(), num_periods: 1, - } - .tree_hash(), + }, handle.handle.clone(), Bytes32::default(), owner_nft_launcher_id, @@ -241,7 +248,7 @@ pub async fn xchandles_continue_launch( &offer, payment_asset_id, launcher_id, - vec![(cat_destination_puzzle_hash, handles_payment_total)], + &[(cat_destination_puzzle_hash, handles_payment_total)], )?; let created_cat = created_cats[0]; diff --git a/src/cli/xchandles/expire.rs b/src/cli/xchandles/expire.rs index c5774b64..00571baf 100644 --- a/src/cli/xchandles/expire.rs +++ b/src/cli/xchandles/expire.rs @@ -5,19 +5,26 @@ use chia::{ use chia_puzzle_types::{cat::CatArgs, singleton::SingletonStruct, LineageProof}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, CatLayer, DriverError, Layer, Offer, Puzzle, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, CatLayer, DriverError, Layer, + Offer, PrecommitCoin, PrecommitLayer, Puzzle, Slot, SpendContext, XchandlesExpireAction, + XchandlesExpirePricingPuzzle, XchandlesPrecommitValue, XchandlesRefundAction, + }, + types::{ + puzzles::{ + DefaultCatMakerArgs, XchandlesFactorPricingPuzzleArgs, XchandlesPricingSolution, + XchandlesSlotValue, + }, + Mod, + }, utils::Address, }; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ - 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, - XchandlesFactorPricingPuzzleArgs, XchandlesPrecommitValue, XchandlesPricingSolution, - XchandlesRefundAction, XchandlesSlotValue, + assets_xch_only, get_coinset_client, get_constants, get_last_onchain_timestamp, get_prefix, + hex_string_to_bytes32, no_assets, parse_amount, quick_sync_xchandles, sync_xchandles, + wait_for_coin, yes_no_prompt, CliError, Db, SageClient, XchandlesApiClient, }; #[allow(clippy::too_many_arguments)] @@ -60,13 +67,12 @@ pub async fn xchandles_expire( }; println!("done."); - if DefaultCatMakerArgs::curry_tree_hash(payment_asset_id.tree_hash().into()) + if DefaultCatMakerArgs::new(payment_asset_id.tree_hash().into()).curry_tree_hash() != registry.info.state.cat_maker_puzzle_hash.into() || registry.info.state.expired_handle_pricing_puzzle_hash - != XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( + != XchandlesExpirePricingPuzzle::curry_tree_hash( payment_cat_base_price, registration_period, - 1000, ) .into() { @@ -98,18 +104,18 @@ pub async fn xchandles_expire( }; println!("Using expire time: {}", expire_time); - let pricing_puzzle = XchandlesExponentialPremiumRenewPuzzleArgs::from_scale_factor( + let pricing_puzzle = XchandlesExpirePricingPuzzle::from_info( &mut ctx, payment_cat_base_price, registration_period, - 1000, )?; println!("Original slot expiration: {}", slot.info.value.expiration); let mut payment_cat_amount = if refund && slot.info.value.expiration > expire_time { 0 } else { - pricing_puzzle.clone().get_price( + XchandlesExpirePricingPuzzle::get_price( &mut ctx, + pricing_puzzle.clone(), handle.clone(), slot.info.value.expiration, expire_time, @@ -153,12 +159,8 @@ pub async fn xchandles_expire( }; let precommit_coin_value = XchandlesPrecommitValue::for_normal_registration( payment_asset_id.tree_hash(), - XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( - payment_cat_base_price, - registration_period, - 1000, - ), - pricing_solution.tree_hash(), + XchandlesExpirePricingPuzzle::curry_tree_hash(payment_cat_base_price, registration_period), + &pricing_solution, handle.clone(), secret, nft_launcher_id, @@ -298,20 +300,19 @@ pub async fn xchandles_expire( create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; let sec_conds = if refund { + let factor_puzzle_hash = XchandlesFactorPricingPuzzleArgs { + base_price: payment_cat_base_price, + registration_period, + } + .curry_tree_hash(); let slot: Option> = - if DefaultCatMakerArgs::curry_tree_hash(payment_asset_id.tree_hash().into()) + if DefaultCatMakerArgs::new(payment_asset_id.tree_hash().into()).curry_tree_hash() == registry.info.state.cat_maker_puzzle_hash.into() - && registry.info.state.pricing_puzzle_hash - == XchandlesFactorPricingPuzzleArgs::curry_tree_hash( - payment_cat_base_price, - registration_period, - ) - .into() + && registry.info.state.pricing_puzzle_hash == factor_puzzle_hash.into() && registry.info.state.expired_handle_pricing_puzzle_hash - == XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( + == XchandlesExpirePricingPuzzle::curry_tree_hash( payment_cat_base_price, registration_period, - 1000, ) .into() { @@ -320,14 +321,14 @@ pub async fn xchandles_expire( None }; - let precommitted_pricing_puzzle = pricing_puzzle.get_puzzle(&mut ctx)?; + let precommitted_pricing_puzzle = ctx.curry(pricing_puzzle)?; let precommitted_pricing_solution = ctx.alloc(&pricing_solution)?; registry .new_action::() .spend( &mut ctx, &mut registry, - precommit_coin, + &precommit_coin, precommitted_pricing_puzzle, precommitted_pricing_solution, slot, diff --git a/src/cli/xchandles/extend.rs b/src/cli/xchandles/extend.rs index c480016f..f575661c 100644 --- a/src/cli/xchandles/extend.rs +++ b/src/cli/xchandles/extend.rs @@ -1,15 +1,20 @@ use chia::{clvm_utils::ToTreeHash, protocol::SpendBundle}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Offer, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, spend_settlement_cats, Offer, + SpendContext, XchandlesExpirePricingPuzzle, XchandlesExtendAction, + }, + types::{ + puzzles::{DefaultCatMakerArgs, XchandlesFactorPricingPuzzleArgs}, + Mod, + }, }; use crate::{ - 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, + assets_xch_and_cat, get_coinset_client, get_constants, get_last_onchain_timestamp, + hex_string_to_bytes32, no_assets, parse_amount, quick_sync_xchandles, sync_xchandles, + wait_for_coin, yes_no_prompt, CliError, Db, SageClient, XchandlesApiClient, }; #[allow(clippy::too_many_arguments)] @@ -42,10 +47,10 @@ pub async fn xchandles_extend( }; println!("done."); - if DefaultCatMakerArgs::curry_tree_hash(payment_asset_id.tree_hash().into()) + if DefaultCatMakerArgs::new(payment_asset_id.tree_hash().into()).curry_tree_hash() != registry.info.state.cat_maker_puzzle_hash.into() || registry.info.state.pricing_puzzle_hash - != XchandlesFactorPricingPuzzleArgs::curry_tree_hash( + != XchandlesExpirePricingPuzzle::curry_tree_hash( payment_cat_base_price, registration_period, ) @@ -122,7 +127,7 @@ pub async fn xchandles_extend( &offer, payment_asset_id, notarized_payment.nonce, - vec![( + &[( notarized_payment.payments[0].puzzle_hash, notarized_payment.payments[0].amount, )], diff --git a/src/cli/xchandles/initiate_launch.rs b/src/cli/xchandles/initiate_launch.rs index 133b43bb..7daf1688 100644 --- a/src/cli/xchandles/initiate_launch.rs +++ b/src/cli/xchandles/initiate_launch.rs @@ -4,10 +4,8 @@ use crate::{ utils::{yes_no_prompt, CliError}, Db, }, - get_coinset_client, get_prefix, launch_xchandles_registry, load_xchandles_premine_csv, - load_xchandles_state_schedule_csv, no_assets, parse_amount, print_medieval_vault_configuration, - wait_for_coin, MedievalVaultHint, MedievalVaultInfo, SageClient, StateSchedulerInfo, - XchandlesConstants, XchandlesFactorPricingPuzzleArgs, XchandlesRegistryState, + get_coinset_client, get_prefix, load_xchandles_premine_csv, load_xchandles_state_schedule_csv, + no_assets, parse_amount, print_medieval_vault_configuration, wait_for_coin, SageClient, }; use chia::{ bls::PublicKey, @@ -17,8 +15,15 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Cat, DriverError, Launcher, Offer, SpendContext}, - types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, + driver::{ + decode_offer, launch_xchandles_registry, Cat, DriverError, Launcher, MedievalVaultHint, + MedievalVaultInfo, Offer, SingletonInfo, SpendContext, StateSchedulerInfo, + XchandlesConstants, XchandlesRegistryState, + }, + types::{ + puzzles::XchandlesFactorPricingPuzzleArgs, Conditions, MAINNET_CONSTANTS, + TESTNET11_CONSTANTS, + }, utils::Address, }; use clvmr::NodePtr; diff --git a/src/cli/xchandles/listen.rs b/src/cli/xchandles/listen.rs index c299784c..48fad808 100644 --- a/src/cli/xchandles/listen.rs +++ b/src/cli/xchandles/listen.rs @@ -8,17 +8,15 @@ use axum::http::{HeaderValue, Method}; use axum::{http::StatusCode, routing::get, Json, Router}; use chia::protocol::Bytes32; use chia_wallet_sdk::coinset::ChiaRpcClient; -use chia_wallet_sdk::driver::SpendContext; +use chia_wallet_sdk::driver::{SpendContext, XchandlesRegistry}; +use chia_wallet_sdk::types::puzzles::XchandlesSlotValue; use clvmr::Allocator; use futures_util::StreamExt; use serde::{Deserialize, Serialize}; use tokio_tungstenite::{connect_async, tungstenite::protocol::Message}; use tower_http::cors::CorsLayer; -use crate::{ - get_coinset_client, hex_string_to_bytes32, sync_xchandles, CliError, Db, XchandlesRegistry, - XchandlesSlotValue, -}; +use crate::{get_coinset_client, hex_string_to_bytes32, sync_xchandles, CliError, Db}; #[derive(Debug, Deserialize)] struct WebSocketMessage { @@ -50,8 +48,10 @@ pub struct XchandlesNeighborsResponse { pub left_parent_parent_info: String, pub left_parent_inner_puzzle_hash: String, + pub left_parent_amount: u64, pub right_parent_parent_info: String, pub right_parent_inner_puzzle_hash: String, + pub right_parent_amount: u64, } #[derive(Clone)] @@ -155,12 +155,14 @@ async fn get_neighbors( right_owner_launcher_id: hex::encode(right.info.value.owner_launcher_id.to_bytes()), right_resolved_data: hex::encode(right.info.value.resolved_data), - left_parent_parent_info: hex::encode(left.proof.parent_parent_info.to_bytes()), + left_parent_parent_info: hex::encode(left.proof.parent_parent_coin_info.to_bytes()), left_parent_inner_puzzle_hash: hex::encode(left.proof.parent_inner_puzzle_hash.to_bytes()), - right_parent_parent_info: hex::encode(right.proof.parent_parent_info.to_bytes()), + left_parent_amount: left.proof.parent_amount, + right_parent_parent_info: hex::encode(right.proof.parent_parent_coin_info.to_bytes()), right_parent_inner_puzzle_hash: hex::encode( right.proof.parent_inner_puzzle_hash.to_bytes(), ), + right_parent_amount: right.proof.parent_amount, }; Ok(Json(response)) diff --git a/src/cli/xchandles/quick_sync.rs b/src/cli/xchandles/quick_sync.rs index 6146727f..b886e29f 100644 --- a/src/cli/xchandles/quick_sync.rs +++ b/src/cli/xchandles/quick_sync.rs @@ -1,10 +1,10 @@ use chia::protocol::{Bytes32, CoinSpend}; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::SpendContext, + driver::{SpendContext, XchandlesRegistry}, }; -use crate::{mempool_registry_maybe, CliError, Db, XchandlesRegistry}; +use crate::{mempool_registry_maybe, CliError, Db}; pub async fn quick_sync_xchandles( client: &CoinsetClient, diff --git a/src/cli/xchandles/register.rs b/src/cli/xchandles/register.rs index ddcce544..e9b1a169 100644 --- a/src/cli/xchandles/register.rs +++ b/src/cli/xchandles/register.rs @@ -5,19 +5,28 @@ use chia::{ }; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, CatLayer, DriverError, Layer, Offer, Puzzle, SpendContext}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, CatLayer, DriverError, Layer, + Offer, PrecommitCoin, PrecommitLayer, Puzzle, Slot, SpendContext, + XchandlesExpirePricingPuzzle, XchandlesPrecommitValue, XchandlesRefundAction, + XchandlesRegisterAction, + }, + test::print_spend_bundle_to_file, + types::{ + puzzles::{ + DefaultCatMakerArgs, XchandlesFactorPricingPuzzleArgs, XchandlesPricingSolution, + XchandlesSlotValue, + }, + Mod, + }, utils::Address, }; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ - 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, XchandlesPrecommitValue, XchandlesPricingSolution, - XchandlesRefundAction, XchandlesRegisterAction, XchandlesSlotValue, + assets_xch_only, get_coinset_client, get_constants, get_last_onchain_timestamp, get_prefix, + hex_string_to_bytes32, no_assets, parse_amount, quick_sync_xchandles, sync_xchandles, + wait_for_coin, yes_no_prompt, CliError, Db, SageClient, XchandlesApiClient, }; #[allow(clippy::too_many_arguments)] @@ -74,19 +83,19 @@ pub async fn xchandles_register( }; if !refund - && (DefaultCatMakerArgs::curry_tree_hash(payment_asset_id.tree_hash().into()) + && (DefaultCatMakerArgs::new(payment_asset_id.tree_hash().into()).curry_tree_hash() != registry.info.state.cat_maker_puzzle_hash.into() || registry.info.state.pricing_puzzle_hash - != XchandlesFactorPricingPuzzleArgs::curry_tree_hash( - payment_cat_base_price, + != XchandlesFactorPricingPuzzleArgs { + base_price: payment_cat_base_price, registration_period, - ) + } + .curry_tree_hash() .into() || registry.info.state.expired_handle_pricing_puzzle_hash - != XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( + != XchandlesExpirePricingPuzzle::curry_tree_hash( payment_cat_base_price, registration_period, - 1000, ) .into()) { @@ -109,11 +118,12 @@ pub async fn xchandles_register( st }; - let precommitted_pricing_puzzle = XchandlesFactorPricingPuzzleArgs::get_puzzle( + let args = XchandlesExpirePricingPuzzle::from_info( &mut ctx, payment_cat_base_price, registration_period, )?; + let precommitted_pricing_puzzle = ctx.curry(args)?; let pricing_solution = XchandlesPricingSolution { buy_time: start_time, current_expiration: 0, @@ -137,7 +147,7 @@ pub async fn xchandles_register( let precommit_value = XchandlesPrecommitValue::for_normal_registration( payment_asset_id.tree_hash(), ctx.tree_hash(precommitted_pricing_puzzle), - pricing_solution.tree_hash(), + &pricing_solution, handle.clone(), secret, nft_launcher_id, @@ -258,25 +268,22 @@ pub async fn xchandles_register( let (security_coin_sk, security_coin) = create_security_coin(&mut ctx, offer.offered_coins().xch[0])?; + let fph = XchandlesFactorPricingPuzzleArgs { + base_price: payment_cat_base_price, + registration_period, + } + .curry_tree_hash(); let sec_conds = if refund { - let slot: Option> = if DefaultCatMakerArgs::curry_tree_hash( + let slot: Option> = if DefaultCatMakerArgs::new( payment_asset_id.tree_hash().into(), - ) == registry - .info - .state - .cat_maker_puzzle_hash - .into() - && registry.info.state.pricing_puzzle_hash - == XchandlesFactorPricingPuzzleArgs::curry_tree_hash( - payment_cat_base_price, - registration_period, - ) - .into() + ) + .curry_tree_hash() + == registry.info.state.cat_maker_puzzle_hash.into() + && registry.info.state.pricing_puzzle_hash == fph.into() && registry.info.state.expired_handle_pricing_puzzle_hash - == XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( + == XchandlesExpirePricingPuzzle::curry_tree_hash( payment_cat_base_price, registration_period, - 1000, ) .into() { @@ -319,7 +326,7 @@ pub async fn xchandles_register( .spend( &mut ctx, &mut registry, - precommit_coin, + &precommit_coin, precommitted_pricing_puzzle, precommitted_pricing_solution, slot, diff --git a/src/cli/xchandles/sync.rs b/src/cli/xchandles/sync.rs index 44a29738..8dc71819 100644 --- a/src/cli/xchandles/sync.rs +++ b/src/cli/xchandles/sync.rs @@ -3,10 +3,10 @@ use std::collections::HashSet; use chia::{clvm_utils::ToTreeHash, protocol::Bytes32}; use chia_wallet_sdk::{ coinset::{ChiaRpcClient, CoinsetClient}, - driver::SpendContext, + driver::{SpendContext, XchandlesRegistry}, }; -use crate::{CliError, Db, XchandlesRegistry}; +use crate::{CliError, Db}; pub async fn sync_xchandles( client: &CoinsetClient, diff --git a/src/cli/xchandles/unroll_state_scheduler.rs b/src/cli/xchandles/unroll_state_scheduler.rs index efffa025..bf85d2c8 100644 --- a/src/cli/xchandles/unroll_state_scheduler.rs +++ b/src/cli/xchandles/unroll_state_scheduler.rs @@ -1,17 +1,20 @@ use chia::{clvm_utils::ToTreeHash, protocol::SpendBundle}; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Offer, SpendContext}, - types::{Conditions, MAINNET_CONSTANTS, TESTNET11_CONSTANTS}, + driver::{ + create_security_coin, decode_offer, spend_security_coin, DelegatedStateAction, Offer, + SpendContext, XchandlesExpirePricingPuzzle, XchandlesRegistryState, + }, + types::{ + puzzles::{DefaultCatMakerArgs, XchandlesFactorPricingPuzzleArgs}, + Conditions, Mod, MAINNET_CONSTANTS, TESTNET11_CONSTANTS, + }, }; use crate::{ - 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, - XchandlesRegistryState, + assets_xch_only, get_coinset_client, hex_string_to_bytes32, load_xchandles_state_schedule_csv, + no_assets, parse_amount, quick_sync_xchandles, sync_multisig_singleton, sync_xchandles, + wait_for_coin, yes_no_prompt, CliError, Db, MultisigSingleton, SageClient, }; pub async fn xchandles_unroll_state_scheduler( @@ -80,15 +83,15 @@ pub async fn xchandles_unroll_state_scheduler( let schedule = load_xchandles_state_schedule_csv(filename)?; let mut found = false; for record in schedule.iter() { - let cmph = DefaultCatMakerArgs::curry_tree_hash(record.asset_id.tree_hash().into()); - let pph = XchandlesFactorPricingPuzzleArgs::curry_tree_hash( - record.registration_price, - record.registration_period, - ); - let eph = XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( + let cmph = DefaultCatMakerArgs::new(record.asset_id.tree_hash().into()).curry_tree_hash(); + let pph = XchandlesFactorPricingPuzzleArgs { + base_price: record.registration_price, + registration_period: record.registration_period, + } + .curry_tree_hash(); + let eph = XchandlesExpirePricingPuzzle::curry_tree_hash( record.registration_price, record.registration_period, - 1000, ); if cmph == new_state.cat_maker_puzzle_hash.into() && pph == new_state.pricing_puzzle_hash.into() diff --git a/src/cli/xchandles/update.rs b/src/cli/xchandles/update.rs index 7532feb5..4ea40fe3 100644 --- a/src/cli/xchandles/update.rs +++ b/src/cli/xchandles/update.rs @@ -5,18 +5,21 @@ use chia::{ use chia_puzzle_types::standard::StandardArgs; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{decode_offer, Offer, Spend, SpendContext, StandardLayer}, + driver::{ + create_security_coin, decode_offer, sign_standard_transaction, spend_security_coin, + spend_settlement_nft, Offer, SingletonInfo, Spend, SpendContext, StandardLayer, + XchandlesUpdateAction, + }, + types::puzzles::XchandlesSlotValue, utils::Address, }; use clvm_traits::clvm_quote; use clvmr::NodePtr; use crate::{ - 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, + assets_xch_and_nft, get_coinset_client, get_constants, hex_string_to_bytes32, no_assets, + parse_amount, quick_sync_xchandles, sync_xchandles, wait_for_coin, yes_no_prompt, CliError, Db, + SageClient, XchandlesApiClient, }; fn encode_nft(nft_launcher_id: Bytes32) -> Result { @@ -139,7 +142,7 @@ pub async fn xchandles_update( &mut registry, slot, new_owner_launcher_id, - new_resolved_data, + &new_resolved_data, nft.info.inner_puzzle_hash().into(), )?; diff --git a/src/cli/xchandles/verify_deployment.rs b/src/cli/xchandles/verify_deployment.rs index 41170616..9b0dc773 100644 --- a/src/cli/xchandles/verify_deployment.rs +++ b/src/cli/xchandles/verify_deployment.rs @@ -1,18 +1,23 @@ use chia::clvm_utils::ToTreeHash; use chia_puzzle_types::singleton::SingletonSolution; +use chia_wallet_sdk::driver::{ + Layer, XchandlesExpirePricingPuzzle, XchandlesRegistry, XchandlesRegistryState, +}; +use chia_wallet_sdk::types::puzzles::{ + DefaultCatMakerArgs, XchandlesFactorPricingPuzzleArgs, XchandlesRegisterActionSolution, +}; +use chia_wallet_sdk::types::Mod; use chia_wallet_sdk::{ coinset::ChiaRpcClient, - driver::{Layer, SpendContext}, + driver::{ActionLayer, SpendContext}, utils::Address, }; use clvmr::{serde::node_from_bytes, NodePtr}; use crate::{ get_coinset_client, hex_string_to_bytes32, load_xchandles_premine_csv, - load_xchandles_state_schedule_csv, print_medieval_vault_configuration, ActionLayer, CliError, - DefaultCatMakerArgs, MultisigSingleton, XchandlesExponentialPremiumRenewPuzzleArgs, - XchandlesFactorPricingPuzzleArgs, XchandlesRegisterActionSolution, XchandlesRegistry, - XchandlesRegistryState, + load_xchandles_state_schedule_csv, print_medieval_vault_configuration, CliError, + MultisigSingleton, }; use crate::sync_multisig_singleton; @@ -172,22 +177,24 @@ pub async fn xchandles_verify_deployment( let mut price_schedule_ok = true; for (i, record) in price_schedule.iter().enumerate() { let (block, state) = state_scheduler_info.state_schedule[i]; + + let fph = XchandlesFactorPricingPuzzleArgs { + base_price: record.registration_price, + registration_period: record.registration_period, + } + .curry_tree_hash(); if record.block_height != block - || state.pricing_puzzle_hash - != XchandlesFactorPricingPuzzleArgs::curry_tree_hash( - record.registration_price, - record.registration_period, - ) - .into() + || state.pricing_puzzle_hash != fph.into() || state.expired_handle_pricing_puzzle_hash - != XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( + != XchandlesExpirePricingPuzzle::curry_tree_hash( record.registration_price, record.registration_period, - 1000, ) .into() || state.cat_maker_puzzle_hash - != DefaultCatMakerArgs::curry_tree_hash(record.asset_id.tree_hash().into()).into() + != DefaultCatMakerArgs::new(record.asset_id.tree_hash().into()) + .curry_tree_hash() + .into() { price_schedule_ok = false; break; diff --git a/src/cli/xchandles/view.rs b/src/cli/xchandles/view.rs index 09c2d916..e97704ca 100644 --- a/src/cli/xchandles/view.rs +++ b/src/cli/xchandles/view.rs @@ -1,10 +1,16 @@ use chia::clvm_utils::ToTreeHash; -use chia_wallet_sdk::{driver::SpendContext, utils::Address}; +use chia_wallet_sdk::{ + driver::{SpendContext, XchandlesExpirePricingPuzzle}, + types::{ + puzzles::{DefaultCatMakerArgs, XchandlesFactorPricingPuzzleArgs}, + Mod, + }, + utils::Address, +}; use crate::{ get_coinset_client, get_prefix, hex_string_to_bytes32, parse_amount, quick_sync_xchandles, - CliError, Db, DefaultCatMakerArgs, XchandlesExponentialPremiumRenewPuzzleArgs, - XchandlesFactorPricingPuzzleArgs, + CliError, Db, }; #[allow(clippy::too_many_arguments)] @@ -33,7 +39,9 @@ pub async fn xchandles_view( if let Some(payment_asset_id) = payment_asset_id_str { let payment_asset_id = hex_string_to_bytes32(&payment_asset_id)?; if registry.info.state.cat_maker_puzzle_hash - == DefaultCatMakerArgs::curry_tree_hash(payment_asset_id.tree_hash().into()).into() + == DefaultCatMakerArgs::new(payment_asset_id.tree_hash().into()) + .curry_tree_hash() + .into() { println!( " Payment asset id: {} (VERIFIED)", @@ -57,17 +65,16 @@ pub async fn xchandles_view( (payment_cat_base_price_str, registration_period) { let payment_cat_base_price = parse_amount(&payment_cat_base_price, true)?; - if registry.info.state.pricing_puzzle_hash - == XchandlesFactorPricingPuzzleArgs::curry_tree_hash( - payment_cat_base_price, - registration_period, - ) - .into() + let fph = XchandlesFactorPricingPuzzleArgs { + base_price: payment_cat_base_price, + registration_period, + } + .curry_tree_hash(); + if registry.info.state.pricing_puzzle_hash == fph.into() && registry.info.state.expired_handle_pricing_puzzle_hash - == XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( + == XchandlesExpirePricingPuzzle::curry_tree_hash( payment_cat_base_price, registration_period, - 1000, ) .into() { diff --git a/src/cli/xchandles/xchandles_api_client.rs b/src/cli/xchandles/xchandles_api_client.rs index 8d849475..2284b081 100644 --- a/src/cli/xchandles/xchandles_api_client.rs +++ b/src/cli/xchandles/xchandles_api_client.rs @@ -1,11 +1,11 @@ use chia::protocol::Bytes32; +use chia_puzzle_types::LineageProof; +use chia_wallet_sdk::driver::Slot; +use chia_wallet_sdk::types::puzzles::{SlotInfo, XchandlesSlotValue}; use reqwest::Client; use std::time::Duration; -use crate::{ - hex_string_to_bytes, hex_string_to_bytes32, CliError, Slot, SlotInfo, SlotProof, - XchandlesSlotValue, -}; +use crate::{hex_string_to_bytes, hex_string_to_bytes32, CliError}; use super::XchandlesNeighborsResponse; @@ -111,18 +111,22 @@ impl XchandlesApiClient { hex_string_to_bytes32(&neighbors_resp.left_parent_parent_info)?; let left_parent_inner_puzzle_hash = hex_string_to_bytes32(&neighbors_resp.left_parent_inner_puzzle_hash)?; - let left_proof = SlotProof { - parent_parent_info: left_parent_parent_info, + let left_parent_amount = neighbors_resp.left_parent_amount; + let left_proof = LineageProof { + parent_parent_coin_info: left_parent_parent_info, parent_inner_puzzle_hash: left_parent_inner_puzzle_hash, + parent_amount: left_parent_amount, }; let right_parent_parent_info = hex_string_to_bytes32(&neighbors_resp.right_parent_parent_info)?; let right_parent_inner_puzzle_hash = hex_string_to_bytes32(&neighbors_resp.right_parent_inner_puzzle_hash)?; - let right_proof = SlotProof { - parent_parent_info: right_parent_parent_info, + let right_parent_amount = neighbors_resp.right_parent_amount; + let right_proof = LineageProof { + parent_parent_coin_info: right_parent_parent_info, parent_inner_puzzle_hash: right_parent_inner_puzzle_hash, + parent_amount: right_parent_amount, }; let left_info = SlotInfo::::from_value(launcher_id, 0, left_value); diff --git a/src/debug.rs b/src/debug.rs deleted file mode 100644 index c88048fb..00000000 --- a/src/debug.rs +++ /dev/null @@ -1,91 +0,0 @@ -// https://raw.githubusercontent.com/Datalayer-Storage/DataLayer-Driver/1aafc1e89734ddd6d3bda98d9ff45709507469ea/src/debug.rs - -use std::{fs::File, io::Write, path::Path}; - -use chia::{ - bls::G2Element, - protocol::{Coin, CoinSpend, SpendBundle}, -}; -use hex::encode; -use serde::Serialize; - -#[derive(Serialize)] -struct SerializableCoin { - parent_coin_info: String, - puzzle_hash: String, - amount: u64, -} - -#[derive(Serialize)] -struct SerializableCoinSpend { - coin: SerializableCoin, - puzzle_reveal: String, - solution: String, -} - -#[derive(Serialize)] -struct SerializableSpendBundle { - coin_spends: Vec, - aggregated_signature: String, -} - -impl From<&Coin> for SerializableCoin { - fn from(coin: &Coin) -> Self { - SerializableCoin { - parent_coin_info: format!("0x{}", encode(coin.parent_coin_info)), - puzzle_hash: format!("0x{}", encode(coin.puzzle_hash)), - amount: coin.amount, - } - } -} - -impl From<&CoinSpend> for SerializableCoinSpend { - fn from(coin_spend: &CoinSpend) -> Self { - SerializableCoinSpend { - coin: SerializableCoin::from(&coin_spend.coin), - puzzle_reveal: format!( - "0x{}", - encode(coin_spend.puzzle_reveal.clone().into_bytes()) - ), - solution: format!("0x{}", encode(coin_spend.solution.clone().into_bytes())), - } - } -} - -impl From<&SpendBundle> for SerializableSpendBundle { - fn from(spend_bundle: &SpendBundle) -> Self { - SerializableSpendBundle { - coin_spends: spend_bundle - .coin_spends - .iter() - .map(SerializableCoinSpend::from) - .collect(), - aggregated_signature: format!( - "0x{}", - encode(spend_bundle.aggregated_signature.to_bytes()) - ), - } - } -} - -pub fn get_spend_bundle_json(spends: Vec, agg_sig: G2Element) -> String { - let spend_bundle = SpendBundle { - coin_spends: spends, - aggregated_signature: agg_sig, - }; - - let serializable_bundle = SerializableSpendBundle::from(&spend_bundle); - serde_json::to_string(&serializable_bundle).expect("Serialization failed") -} - -pub fn print_spend_bundle(spends: Vec, agg_sig: G2Element) { - println!("{}", get_spend_bundle_json(spends, agg_sig)); -} - -pub fn print_spend_bundle_to_file(spends: Vec, agg_sig: G2Element, file_path: &str) { - let json_string = get_spend_bundle_json(spends, agg_sig); - let path = Path::new(file_path); - let mut file = File::create(path).expect("Unable to create file"); - file.write_all(json_string.as_bytes()) - .expect("Unable to write data"); -} diff --git a/src/drivers.rs b/src/drivers.rs deleted file mode 100644 index 060001dd..00000000 --- a/src/drivers.rs +++ /dev/null @@ -1,3556 +0,0 @@ -use bip39::Mnemonic; -use chia::{ - bls::{sign, SecretKey, Signature}, - clvm_utils::ToTreeHash, - consensus::consensus_constants::ConsensusConstants, - protocol::{Bytes32, Coin, CoinSpend}, - puzzles::{ - offer::{NotarizedPayment, Payment}, - singleton::{SingletonArgs, SingletonSolution, SingletonStruct}, - standard::StandardSolution, - EveProof, LineageProof, Proof, - }, -}; -use chia_puzzle_types::{offer::SettlementPaymentsSolution, standard::StandardArgs, Memos}; -use chia_wallet_sdk::{ - driver::{ - Cat, CatSpend, DriverError, HashedPtr, Launcher, Layer, Nft, Offer, Spend, SpendContext, - StandardLayer, - }, - prelude::{AggSig, AggSigKind}, - signer::{AggSigConstants, RequiredBlsSignature}, - types::{announcement_id, puzzles::SettlementPayment, Condition, Conditions}, -}; -use clvm_traits::{clvm_list, clvm_quote, clvm_tuple, FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; - -use crate::{ - CatalogRegistry, CatalogRegistryConstants, CatalogRegistryInfo, CatalogRegistryState, - CatalogSlotValue, DefaultCatMakerArgs, P2DelegatedBySingletonLayerArgs, Reserve, - RewardDistributor, RewardDistributorConstants, RewardDistributorInfo, - RewardDistributorRewardSlotValue, RewardDistributorSlotNonce, RewardDistributorState, Slot, - SlotInfo, SlotProof, XchandlesConstants, XchandlesRegistry, XchandlesRegistryInfo, - XchandlesRegistryState, XchandlesSlotValue, -}; - -pub struct SecuredOneSidedOffer { - pub coin_spends: Vec, - pub aggregated_signature: Signature, - pub security_coin: Coin, - pub security_base_conditions: Conditions, - pub created_cat: Option, - pub created_nft: Option>, -} - -fn custom_err(e: T) -> DriverError -where - T: ToString, -{ - DriverError::Custom(e.to_string()) -} - -pub fn new_sk() -> Result { - // we need the security coin puzzle hash to spend the offer coin after finding it - let mut entropy = [0u8; 32]; - getrandom::fill(&mut entropy).map_err(custom_err)?; - let mnemonic = Mnemonic::from_entropy(&entropy).map_err(custom_err)?; - let seed = mnemonic.to_seed(""); - let sk = SecretKey::from_seed(&seed); - Ok(sk) -} - -pub fn spend_security_coin( - ctx: &mut SpendContext, - security_coin: Coin, - conditions: Conditions, - sk: &SecretKey, - consensus_constants: &ConsensusConstants, -) -> Result { - let pk = sk.public_key(); - - let layer = StandardLayer::new(pk); - let puzzle_reveal_ptr = layer.construct_puzzle(ctx)?; - - let quoted_conditions_ptr = ctx.alloc(&clvm_quote!(conditions))?; - let solution_ptr = layer.construct_solution( - ctx, - StandardSolution { - original_public_key: None, - delegated_puzzle: quoted_conditions_ptr, - solution: NodePtr::NIL, - }, - )?; - - let spend = Spend::new(puzzle_reveal_ptr, solution_ptr); - ctx.spend(security_coin, spend)?; - - sign_standard_transaction(ctx, security_coin, spend, sk, consensus_constants) -} - -pub fn sign_standard_transaction( - ctx: &mut SpendContext, - coin: Coin, - spend: Spend, - sk: &SecretKey, - consensus_constants: &ConsensusConstants, -) -> Result { - let output = ctx.run(spend.puzzle, spend.solution)?; - let output = Vec::>::from_clvm(ctx, output)?; - let Some(agg_sig_me) = output.iter().find_map(|cond| { - if let Condition::AggSigMe(agg_sig_me) = cond { - return Some(agg_sig_me); - } - - None - }) else { - return Err(DriverError::Custom( - "Missing agg_sig_me from security coin".to_string(), - )); - }; - - let required_signature = RequiredBlsSignature::from_condition( - &coin, - AggSig::new( - AggSigKind::Me, - agg_sig_me.public_key, - agg_sig_me.message.clone(), - ), - &AggSigConstants::new(consensus_constants.agg_sig_me_additional_data), - ); - - Ok(sign(sk, required_signature.message())) -} - -pub fn eve_singleton_inner_puzzle( - ctx: &mut SpendContext, - launcher_id: Bytes32, - left_slot_value: S, - right_slot_value: S, - memos_after_hint: NodePtr, - target_inner_puzzle_hash: Bytes32, -) -> Result -where - S: ToTreeHash, -{ - let left_slot_info = SlotInfo::from_value(launcher_id, 0, left_slot_value); - let left_slot_puzzle_hash = Slot::::puzzle_hash(&left_slot_info); - - let right_slot_info = SlotInfo::from_value(launcher_id, 0, right_slot_value); - let right_slot_puzzle_hash = Slot::::puzzle_hash(&right_slot_info); - - let slot_hint: Bytes32 = Slot::<()>::first_curry_hash(launcher_id, 0).into(); - let slot_memos = ctx.hint(slot_hint)?; - let launcher_id_ptr = ctx.alloc(&launcher_id)?; - 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, 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) -} - -// Spends the eve signleton, whose only job is to create the -// slot 'premine' (leftmost and rightmost slots) and -// transition to the actual registry puzzle -#[allow(clippy::type_complexity)] -fn spend_eve_coin_and_create_registry( - ctx: &mut SpendContext, - launcher: Launcher, - target_inner_puzzle_hash: Bytes32, - left_slot_value: S, - right_slot_value: S, - memos_after_hint: M, - launcher_kv_list: KV, -) -> Result<(Conditions, Coin, Proof, [Slot; 2]), DriverError> -where - S: Clone + ToTreeHash, - M: ToClvm, - KV: ToClvm, -{ - let launcher_coin = launcher.coin(); - let launcher_id = launcher_coin.coin_id(); - - let memos_after_hint = ctx.alloc(&memos_after_hint)?; - let eve_singleton_inner_puzzle = eve_singleton_inner_puzzle( - ctx, - launcher_id, - left_slot_value.clone(), - right_slot_value.clone(), - memos_after_hint, - target_inner_puzzle_hash, - )?; - - let eve_singleton_inner_puzzle_hash = ctx.tree_hash(eve_singleton_inner_puzzle); - let eve_singleton_proof = Proof::Eve(EveProof { - parent_parent_coin_info: launcher_coin.parent_coin_info, - parent_amount: launcher_coin.amount, - }); - - let (security_coin_conditions, eve_coin) = launcher.with_singleton_amount(1).spend( - ctx, - eve_singleton_inner_puzzle_hash.into(), - launcher_kv_list, - )?; - - let eve_coin_solution = SingletonSolution { - lineage_proof: eve_singleton_proof, - amount: 1, - inner_solution: NodePtr::NIL, - } - .to_clvm(ctx)?; - - let eve_singleton_puzzle = - ctx.curry(SingletonArgs::new(launcher_id, eve_singleton_inner_puzzle))?; - let eve_singleton_spend = Spend::new(eve_singleton_puzzle, eve_coin_solution); - ctx.spend(eve_coin, eve_singleton_spend)?; - - let new_registry_coin = Coin::new( - eve_coin.coin_id(), - SingletonArgs::curry_tree_hash(launcher_id, target_inner_puzzle_hash.into()).into(), - 1, - ); - let new_proof = Proof::Lineage(LineageProof { - parent_parent_coin_info: eve_coin.parent_coin_info, - parent_inner_puzzle_hash: eve_singleton_inner_puzzle_hash.into(), - parent_amount: 1, - }); - - let slot_proof = SlotProof { - parent_parent_info: eve_coin.parent_coin_info, - parent_inner_puzzle_hash: eve_singleton_inner_puzzle_hash.into(), - }; - let left_slot = Slot::new( - slot_proof, - SlotInfo::from_value(launcher_id, 0, left_slot_value), - ); - let right_slot = Slot::new( - slot_proof, - SlotInfo::from_value(launcher_id, 0, right_slot_value), - ); - - Ok(( - security_coin_conditions.assert_concurrent_spend(eve_coin.coin_id()), - new_registry_coin, - new_proof, - [left_slot, right_slot], - )) -} - -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, - initial_registration_price: u64, - // (registry launcher id, security coin, additional_args) -> (additional conditions, registry constants, initial_registration_asset_id) - get_additional_info: fn( - ctx: &mut SpendContext, - Bytes32, - Coin, - V, - ) -> Result< - (Conditions, CatalogRegistryConstants, Bytes32), - DriverError, - >, - consensus_constants: &ConsensusConstants, - additional_args: V, -) -> Result< - ( - Signature, - SecretKey, - CatalogRegistry, - [Slot; 2], - Coin, // security coin - ), - DriverError, -> { - 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 = security_coin.coin_id(); - let mut security_coin_conditions = Conditions::new(); - - // Create CATalog registry launcher - let registry_launcher = Launcher::new(security_coin_id, 1); - let registry_launcher_coin = registry_launcher.coin(); - 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, security_coin, additional_args)?; - - let initial_state = CatalogRegistryState { - registration_price: initial_registration_price, - cat_maker_puzzle_hash: DefaultCatMakerArgs::curry_tree_hash( - initial_registration_asset_id.tree_hash().into(), - ) - .into(), - }; - let catalog_registry_info = CatalogRegistryInfo::new( - initial_state, - catalog_constants.with_launcher_id(registry_launcher_id), - ); - let catalog_inner_puzzle_hash = catalog_registry_info.clone().inner_puzzle_hash(); - - let (new_security_coin_conditions, new_catalog_registry_coin, catalog_proof, slots) = - spend_eve_coin_and_create_registry( - ctx, - registry_launcher, - catalog_inner_puzzle_hash.into(), - CatalogSlotValue::initial_left_end(), - CatalogSlotValue::initial_right_end(), - clvm_tuple!( - initial_registration_asset_id, - clvm_tuple!(initial_state, ()) - ), - (), - )?; - - let catalog_registry = CatalogRegistry::new( - new_catalog_registry_coin, - catalog_proof, - catalog_registry_info, - ); - - // this creates the CATalog registry & secures the spend - security_coin_conditions = security_coin_conditions - .extend(new_security_coin_conditions) - .extend(additional_security_coin_conditions); - - // Spend security coin - let security_coin_sig = spend_security_coin( - ctx, - security_coin, - security_coin_conditions, - &security_coin_sk, - consensus_constants, - )?; - - // Finally, return the data - Ok(( - security_coin_sig + &offer.spend_bundle().aggregated_signature, - security_coin_sk, - catalog_registry, - slots, - security_coin, - )) -} - -#[allow(clippy::too_many_arguments)] -#[allow(clippy::type_complexity)] -pub fn launch_xchandles_registry( - ctx: &mut SpendContext, - 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) - get_additional_info: fn( - ctx: &mut SpendContext, - Bytes32, - Coin, - V, - ) -> Result< - (Conditions, XchandlesConstants, Bytes32), - DriverError, - >, - consensus_constants: &ConsensusConstants, - additional_args: V, -) -> Result< - ( - Signature, - SecretKey, - XchandlesRegistry, - [Slot; 2], - Coin, // security coin - ), - DriverError, -> { - 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 = security_coin.coin_id(); - - let mut security_coin_conditions = Conditions::new(); - - // Create registry coin launcher - let registry_launcher = Launcher::new(security_coin_id, 1); - let registry_launcher_coin = registry_launcher.coin(); - 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, security_coin, additional_args)?; - - // Spend intermediary coin and create registry - let initial_state = XchandlesRegistryState::from( - initial_registration_asset_id.tree_hash().into(), - initial_base_registration_price, - initial_registration_period, - ); - let target_xchandles_info = XchandlesRegistryInfo::new( - initial_state, - xchandles_constants.with_launcher_id(registry_launcher_id), - ); - - let target_xchandles_inner_puzzle_hash = target_xchandles_info.clone().inner_puzzle_hash(); - let (new_security_coin_conditions, new_xchandles_coin, xchandles_proof, slots) = - spend_eve_coin_and_create_registry( - ctx, - registry_launcher, - target_xchandles_inner_puzzle_hash.into(), - XchandlesSlotValue::initial_left_end(), - XchandlesSlotValue::initial_right_end(), - (), - clvm_list!( - initial_registration_asset_id, - initial_base_registration_price, - initial_registration_period, - initial_state, - target_xchandles_info.constants - ), - )?; - - // this creates the launcher & secures the spend - security_coin_conditions = security_coin_conditions - .extend(new_security_coin_conditions) - .extend(additional_security_coin_conditions); - - let xchandles_registry = - XchandlesRegistry::new(new_xchandles_coin, xchandles_proof, target_xchandles_info); - - // Spend security coin - let security_coin_sig = spend_security_coin( - ctx, - security_coin, - security_coin_conditions, - &security_coin_sk, - consensus_constants, - )?; - - // Finally, return the data - Ok(( - security_coin_sig + &offer.spend_bundle().aggregated_signature, - security_coin_sk, - xchandles_registry, - slots, - 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, - first_epoch_start: u64, - cat_refund_puzzle_hash: Bytes32, - constants: RewardDistributorConstants, - consensus_constants: &ConsensusConstants, - comment: &str, -) -> Result< - ( - Signature, - SecretKey, - RewardDistributor, - Slot, - Cat, - ), - DriverError, -> { - 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 = 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(); - - let controller_singleton_struct_hash: Bytes32 = - SingletonStruct::new(launcher_id).tree_hash().into(); - let reserve_inner_ph: Bytes32 = - P2DelegatedBySingletonLayerArgs::curry_tree_hash(controller_singleton_struct_hash, 0) - .into(); - - 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, - constants.reserve_asset_id, - constants.launcher_id, - vec![(interim_cat_puzzle_hash.into(), total_cat_amount)], - )?; - - 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( - RewardDistributorState::initial(first_epoch_start), - constants.with_launcher_id(launcher_id), - ); - - let target_inner_puzzle_hash = target_info.clone().inner_puzzle_hash(); - - let slot_value = RewardDistributorRewardSlotValue { - epoch_start: first_epoch_start, - next_epoch_initialized: false, - rewards: 0, - }; - let slot_info = SlotInfo::::from_value( - launcher_id, - RewardDistributorSlotNonce::REWARD.to_u64(), - slot_value, - ); - let slot_puzzle_hash = Slot::::puzzle_hash(&slot_info); - - 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, 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); - let eve_singleton_proof = Proof::Eve(EveProof { - parent_parent_coin_info: launcher_coin.parent_coin_info, - parent_amount: launcher_coin.amount, - }); - - let (launch_conditions, eve_coin) = launcher.with_singleton_amount(1).spend( - ctx, - eve_singleton_inner_puzzle_hash.into(), - (first_epoch_start, target_info.constants), - )?; - security_coin_conditions = security_coin_conditions.extend(launch_conditions); - - let eve_coin_solution = SingletonSolution { - lineage_proof: eve_singleton_proof, - amount: 1, - inner_solution: NodePtr::NIL, - } - .to_clvm(ctx)?; - - let eve_singleton_puzzle = - ctx.curry(SingletonArgs::new(launcher_id, eve_singleton_inner_puzzle))?; - let eve_singleton_spend = Spend::new(eve_singleton_puzzle, eve_coin_solution); - ctx.spend(eve_coin, eve_singleton_spend)?; - - let new_registry_coin = Coin::new( - eve_coin.coin_id(), - SingletonArgs::curry_tree_hash(launcher_id, target_inner_puzzle_hash).into(), - 1, - ); - let new_proof = Proof::Lineage(LineageProof { - parent_parent_coin_info: eve_coin.parent_coin_info, - parent_inner_puzzle_hash: eve_singleton_inner_puzzle_hash.into(), - parent_amount: 1, - }); - - let slot_proof = SlotProof { - parent_parent_info: eve_coin.parent_coin_info, - parent_inner_puzzle_hash: eve_singleton_inner_puzzle_hash.into(), - }; - let slot = Slot::new(slot_proof, slot_info); - - // this creates the launcher & secures the spend - let security_coin_conditions = - security_coin_conditions.assert_concurrent_spend(eve_coin.coin_id()); - - // create reserve and registry - let reserve_cat = created_cats[0]; - let reserve = Reserve::new( - reserve_cat.coin.parent_coin_info, - reserve_cat.lineage_proof.unwrap(), - reserve_cat.info.asset_id, - controller_singleton_struct_hash, - 0, - reserve_cat.coin.amount, - ); - let registry = RewardDistributor::new(new_registry_coin, new_proof, target_info, reserve); - - // Spend security coin - let security_coin_sig = spend_security_coin( - ctx, - security_coin, - security_coin_conditions, - &security_coin_sk, - consensus_constants, - )?; - - // Finally, return the data - Ok(( - security_coin_sig + &offer.spend_bundle().aggregated_signature, - security_coin_sk, - registry, - slot, - created_cats[1], // refund cat - )) -} - -#[cfg(test)] -mod tests { - use chia::{ - protocol::{Bytes, SpendBundle}, - puzzles::{ - cat::GenesisByCoinIdTailArgs, - singleton::{SingletonSolution, SingletonStruct}, - CoinProof, - }, - }; - use chia_puzzles::{SETTLEMENT_PAYMENT_HASH, SINGLETON_LAUNCHER_HASH}; - use chia_wallet_sdk::{ - driver::{Nft, NftMint, SingleCatSpend, SpendWithConditions}, - test::Simulator, - types::TESTNET11_CONSTANTS, - }; - use clvm_traits::clvm_list; - use clvmr::Allocator; - use hex_literal::hex; - - use crate::{ - benchmarker::tests::Benchmark, CatNftMetadata, CatalogPrecommitValue, CatalogRefundAction, - CatalogRegisterAction, CatalogSlotValue, DelegatedStateAction, - DelegatedStateActionSolution, IntermediaryCoinProof, NftLauncherProof, PrecommitCoin, - RewardDistributorAddEntryAction, RewardDistributorAddIncentivesAction, - RewardDistributorCommitIncentivesAction, RewardDistributorInitiatePayoutAction, - RewardDistributorNewEpochAction, RewardDistributorRemoveEntryAction, - RewardDistributorStakeAction, RewardDistributorSyncAction, RewardDistributorType, - RewardDistributorUnstakeAction, RewardDistributorWithdrawIncentivesAction, Slot, - SpendContextExt, XchandlesExpireAction, XchandlesExponentialPremiumRenewPuzzleArgs, - XchandlesExtendAction, XchandlesFactorPricingPuzzleArgs, XchandlesOracleAction, - XchandlesPrecommitValue, XchandlesPricingSolution, XchandlesRefundAction, - XchandlesRegisterAction, XchandlesUpdateAction, ANY_METADATA_UPDATER_HASH, - }; - - use super::*; - - fn cat_nft_metadata_for_testing() -> CatNftMetadata { - CatNftMetadata { - ticker: "TDBX".to_string(), - name: "Testnet dexie bucks".to_string(), - description: " Testnet version of dexie bucks".to_string(), - precision: 4, - image_uris: vec!["https://icons-testnet.dexie.space/d82dd03f8a9ad2f84353cd953c4de6b21dbaaf7de3ba3f4ddd9abe31ecba80ad.webp".to_string()], - image_hash: Bytes32::from( - hex!("c84607c0e4cb4a878cc34ba913c90504ed0aac0f4484c2078529b9e42387da99") - ), - metadata_uris: vec!["https://icons-testnet.dexie.space/test.json".to_string()], - metadata_hash: Some(Bytes32::from([2; 32])), - license_uris: vec!["https://icons-testnet.dexie.space/license.pdf".to_string()], - license_hash: Some(Bytes32::from([3; 32])), - } - } - - // ensures conditions are met - fn ensure_conditions_met( - ctx: &mut SpendContext, - sim: &mut Simulator, - conditions: Conditions, - amount_to_mint: u64, - ) -> Result<(), DriverError> { - let checker_puzzle_ptr = clvm_quote!(conditions).to_clvm(ctx)?; - let checker_coin = sim.new_coin(ctx.tree_hash(checker_puzzle_ptr).into(), amount_to_mint); - ctx.spend(checker_coin, Spend::new(checker_puzzle_ptr, NodePtr::NIL))?; - - Ok(()) - } - - // Launches a test singleton with an innter puzzle of '1' - // JUST FOR TESTING PURPOSES PLEASE DO NOT USE THIS THING IN PRODUCTION - fn launch_test_singleton( - ctx: &mut SpendContext, - sim: &mut Simulator, - ) -> Result<(Bytes32, Coin, Proof, NodePtr, Bytes32, NodePtr), DriverError> { - let test_singleton_launcher_coin = sim.new_coin(SINGLETON_LAUNCHER_HASH.into(), 1); - let test_singleton_launcher = - Launcher::new(test_singleton_launcher_coin.parent_coin_info, 1); - - let test_singleton_launcher_id = test_singleton_launcher.coin().coin_id(); - - let test_singleton_inner_puzzle = ctx.alloc(&1)?; - let test_singleton_inner_puzzle_hash = ctx.tree_hash(test_singleton_inner_puzzle); - let (_, test_singleton_coin) = - test_singleton_launcher.spend(ctx, test_singleton_inner_puzzle_hash.into(), ())?; - - let test_singleton_puzzle = ctx.curry(SingletonArgs::new( - test_singleton_launcher_id, - test_singleton_inner_puzzle, - ))?; - let test_singleton_proof: Proof = Proof::Eve(EveProof { - parent_parent_coin_info: test_singleton_launcher_coin.parent_coin_info, - parent_amount: test_singleton_launcher_coin.amount, - }); - - Ok(( - test_singleton_launcher_id, - test_singleton_coin, - test_singleton_proof, - test_singleton_inner_puzzle, - test_singleton_inner_puzzle_hash.into(), - test_singleton_puzzle, - )) - } - - // Spends the price singleton to update the price of a registry - fn spend_price_singleton( - ctx: &mut SpendContext, - price_singleton_coin: Coin, - price_singleton_proof: Proof, - price_singleton_puzzle: NodePtr, - new_state: S, - receiver_puzzle_hash: Bytes32, - ) -> Result<(Coin, Proof, DelegatedStateActionSolution), DriverError> - where - S: ToTreeHash + ToClvm, - { - let price_singleton_inner_puzzle = ctx.alloc(&1)?; - let price_singleton_inner_puzzle_hash = ctx.tree_hash(price_singleton_inner_puzzle); - - 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, Memos::None); - - let price_singleton_inner_solution = price_singleton_inner_solution.to_clvm(ctx)?; - let price_singleton_solution = SingletonSolution { - lineage_proof: price_singleton_proof, - amount: 1, - inner_solution: price_singleton_inner_solution, - } - .to_clvm(ctx)?; - - let price_singleton_spend = Spend::new(price_singleton_puzzle, price_singleton_solution); - ctx.spend(price_singleton_coin, price_singleton_spend)?; - - // compute price singleton info for next spend - let next_price_singleton_proof = Proof::Lineage(LineageProof { - parent_parent_coin_info: price_singleton_coin.parent_coin_info, - parent_inner_puzzle_hash: price_singleton_inner_puzzle_hash.into(), - parent_amount: price_singleton_coin.amount, - }); - let next_price_singleton_coin = Coin::new( - price_singleton_coin.coin_id(), - price_singleton_coin.puzzle_hash, - 1, - ); - - Ok(( - next_price_singleton_coin, - next_price_singleton_proof, - DelegatedStateActionSolution { - new_state: new_state.to_clvm(ctx)?, - other_singleton_inner_puzzle_hash: price_singleton_inner_puzzle_hash.into(), - }, - )) - } - - #[allow(clippy::too_many_arguments)] - fn test_refund_for_catalog( - ctx: &mut SpendContext, - sim: &mut Simulator, - benchmark: &mut Benchmark, - benchmark_label: &str, - reg_amount: u64, - payment_cat: Cat, - tail_puzzle_to_refund: Option, - catalog: CatalogRegistry, - catalog_constants: &CatalogRegistryConstants, - slots: &[Slot], - user_puzzle_hash: Bytes32, - minter_p2: StandardLayer, - minter_puzzle_hash: Bytes32, - sks: &[SecretKey; 2], - ) -> anyhow::Result<(CatalogRegistry, Cat)> { - // create precommit coin - let user_coin = sim.new_coin(user_puzzle_hash, reg_amount); - // pretty much a random TAIL - we're not actually launching it - let tail = if let Some(t) = tail_puzzle_to_refund { - t - } else { - ctx.curry(GenesisByCoinIdTailArgs::new(user_coin.coin_id()))? - }; - let tail_hash = ctx.tree_hash(tail); - // doesn't matter - we're getting refudned anyway - let eve_nft_inner_puzzle_hash = tail_hash; - - let value = CatalogPrecommitValue::with_default_cat_maker( - payment_cat.info.asset_id.tree_hash(), - eve_nft_inner_puzzle_hash.into(), - tail, - ); - - let refund_puzzle = ctx.alloc(&1)?; - let refund_puzzle_hash = ctx.tree_hash(refund_puzzle); - let precommit_coin = PrecommitCoin::new( - ctx, - payment_cat.coin.coin_id(), - payment_cat.child_lineage_proof(), - payment_cat.info.asset_id, - SingletonStruct::new(catalog.info.constants.launcher_id) - .tree_hash() - .into(), - catalog_constants.relative_block_height, - catalog_constants.precommit_payout_puzzle_hash, - refund_puzzle_hash.into(), - value, - reg_amount, - )?; - - let payment_cat_inner_spend = minter_p2.spend_with_conditions( - ctx, - Conditions::new() - .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, Memos::None) - .create_coin( - minter_puzzle_hash, - payment_cat.coin.amount - reg_amount, - Memos::None, - ), - )?; - Cat::spend_all( - ctx, - &[CatSpend { - cat: payment_cat, - spend: payment_cat_inner_spend, - hidden: false, - }], - )?; - - let new_payment_cat = - 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)?; - - let slot = slots - .iter() - .find(|s| s.info.value.asset_id == tail_hash.into()); - - let mut catalog = catalog; - let secure_cond = catalog.new_action::().spend( - ctx, - &mut catalog, - tail_hash.into(), - slot.map(|s| s.info.value.neighbors), - precommit_coin, - slot.cloned(), - )?; - - // 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)?; - - // sim.spend_coins(ctx.take(), sks)?; - benchmark.add_spends(ctx, sim, benchmark_label, sks)?; - - Ok((new_catalog, new_payment_cat)) - } - - #[test] - fn test_catalog() -> anyhow::Result<()> { - let ctx = &mut SpendContext::new(); - let mut sim = Simulator::new(); - let mut benchmark = Benchmark::new("CATalog".to_string()); - - // setup config - - let initial_registration_price = 2000; - let test_price_schedule = [1000, 500, 250]; - - let catalog_constants = CatalogRegistryConstants { - launcher_id: Bytes32::from([1; 32]), - royalty_address: Bytes32::from([7; 32]), - royalty_basis_points: 100, - precommit_payout_puzzle_hash: Bytes32::from([8; 32]), - relative_block_height: 1, - price_singleton_launcher_id: Bytes32::from(hex!( - "0000000000000000000000000000000000000000000000000000000000000000" - )), - }; - - // Create source offer - let user_bls = sim.bls(0); - - let offer_amount = 1; - let launcher_bls = sim.bls(offer_amount); - - 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, - Memos::None, - ), - )?; - - let puzzle_reveal = ctx.serialize(&offer_spend.puzzle)?; - let solution = ctx.serialize(&offer_spend.solution)?; - 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, - mut price_singleton_coin, - mut price_singleton_proof, - _price_singleton_inner_puzzle, - _price_singleton_inner_puzzle_hash, - price_singleton_puzzle, - ) = launch_test_singleton(ctx, &mut sim)?; - - // Launch test 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, 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, Memos::None), - )?; - let mut payment_cat = payment_cat[0]; - minter_p2.spend(ctx, minter_bls.coin, issue_cat)?; - - sim.spend_coins(ctx.take(), &[minter_bls.sk.clone()])?; - - // Launch catalog - let (_, security_sk, mut catalog, slots, _security_coin) = launch_catalog_registry( - ctx, - &offer, - initial_registration_price, - |_ctx, _launcher_id, _coin, (catalog_constants, initial_registration_asset_id)| { - Ok(( - Conditions::new(), - catalog_constants, - initial_registration_asset_id, - )) - }, - &TESTNET11_CONSTANTS, - ( - catalog_constants.with_price_singleton(price_singleton_launcher_id), - payment_cat.info.asset_id, - ), - )?; - - // sim.spend_coins(ctx.take(), &[launcher_bls.sk, security_sk])?; - benchmark.add_spends(ctx, &mut sim, "launch", &[launcher_bls.sk, security_sk])?; - - // Register CAT - - let mut tail: NodePtr = NodePtr::NIL; // will be used for refund as well - let mut slots: Vec> = slots.into(); - for i in 0..7 { - // create precommit coin - let reg_amount = if i % 2 == 1 { - test_price_schedule[i / 2] - } else { - catalog.info.state.registration_price - }; - let user_coin = sim.new_coin(user_bls.puzzle_hash, reg_amount); - // pretty much a random TAIL - we're not actually launching it - tail = ctx.curry(GenesisByCoinIdTailArgs::new(user_coin.coin_id()))?; - let tail_hash = ctx.tree_hash(tail); - - let eve_nft_inner_puzzle = clvm_quote!(Conditions::new().create_coin( - Bytes32::new([4 + i as u8; 32]), - 1, - 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.info.asset_id.tree_hash(), - eve_nft_inner_puzzle_hash.into(), - tail, - ); - - let refund_puzzle = ctx.alloc(&1)?; - let refund_puzzle_hash = ctx.tree_hash(refund_puzzle); - let precommit_coin = PrecommitCoin::new( - ctx, - payment_cat.coin.coin_id(), - payment_cat.child_lineage_proof(), - payment_cat.info.asset_id, - SingletonStruct::new(catalog.info.constants.launcher_id) - .tree_hash() - .into(), - catalog_constants.relative_block_height, - catalog_constants.precommit_payout_puzzle_hash, - refund_puzzle_hash.into(), - value, - reg_amount, - )?; - - let payment_cat_inner_spend = minter_p2.spend_with_conditions( - ctx, - Conditions::new() - .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, Memos::None) - .create_coin( - minter_bls.puzzle_hash, - payment_cat_amount - reg_amount, - Memos::None, - ), - )?; - let new_cats = Cat::spend_all( - ctx, - &[CatSpend { - cat: payment_cat, - spend: payment_cat_inner_spend, - hidden: false, - }], - )?; - - payment_cat_amount -= reg_amount; - payment_cat = new_cats[1]; - - // sim.spend_coins(ctx.take(), &[user_bls.sk.clone(), minter_bls.sk.clone()])?; - benchmark.add_spends( - ctx, - &mut sim, - "create_precommit", - &[user_bls.sk.clone(), minter_bls.sk.clone()], - )?; - - // call the 'register' action on CATalog - slots.sort_unstable_by(|a, b| a.info.value.cmp(&b.info.value)); - - let slot_value_to_insert = - CatalogSlotValue::new(tail_hash.into(), Bytes32::default(), Bytes32::default()); - - let mut left_slot: Option> = None; - let mut right_slot: Option> = None; - for slot in slots.iter() { - let slot_value = slot.info.value; - - if slot_value < slot_value_to_insert { - // slot belongs to the left - if let Some(left_slot_ref) = &left_slot { - if slot_value > left_slot_ref.info.value { - left_slot = Some(slot.clone()); - } - } else { - left_slot = Some(slot.clone()); - } - } else { - // slot belongs to the right - if let Some(right_slot_ref) = &right_slot { - if slot_value < right_slot_ref.info.value { - right_slot = Some(slot.clone()); - } - } else { - right_slot = Some(slot.clone()); - } - } - } - - let (left_slot, right_slot) = (left_slot.unwrap(), right_slot.unwrap()); - - if i % 2 == 1 { - let new_price = reg_amount; - assert_ne!(new_price, catalog.info.state.registration_price); - - let new_state = CatalogRegistryState { - cat_maker_puzzle_hash: DefaultCatMakerArgs::curry_tree_hash( - payment_cat.info.asset_id.tree_hash().into(), - ) - .into(), - registration_price: new_price, - }; - - let ( - new_price_singleton_coin, - new_price_singleton_proof, - delegated_state_action_solution, - ) = spend_price_singleton( - ctx, - price_singleton_coin, - price_singleton_proof, - price_singleton_puzzle, - new_state, - catalog.coin.puzzle_hash, - )?; - - price_singleton_coin = new_price_singleton_coin; - price_singleton_proof = new_price_singleton_proof; - - let (_conds, action_spend) = catalog.new_action::().spend( - ctx, - catalog.coin, - new_state, - delegated_state_action_solution.other_singleton_inner_puzzle_hash, - )?; - - 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 = catalog.new_action::().spend( - ctx, - &mut catalog, - tail_hash.into(), - left_slot.clone(), - right_slot.clone(), - precommit_coin, - Spend { - puzzle: eve_nft_inner_puzzle, - solution: NodePtr::NIL, - }, - )?; - - // 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)?; - - // sim.spend_coins(ctx.take(), &[user_bls.sk.clone()])?; - benchmark.add_spends(ctx, &mut sim, "register", &[user_bls.sk.clone()])?; - - slots.retain(|s| { - s.info.value_hash != left_slot.info.value_hash - && s.info.value_hash != right_slot.info.value_hash - }); - 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!( - catalog.info.state.registration_price, - test_price_schedule[2], // 1, 3, 5 updated the price - ); - - // Test refunds - - // b - the amount is wrong (by one) - let (catalog, payment_cat) = test_refund_for_catalog( - ctx, - &mut sim, - &mut benchmark, - "refund_amount_wrong", - catalog.info.state.registration_price + 1, - payment_cat, - None, - catalog, - &catalog_constants, - &slots, - user_bls.puzzle_hash, - minter_p2, - minter_bls.puzzle_hash, - &[user_bls.sk.clone(), minter_bls.sk.clone()], - )?; - - // a - the CAT maker puzzle has changed - // i.e., use different payment CAT - let alternative_payment_cat_amount = 10_000_000; - let minter2_bls = sim.bls(alternative_payment_cat_amount); - let minter_p2_2 = StandardLayer::new(minter2_bls.pk); - - 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, - Memos::None, - ), - )?; - minter_p2_2.spend(ctx, minter2_bls.coin, issue_cat)?; - let alternative_payment_cat = alternative_payment_cat[0]; - - sim.spend_coins(ctx.take(), &[minter2_bls.sk.clone()])?; - - let (catalog, _alternative_payment_cat) = test_refund_for_catalog( - ctx, - &mut sim, - &mut benchmark, - "refund_cat_changed", - catalog.info.state.registration_price, - alternative_payment_cat, - None, - catalog, - &catalog_constants, - &slots, - user_bls.puzzle_hash, - minter_p2_2, - minter2_bls.puzzle_hash, - &[user_bls.sk.clone(), minter2_bls.sk.clone()], - )?; - - // c - the tail hash has already been registered - let (_catalog, _payment_cat) = test_refund_for_catalog( - ctx, - &mut sim, - &mut benchmark, - "refund_cat_already_registered", - catalog.info.state.registration_price, - payment_cat, - Some(tail), - catalog, - &catalog_constants, - &slots, - user_bls.puzzle_hash, - minter_p2, - minter_bls.puzzle_hash, - &[user_bls.sk.clone(), minter_bls.sk.clone()], - )?; - - benchmark.print_summary(Some("catalog.costs")); - Ok(()) - } - - #[allow(clippy::too_many_arguments)] - fn test_refund_for_xchandles( - ctx: &mut SpendContext, - sim: &mut Simulator, - benchmark: &mut Benchmark, - benchmark_label: &str, - handle_to_refund: String, - pricing_puzzle: NodePtr, - pricing_solution: NodePtr, - slot: Option>, - payment_cat: Cat, - payment_cat_amount: u64, - registry: XchandlesRegistry, - minter_p2: StandardLayer, - minter_puzzle_hash: Bytes32, - minter_sk: &SecretKey, - user_sk: &SecretKey, - ) -> anyhow::Result<(XchandlesRegistry, Cat)> { - let pricing_puzzle_hash = ctx.tree_hash(pricing_puzzle); - let pricing_solution_hash = ctx.tree_hash(pricing_solution); - - let value = XchandlesPrecommitValue::for_normal_registration( - payment_cat.info.asset_id.tree_hash(), - pricing_puzzle_hash, - pricing_solution_hash, - handle_to_refund.clone(), - Bytes32::default(), - Bytes32::default(), - Bytes::default(), - ); - - let refund_puzzle = ctx.alloc(&1)?; - let refund_puzzle_hash = ctx.tree_hash(refund_puzzle); - let precommit_coin = PrecommitCoin::new( - ctx, - payment_cat.coin.coin_id(), - payment_cat.child_lineage_proof(), - payment_cat.info.asset_id, - SingletonStruct::new(registry.info.constants.launcher_id) - .tree_hash() - .into(), - registry.info.constants.relative_block_height, - registry.info.constants.precommit_payout_puzzle_hash, - refund_puzzle_hash.into(), - value, - payment_cat_amount, - )?; - - let payment_cat_inner_spend = minter_p2.spend_with_conditions( - ctx, - Conditions::new() - .create_coin( - precommit_coin.inner_puzzle_hash, - payment_cat_amount, - Memos::None, - ) - .create_coin( - minter_puzzle_hash, - payment_cat.coin.amount - payment_cat_amount, - Memos::None, - ), - )?; - Cat::spend_all( - ctx, - &[CatSpend { - cat: payment_cat, - spend: payment_cat_inner_spend, - hidden: false, - }], - )?; - - let new_payment_cat = payment_cat.child( - minter_puzzle_hash, - payment_cat.coin.amount - payment_cat_amount, - ); - - // sim.spend_coins(ctx.take(), &[user_sk.clone(), minter_sk.clone()])?; - benchmark.add_spends( - ctx, - sim, - "create_precommit", - &[user_sk.clone(), minter_sk.clone()], - )?; - - let mut registry = registry; - let used_slot_value_hash = slot.clone().map(|s| s.info.value_hash); - let secure_cond = registry.new_action::().spend( - ctx, - &mut registry, - precommit_coin, - pricing_puzzle, - pricing_solution, - slot, - )?; - 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)?; - - ensure_conditions_met(ctx, sim, secure_cond.clone(), 0)?; - - // sim.spend_coins(ctx.take(), &[user_sk.clone()])?; - benchmark.add_spends(ctx, sim, benchmark_label, &[user_sk.clone()])?; - - Ok((new_registry, new_payment_cat)) - } - - #[test] - fn test_xchandles() -> anyhow::Result<()> { - let ctx = &mut SpendContext::new(); - let mut sim = Simulator::new(); - let mut benchmark = Benchmark::new("XCHandles".to_string()); - // setup config - let initial_registration_price = 2000; - let test_price_schedule = [1000, 500, 250]; - - let xchandles_constants = XchandlesConstants { - launcher_id: Bytes32::from([1; 32]), - precommit_payout_puzzle_hash: Bytes32::from([8; 32]), - relative_block_height: 1, - price_singleton_launcher_id: Bytes32::from(hex!( - "0000000000000000000000000000000000000000000000000000000000000000" - )), - }; - - // Create source offer - let user_bls = sim.bls(0); - let user_p2 = StandardLayer::new(user_bls.pk); - - let offer_amount = 1; - 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, - Memos::None, - ), - )?; - - let puzzle_reveal = ctx.serialize(&offer_spend.puzzle)?; - let solution = ctx.serialize(&offer_spend.solution)?; - 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, 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, Memos::None), - )?; - let mut payment_cat = payment_cat[0]; - minter_p2.spend(ctx, minter_bls.coin, issue_cat)?; - - sim.spend_coins(ctx.take(), &[minter_bls.sk.clone()])?; - - // Launch price singleton - let ( - price_singleton_launcher_id, - mut price_singleton_coin, - mut price_singleton_proof, - _price_singleton_inner_puzzle, - _price_singleton_inner_puzzle_hash, - price_singleton_puzzle, - ) = launch_test_singleton(ctx, &mut sim)?; - - // Launch XCHandles - let reg_period = 366 * 24 * 60 * 60; - let (_, security_sk, mut registry, slots_returned_by_launch, _security_coin) = - launch_xchandles_registry( - ctx, - &offer, - initial_registration_price, - reg_period, - |_ctx, _launcher_id, _coin, (xchandles_constants, payment_cat_asset_id)| { - Ok((Conditions::new(), xchandles_constants, payment_cat_asset_id)) - }, - &TESTNET11_CONSTANTS, - ( - xchandles_constants.with_price_singleton(price_singleton_launcher_id), - payment_cat.info.asset_id, - ), - )?; - - // Check XCHandlesRegistry::from_launcher_solution - let spends = ctx.take(); - let mut initial_slots = None; - for spend in spends { - if spend.coin.puzzle_hash == SINGLETON_LAUNCHER_HASH.into() { - let launcher_solution = ctx.alloc(&spend.solution)?; - - if let Some((registry, slots, initial_registration_asset_id, initial_base_price)) = - XchandlesRegistry::from_launcher_solution(ctx, spend.coin, launcher_solution)? - { - initial_slots = Some(slots); - assert_eq!(initial_registration_asset_id, payment_cat.info.asset_id); - assert_eq!( - registry.info.constants, - xchandles_constants - .with_price_singleton(price_singleton_launcher_id) - .with_launcher_id(spend.coin.coin_id()) - ); - assert_eq!(initial_registration_price, initial_base_price); - }; - } - - ctx.insert(spend); - } - - // This will fail if we didn't find (or were not able to parse) the XCHandles launcher - assert!(initial_slots.is_some()); - - // sim.spend_coins(ctx.take(), &[launcher_bls.sk, security_sk])?; - benchmark.add_spends(ctx, &mut sim, "launch", &[launcher_bls.sk, security_sk])?; - - let slots = initial_slots.unwrap(); - assert!(sim.coin_state(slots[0].coin.coin_id()).is_some()); - assert!(sim.coin_state(slots[1].coin.coin_id()).is_some()); - assert_eq!(slots, slots_returned_by_launch); - - // Register 7 handles - - let mut base_price = initial_registration_price; - - let mut slots: Vec> = slots.into(); - for i in 0..7 { - // mint controller singleton (it's a DID, not an NFT - don't rat on me to the NFT board plz) - let launcher_coin = sim.new_coin(SINGLETON_LAUNCHER_HASH.into(), 1); - let launcher = Launcher::new(launcher_coin.parent_coin_info, 1); - let (_, did) = launcher.create_simple_did(ctx, &user_p2)?; - - // name is "aa" + "a" * i + "{i}" - let handle = if i == 0 { - "aa0".to_string() - } else { - "aa".to_string() + &"a".repeat(i).to_string() + &i.to_string() - }; - let handle_hash: Bytes32 = handle.tree_hash().into(); - - // create precommit coin - if i % 2 == 1 { - base_price = test_price_schedule[i / 2]; - }; - let reg_amount = XchandlesFactorPricingPuzzleArgs::get_price(base_price, &handle, 1); - - let handle_owner_launcher_id = did.info.launcher_id; - let handle_resolved_data: Bytes = Bytes32::from([u8::MAX - i as u8; 32]).into(); - let secret = Bytes32::default(); - - let value = XchandlesPrecommitValue::for_normal_registration( - payment_cat.info.asset_id.tree_hash(), - XchandlesFactorPricingPuzzleArgs::curry_tree_hash(base_price, reg_period), - XchandlesPricingSolution { - buy_time: 100, - current_expiration: 0, - handle: handle.clone(), - num_periods: 1, - } - .tree_hash(), - handle.clone(), - secret, - handle_owner_launcher_id, - handle_resolved_data, - ); - - let refund_puzzle = ctx.alloc(&1)?; - let refund_puzzle_hash = ctx.tree_hash(refund_puzzle); - let precommit_coin = PrecommitCoin::new( - ctx, - payment_cat.coin.coin_id(), - payment_cat.child_lineage_proof(), - payment_cat.info.asset_id, - SingletonStruct::new(registry.info.constants.launcher_id) - .tree_hash() - .into(), - xchandles_constants.relative_block_height, - xchandles_constants.precommit_payout_puzzle_hash, - refund_puzzle_hash.into(), - value, - reg_amount, - )?; - - let payment_cat_inner_spend = minter_p2.spend_with_conditions( - ctx, - Conditions::new() - .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, Memos::None) - .create_coin( - minter_bls.puzzle_hash, - payment_cat_amount - reg_amount, - Memos::None, - ), - )?; - Cat::spend_all( - ctx, - &[CatSpend { - cat: payment_cat, - spend: payment_cat_inner_spend, - hidden: false, - }], - )?; - - payment_cat_amount -= reg_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( - ctx, - &mut sim, - "create_precommit", - &[user_bls.sk.clone(), minter_bls.sk.clone()], - )?; - - // call the 'register' action on the registry - slots.sort_unstable_by(|a, b| a.info.value.cmp(&b.info.value)); - - let slot_value_to_insert = XchandlesSlotValue::new( - handle_hash, - Bytes32::default(), - Bytes32::default(), - 0, - Bytes32::default(), - Bytes::default(), - ); - - let mut left_slot: Option> = None; - let mut right_slot: Option> = None; - for slot in slots.iter() { - let slot_value = slot.info.value.clone(); - - if slot_value < slot_value_to_insert { - // slot belongs to the left - if let Some(left_slot_ref) = &left_slot { - if slot_value > left_slot_ref.info.value { - left_slot = Some(slot.clone()); - } - } else { - left_slot = Some(slot.clone()); - } - } else { - // slot belongs to the right - if let Some(right_slot_ref) = &right_slot { - if slot_value < right_slot_ref.info.value { - right_slot = Some(slot.clone()); - } - } else { - right_slot = Some(slot.clone()); - } - } - } - - let (left_slot, right_slot) = (left_slot.unwrap(), right_slot.unwrap()); - - // update price - if i % 2 == 1 { - let new_price = test_price_schedule[i / 2]; - let new_price_puzzle_hash: Bytes32 = - XchandlesFactorPricingPuzzleArgs::curry_tree_hash(new_price, reg_period).into(); - assert_ne!( - new_price_puzzle_hash, - registry.info.state.pricing_puzzle_hash - ); - - let ( - new_price_singleton_coin, - new_price_singleton_proof, - delegated_state_action_solution, - ) = spend_price_singleton( - ctx, - price_singleton_coin, - price_singleton_proof, - price_singleton_puzzle, - XchandlesRegistryState::from( - payment_cat.info.asset_id.tree_hash().into(), - new_price, - reg_period, - ), - registry.coin.puzzle_hash, - )?; - - price_singleton_coin = new_price_singleton_coin; - price_singleton_proof = new_price_singleton_proof; - - let (_conds, action_spend) = registry.new_action::().spend( - ctx, - registry.coin, - delegated_state_action_solution.new_state, - delegated_state_action_solution.other_singleton_inner_puzzle_hash, - )?; - - 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 = registry.new_action::().spend( - ctx, - &mut registry, - left_slot.clone(), - right_slot.clone(), - precommit_coin, - base_price, - reg_period, - 100, - )?; - - ensure_conditions_met(ctx, &mut sim, secure_cond.clone(), 1)?; - - assert_eq!( - registry - .pending_spend - .spent_slots - .iter() - .rev() - .take(2) - .collect::>(), - spent_values.iter().rev().collect::>(), - ); - 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()])?; - benchmark.add_spends(ctx, &mut sim, "register", &[user_bls.sk.clone()])?; - - slots.retain(|s| { - s.info.value_hash != left_slot.info.value_hash - && s.info.value_hash != right_slot.info.value_hash - }); - - let oracle_slot = new_slots[1].clone(); - slots.extend(new_slots); - - // test on-chain oracle for current handle - let spent_slot_value_hash = oracle_slot.info.value_hash; - 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, - registry - .pending_spend - .spent_slots - .iter() - .next_back() - .unwrap() - .tree_hash() - .into() - ); - 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()])?; - - slots.retain(|s| s.info.value_hash != oracle_slot.info.value_hash); - slots.push(new_slot.clone()); - - // test on-chain extend mechanism for current handle - let extension_years: u64 = i as u64 + 1; - let extension_slot = new_slot; - let pay_for_extension: u64 = - XchandlesFactorPricingPuzzleArgs::get_price(base_price, &handle, extension_years); - - let spent_slot_value_hash = extension_slot.info.value_hash; - let (extend_conds, notarized_payment) = - registry.new_action::().spend( - ctx, - &mut registry, - handle, - extension_slot.clone(), - 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, - 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, - Memos::None, - ) - .create_coin( - minter_bls.puzzle_hash, - payment_cat_amount - pay_for_extension, - Memos::None, - ), - )?; - - let cat_offer_inner_spend = Spend::new( - ctx.alloc_mod::()?, - ctx.alloc(&clvm_list!(notarized_payment))?, - ); - - Cat::spend_all( - ctx, - &[ - CatSpend { - cat: payment_cat, - spend: payment_cat_inner_spend, - hidden: false, - }, - CatSpend { - 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.child(minter_bls.puzzle_hash, payment_cat_amount); - - registry = registry.finish_spend(ctx)?.0; - - // sim.spend_coins(spends, &[user_bls.sk.clone(), minter_bls.sk.clone()])?; - benchmark.add_spends( - ctx, - &mut sim, - "extend", - &[user_bls.sk.clone(), minter_bls.sk.clone()], - )?; - - slots.retain(|s| s.info.value_hash != extension_slot.info.value_hash); - slots.push(new_slot.clone()); - - // test on-chain mechanism for handle updates - let new_owner_launcher_id = Bytes32::new([4 + i as u8; 32]); - let new_resolved_data: Bytes = Bytes32::new([u8::MAX - i as u8 - 1; 32]).into(); - let update_slot = new_slot; - let update_slot_value_hash = update_slot.info.value_hash; - - let update_conds = registry.new_action::().spend( - ctx, - &mut registry, - update_slot.clone(), - new_owner_launcher_id, - 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, - registry - .pending_spend - .spent_slots - .iter() - .next_back() - .unwrap() - .tree_hash() - .into() - ); - 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()])?; - - slots.retain(|s| s.info.value_hash != update_slot.info.value_hash); - slots.push(new_slot.clone()); - } - - assert_eq!( - registry.info.state.pricing_puzzle_hash, - // iterations 1, 3, 5 updated the price - XchandlesFactorPricingPuzzleArgs::curry_tree_hash(test_price_schedule[2], reg_period) - .into(), - ); - - // expire one of the slots - let handle_to_expire = "aa0".to_string(); - let handle_hash: Bytes32 = handle_to_expire.tree_hash().into(); - let initial_slot = slots - .iter() - .find(|s| s.info.value.handle_hash == handle_hash) - .unwrap(); - - // precommit coin needed - let refund_puzzle = ctx.alloc(&1)?; - let refund_puzzle_hash = ctx.tree_hash(refund_puzzle); - 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.info.asset_id.tree_hash(), - XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( - base_price, reg_period, 1000, - ), - XchandlesPricingSolution { - buy_time, - current_expiration: expiration, - handle: handle_to_expire.clone(), - num_periods: 1, - } - .tree_hash(), - handle_to_expire.clone(), - Bytes32::default(), - Bytes32::from([42; 32]), - Bytes32::from([69; 32]).into(), - ); - - let pricing_puzzle = XchandlesExponentialPremiumRenewPuzzleArgs::from_scale_factor( - ctx, base_price, reg_period, 1000, - )?; - let reg_amount = - pricing_puzzle.get_price(ctx, handle_to_expire, expiration, buy_time, 1)? as u64; - - let precommit_coin = PrecommitCoin::::new( - ctx, - payment_cat.coin.coin_id(), - payment_cat.child_lineage_proof(), - payment_cat.info.asset_id, - SingletonStruct::new(registry.info.constants.launcher_id) - .tree_hash() - .into(), - xchandles_constants.relative_block_height, - xchandles_constants.precommit_payout_puzzle_hash, - refund_puzzle_hash.into(), - value, - reg_amount, - )?; - assert!(reg_amount <= payment_cat_amount); - - let payment_cat_inner_spend = minter_p2.spend_with_conditions( - ctx, - Conditions::new() - .create_coin(precommit_coin.inner_puzzle_hash, reg_amount, Memos::None) - .create_coin( - minter_bls.puzzle_hash, - payment_cat_amount - reg_amount, - Memos::None, - ), - )?; - Cat::spend_all( - ctx, - &[CatSpend { - cat: payment_cat, - spend: payment_cat_inner_spend, - hidden: false, - }], - )?; - - payment_cat = - 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()])?; - benchmark.add_spends( - ctx, - &mut sim, - "create_precommit", - &[user_bls.sk.clone(), minter_bls.sk.clone()], - )?; - - let spent_slot_value_hash = initial_slot.info.value_hash; - let expire_conds = registry.new_action::().spend( - ctx, - &mut registry, - initial_slot.clone(), - 1, - base_price, - reg_period, - precommit_coin, - buy_time, - )?; - - // assert expire conds - ensure_conditions_met(ctx, &mut sim, expire_conds, 1)?; - - assert_eq!( - spent_slot_value_hash, - registry - .pending_spend - .spent_slots - .iter() - .next_back() - .unwrap() - .tree_hash() - .into() - ); - 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()])?; - - // Test refunds - let unregistered_handle = "yak7".to_string(); - - for use_factor_pricing in [true, false] { - let pricing_puzzle = if use_factor_pricing { - XchandlesFactorPricingPuzzleArgs::get_puzzle(ctx, base_price, reg_period)? - } else { - XchandlesExponentialPremiumRenewPuzzleArgs::from_scale_factor( - ctx, base_price, reg_period, 1000, - )? - .get_puzzle(ctx)? - }; - 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); - let other_pricing_puzzle = if use_factor_pricing { - XchandlesFactorPricingPuzzleArgs::get_puzzle(ctx, base_price + 1, reg_period)? - } else { - XchandlesExponentialPremiumRenewPuzzleArgs::from_scale_factor( - ctx, - base_price + 1, - reg_period, - 1000, - )? - .get_puzzle(ctx)? - }; - let other_expected_price = XchandlesFactorPricingPuzzleArgs::get_price( - base_price + 1, - &unregistered_handle, - 1, - ); - assert_ne!(other_expected_price, expected_price); - - let existing_handle = if use_factor_pricing { - "aaa1".to_string() - } else { - "aaaa2".to_string() - }; - let existing_slot = slots - .iter() - .find(|s| s.info.value.handle_hash == existing_handle.tree_hash().into()) - .unwrap() - .clone(); - 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); - - // a - the CAT maker puzzle has changed - let alternative_payment_cat_amount = 10_000_000; - let minter2 = sim.bls(alternative_payment_cat_amount); - let minter_p2_2 = StandardLayer::new(minter2.pk); - - 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, - Memos::None, - ), - )?; - minter_p2_2.spend(ctx, minter2.coin, issue_cat)?; - - let alternative_payment_cat = alternative_payment_cat[0]; - sim.spend_coins(ctx.take(), &[minter2.sk.clone()])?; - - registry = test_refund_for_xchandles( - ctx, - &mut sim, - &mut benchmark, - "refund_cat_wrong", - unregistered_handle.clone(), - pricing_puzzle, - pricing_solution, - None, - alternative_payment_cat, - expected_price, - registry, - minter_p2_2, - minter2.puzzle_hash, - &minter2.sk, - &user_bls.sk, - )? - .0; - - // b - the amount is wrong - (registry, payment_cat) = test_refund_for_xchandles( - ctx, - &mut sim, - &mut benchmark, - "refund_amount_wrong", - unregistered_handle.clone(), - pricing_puzzle, - pricing_solution, - None, - payment_cat, - expected_price + 1, - registry, - minter_p2, - minter_bls.puzzle_hash, - &minter_bls.sk, - &user_bls.sk, - )?; - - // c - the pricing puzzle has changed - (registry, payment_cat) = test_refund_for_xchandles( - ctx, - &mut sim, - &mut benchmark, - "refund_pricing_wrong", - unregistered_handle.clone(), - other_pricing_puzzle, - pricing_solution, - None, - payment_cat, - other_expected_price, - registry, - minter_p2, - minter_bls.puzzle_hash, - &minter_bls.sk, - &user_bls.sk, - )?; - - // d - the handle has already been registered - (registry, payment_cat) = test_refund_for_xchandles( - ctx, - &mut sim, - &mut benchmark, - "refund_handle_already_registered", - existing_handle.clone(), // already registered handle - pricing_puzzle, - existing_handle_pricing_solution, - Some(existing_slot), - payment_cat, - existing_handle_expected_price, - registry, - minter_p2, - minter_bls.puzzle_hash, - &minter_bls.sk, - &user_bls.sk, - )?; - } - - benchmark.print_summary(Some("xchandles.costs")); - - Ok(()) - } - - #[test] - fn test_nft_with_any_metadata_updater() -> anyhow::Result<()> { - let ctx = &mut SpendContext::new(); - let mut sim = Simulator::new(); - - let bls = sim.bls(1); - let p2 = StandardLayer::new(bls.pk); - - let nft_launcher = Launcher::new(bls.coin.coin_id(), 1); - - let royalty_puzzle_hash = Bytes32::from([7; 32]); - let (create_nft, nft) = nft_launcher.mint_nft( - ctx, - NftMint:: { - metadata: cat_nft_metadata_for_testing(), - metadata_updater_puzzle_hash: ANY_METADATA_UPDATER_HASH.into(), - royalty_puzzle_hash, - royalty_basis_points: 100, - p2_puzzle_hash: bls.puzzle_hash, - transfer_condition: None, - }, - )?; - p2.spend(ctx, bls.coin, create_nft)?; - - // actually try to run updater - let new_metadata = CatNftMetadata { - ticker: "XXX".to_string(), - name: "Test Name".to_string(), - description: "Test desc".to_string(), - precision: 4, - image_uris: vec!["img URI".to_string()], - image_hash: Bytes32::from([31; 32]), - metadata_uris: vec!["meta URI".to_string()], - metadata_hash: Some(Bytes32::from([8; 32])), - license_uris: vec!["license URI".to_string()], - license_hash: Some(Bytes32::from([9; 32])), - }; - - let metadata_update = Spend { - puzzle: ctx.any_metadata_updater()?, - solution: ctx.alloc(&new_metadata)?, - }; - - let new_nft: Nft = nft.transfer_with_metadata( - ctx, - &p2, - bls.puzzle_hash, - metadata_update, - Conditions::new(), - )?; - - assert_eq!(new_nft.info.metadata, new_metadata); - sim.spend_coins(ctx.take(), &[bls.sk])?; - Ok(()) - } - - // Spends the manager singleton - fn spend_manager_singleton( - ctx: &mut SpendContext, - test_singleton_coin: Coin, - test_singleton_proof: Proof, - test_singleton_puzzle: NodePtr, - test_singleton_output_conditions: Conditions, - ) -> Result<(Coin, Proof), DriverError> { - let test_singleton_inner_puzzle = ctx.alloc(&1)?; - 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, Memos::None) - .to_clvm(ctx)?; - let test_singleton_solution = ctx.alloc(&SingletonSolution { - lineage_proof: test_singleton_proof, - amount: 1, - inner_solution: test_singleton_inner_solution, - })?; - - let test_singleton_spend = Spend::new(test_singleton_puzzle, test_singleton_solution); - ctx.spend(test_singleton_coin, test_singleton_spend)?; - - // compute manager singleton info for next spend - let next_test_singleton_proof = Proof::Lineage(LineageProof { - parent_parent_coin_info: test_singleton_coin.parent_coin_info, - parent_inner_puzzle_hash: test_singleton_inner_puzzle_hash.into(), - parent_amount: test_singleton_coin.amount, - }); - let next_test_singleton_coin = Coin::new( - test_singleton_coin.coin_id(), - test_singleton_coin.puzzle_hash, - 1, - ); - - Ok((next_test_singleton_coin, next_test_singleton_proof)) - } - - #[test] - fn test_managed_reward_distributor() -> anyhow::Result<()> { - test_reward_distributor(RewardDistributorType::Manager) - } - - #[test] - fn test_nft_reward_distributor() -> anyhow::Result<()> { - test_reward_distributor(RewardDistributorType::Nft) - } - - fn test_reward_distributor(manager_type: RewardDistributorType) -> anyhow::Result<()> { - let ctx = &mut SpendContext::new(); - let mut sim = Simulator::new(); - let mut benchmark = Benchmark::new(format!( - "Reward Distributor ({})", - match manager_type { - RewardDistributorType::Manager => "Manager", - RewardDistributorType::Nft => "NFT", - } - )); - - // Launch token CAT - let cat_amount = 10_000_000_000; - let cat_minter = sim.bls(cat_amount); - let cat_minter_p2 = StandardLayer::new(cat_minter.pk); - - 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, Memos::None), - )?; - cat_minter_p2.spend(ctx, cat_minter.coin, issue_cat)?; - - let source_cat = source_cat[0]; - sim.spend_coins(ctx.take(), &[cat_minter.sk.clone()])?; - - // Launch manager singleton - let ( - manager_or_did_launcher_id, - mut manager_or_did_coin, - mut manager_or_did_singleton_proof, - _manager_or_didsingleton_inner_puzzle, - manager_or_did_singleton_inner_puzzle_hash, - manager_or_did_singleton_puzzle, - ) = launch_test_singleton(ctx, &mut sim)?; - - // setup config - let constants = RewardDistributorConstants::without_launcher_id( - manager_type, - manager_or_did_launcher_id, - Bytes32::new([1; 32]), - 1000, - 300, - 42, - 420, // 4.2% fee - 9000, // 90% of the amount deposited will be returned - source_cat.info.asset_id, - ); - - // Create source offer - let entry1_bls = sim.bls(0); - let entry2_bls = sim.bls(0); - - let offer_amount = 1; - 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, - Memos::None, - ), - )?; - - let puzzle_reveal = ctx.serialize(&offer_spend.puzzle)?; - let solution = ctx.serialize(&offer_spend.solution)?; - - let cat_minter_inner_puzzle = clvm_quote!(Conditions::new().create_coin( - SETTLEMENT_PAYMENT_HASH.into(), - source_cat.coin.amount, - Memos::None - )) - .to_clvm(ctx)?; - let source_cat_inner_spend = cat_minter_p2.delegated_inner_spend( - ctx, - Spend { - puzzle: cat_minter_inner_puzzle, - solution: NodePtr::NIL, - }, - )?; - source_cat.spend( - ctx, - SingleCatSpend { - prev_coin_id: source_cat.coin.coin_id(), - next_coin_proof: CoinProof { - parent_coin_info: source_cat.coin.parent_coin_info, - inner_puzzle_hash: cat_minter.puzzle_hash, - amount: source_cat.coin.amount, - }, - prev_subtotal: 0, - extra_delta: 0, - p2_spend: source_cat_inner_spend, - revoke: false, - }, - )?; - let spends = ctx.take(); - let cat_offer_spend = spends - .iter() - .find(|s| s.coin.coin_id() == source_cat.coin.coin_id()) - .unwrap() - .clone(); - for spend in spends { - if spend.coin.coin_id() != source_cat.coin.coin_id() { - ctx.insert(spend); - } - } - - 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), - 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(), - // &[ - // launcher_bls.sk.clone(), - // security_sk.clone(), - // cat_minter.sk.clone(), - // ], - // )?; - benchmark.add_spends( - ctx, - &mut sim, - "launch", - &[ - launcher_bls.sk.clone(), - security_sk.clone(), - cat_minter.sk.clone(), - ], - )?; - - 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 = registry - .new_action::() - .spend( - ctx, - &mut registry, - entry1_bls.puzzle_hash, - 1, - manager_or_did_singleton_inner_puzzle_hash, - )?; - 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, - manager_or_did_coin, - manager_or_did_singleton_proof, - manager_or_did_singleton_puzzle, - manager_conditions, - )?; - - // sim.spend_coins(ctx.take(), &[])?; - benchmark.add_spends(ctx, &mut sim, "add_entry", &[])?; - - (entry1_slot, None) - } else { - let nft_launcher = - Launcher::new(manager_or_did_coin.coin_id(), 0).with_singleton_amount(1); - let nft_launcher_coin = nft_launcher.coin(); - let meta = ctx.alloc(&"nft1")?; - let meta = HashedPtr::from_ptr(ctx, meta); - - let (conds, nft) = nft_launcher.mint_nft( - ctx, - NftMint::new(meta, nft_bls.puzzle_hash, 10, None) - .with_royalty_puzzle_hash(Bytes32::from([1; 32])) - .with_custom_metadata_updater(ANY_METADATA_UPDATER_HASH.into()), - )?; - - (manager_or_did_coin, manager_or_did_singleton_proof) = spend_manager_singleton( - ctx, - manager_or_did_coin, - manager_or_did_singleton_proof, - manager_or_did_singleton_puzzle, - conds, - )?; - - ensure_conditions_met( - ctx, - &mut sim, - Conditions::new().assert_concurrent_spend(nft_launcher_coin.coin_id()), - 1, - )?; - - benchmark.add_spends(ctx, &mut sim, "mint_nft", &[])?; - - let Proof::Lineage(did_proof) = manager_or_did_singleton_proof else { - panic!("did_proof is not a lineage proof"); - }; - let nft_proof = NftLauncherProof { - did_proof, - intermediary_coin_proofs: vec![IntermediaryCoinProof { - full_puzzle_hash: nft_launcher_coin.puzzle_hash, - amount: nft_launcher_coin.amount, - }], - }; - - let (sec_conds, notarized_payment, locked_nft) = registry - .new_action::() - .spend(ctx, &mut registry, nft, nft_proof, nft_bls.puzzle_hash)?; - 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.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, - Memos::None - )))?, - NodePtr::NIL, - ); - let nft_inner_spend = - StandardLayer::new(nft_bls.pk).delegated_inner_spend(ctx, nft_inner_spend)?; - let _new_nft = nft.spend(ctx, nft_inner_spend)?; - - let nft_inner_spend = Spend::new( - ctx.alloc_mod::()?, - ctx.alloc(&SettlementPaymentsSolution { - notarized_payments: vec![notarized_payment], - })?, - ); - 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()])?; - - (entry1_slot, Some(locked_nft)) - }; - - // commit incentives for first epoch - let rewards_to_add = constants.epoch_seconds; - let secure_conditions = registry - .new_action::() - .spend( - ctx, - &mut registry, - first_epoch_slot, - first_epoch_start, - 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( - ctx, - secure_conditions.create_coin( - cat_minter.puzzle_hash, - source_cat.coin.amount - rewards_to_add, - hint, - ), - )?, - ); - - 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.child( - cat_minter.puzzle_hash, - source_cat.coin.amount - rewards_to_add, - ); - assert!(sim - .coin_state(first_epoch_commitment_slot.coin.coin_id()) - .is_some()); - for incentive_slot in incentive_slots.iter() { - assert!(sim.coin_state(incentive_slot.coin.coin_id()).is_some()); - } - - // 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 = registry - .new_action::() - .spend( - ctx, - &mut registry, - incentive_slots.last().unwrap().clone(), - fifth_epoch_start, - 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() - .map(|s| s.info.value.epoch_start) - .collect::>(); - incentive_slots.retain(|s| !new_value_keys.contains(&s.info.value.epoch_start)); - incentive_slots.extend(new_incentive_slots); - - // spend reserve and source cat together so deltas add up - let source_cat_spend = CatSpend::new( - source_cat, - cat_minter_p2.spend_with_conditions( - ctx, - secure_conditions.create_coin( - cat_minter.puzzle_hash, - source_cat.coin.amount - rewards_to_add, - Memos::None, - ), - )?, - ); - - 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.child( - cat_minter.puzzle_hash, - source_cat.coin.amount - rewards_to_add, - ); - assert!(sim - .coin_state(fifth_epoch_commitment_slot.coin.coin_id()) - .is_some()); - for incentive_slot in incentive_slots.iter() { - assert!(sim.coin_state(incentive_slot.coin.coin_id()).is_some()); - } - - // 2nd commit incentives for fifth epoch - let rewards_to_add = constants.epoch_seconds * 2; - let secure_conditions = registry - .new_action::() - .spend( - ctx, - &mut registry, - incentive_slots - .iter() - .find(|s| s.info.value.epoch_start == fifth_epoch_start) - .unwrap() - .clone(), - fifth_epoch_start, - 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() - .map(|s| s.info.value.epoch_start) - .collect::>(); - incentive_slots.retain(|s| !new_value_keys.contains(&s.info.value.epoch_start)); - incentive_slots.extend(new_incentive_slots); - - // spend reserve and source cat together so deltas add up - let source_cat_spend = CatSpend::new( - source_cat, - cat_minter_p2.spend_with_conditions( - ctx, - secure_conditions.create_coin( - cat_minter.puzzle_hash, - source_cat.coin.amount - rewards_to_add, - Memos::None, - ), - )?, - ); - - 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.child( - cat_minter.puzzle_hash, - source_cat.coin.amount - rewards_to_add, - ); - assert!(sim - .coin_state(fifth_epoch_commitment_slot2.coin.coin_id()) - .is_some()); - for incentive_slot in incentive_slots.iter() { - assert!(sim.coin_state(incentive_slot.coin.coin_id()).is_some()); - } - assert!(sim - .coin_state(registry.reserve.coin.coin_id()) - .unwrap() - .spent_height - .is_none()); - - // withdraw the 1st incentives for epoch 5 - let (withdraw_incentives_conditions, withdrawn_amount) = registry - .new_action::() - .spend( - ctx, - &mut registry, - fifth_epoch_commitment_slot.clone(), - incentive_slots - .iter() - .find(|s| s.info.value.epoch_start == fifth_epoch_start) - .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() - .child( - cat_minter.puzzle_hash, // fifth_epoch_commitment_slot.info.value.unwrap().clawback_ph, - withdrawn_amount, - ) - .coin - .coin_id(); - - 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![])?.0; - sim.set_next_timestamp(first_epoch_start)?; - // sim.spend_coins(ctx.take(), &[cat_minter.sk.clone()])?; - benchmark.add_spends( - ctx, - &mut sim, - "withdraw_incentives", - &[cat_minter.sk.clone()], - )?; - - assert!(sim.coin_state(payout_coin_id).is_some()); - assert!(sim - .coin_state(fifth_epoch_commitment_slot.coin.coin_id()) - .unwrap() - .spent_height - .is_some()); - assert!(sim - .coin_state(new_reward_slot.coin.coin_id()) - .unwrap() - .spent_height - .is_none()); - incentive_slots - .retain(|s| s.info.value.epoch_start != new_reward_slot.info.value.epoch_start); - incentive_slots.push(new_reward_slot); - - // start first epoch - let reserve_cat = registry.reserve.to_cat(); - let first_epoch_incentives_slot = incentive_slots - .iter() - .find(|s| s.info.value.epoch_start == first_epoch_start) - .unwrap() - .clone(); - let (new_epoch_conditions, fee) = registry - .new_action::() - .spend( - ctx, - &mut registry, - 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 - .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![])?.0; - sim.pass_time(100); - // sim.spend_coins(ctx.take(), &[])?; - benchmark.add_spends(ctx, &mut sim, "new_epoch", &[])?; - - assert!(sim.coin_state(payout_coin_id).is_some()); - assert_eq!(registry.info.state.active_shares, 1); - assert_eq!(registry.info.state.total_reserves, 4000 - fee); - assert_eq!(registry.info.state.round_reward_info.cumulative_payout, 0); - assert_eq!( - registry.info.state.round_reward_info.remaining_rewards, - first_epoch_incentives_slot.info.value.rewards - fee - ); - assert_eq!( - registry.info.state.round_time_info.last_update, - first_epoch_start - ); - assert_eq!( - registry.info.state.round_time_info.epoch_end, - first_epoch_start + constants.epoch_seconds - ); - assert!(sim - .coin_state(first_epoch_incentives_slot.coin.coin_id()) - .unwrap() - .spent_height - .is_some()); - assert!(sim - .coin_state(new_reward_slot.coin.coin_id()) - .unwrap() - .spent_height - .is_none()); - incentive_slots - .retain(|s| s.info.value.epoch_start != new_reward_slot.info.value.epoch_start); - incentive_slots.push(new_reward_slot); - - // sync to 10% - let initial_reward_info = registry.info.state.round_reward_info; - let sync_conditions = registry.new_action::().spend( - ctx, - &mut registry, - first_epoch_start + 100, - )?; - ensure_conditions_met(ctx, &mut sim, sync_conditions, 0)?; - - registry = registry.finish_spend(ctx, vec![])?.0; - sim.pass_time(400); - // sim.spend_coins(ctx.take(), &[])?; - benchmark.add_spends(ctx, &mut sim, "sync", &[])?; - - assert!(registry.info.state.round_time_info.last_update == first_epoch_start + 100); - - let cumulative_payout_delta = initial_reward_info.remaining_rewards / 10; - assert!( - registry.info.state.round_reward_info.remaining_rewards - == initial_reward_info.remaining_rewards - cumulative_payout_delta - ); - assert!( - registry.info.state.round_reward_info.cumulative_payout - == initial_reward_info.cumulative_payout + cumulative_payout_delta - ); - - // sync to 50% (so + 40%) - let initial_reward_info = registry.info.state.round_reward_info; - let sync_conditions = registry.new_action::().spend( - ctx, - &mut registry, - first_epoch_start + 500, - )?; - ensure_conditions_met(ctx, &mut sim, sync_conditions, 0)?; - - 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); - - let cumulative_payout_delta = initial_reward_info.remaining_rewards * 400 / 900; - assert!( - registry.info.state.round_reward_info.remaining_rewards - == initial_reward_info.remaining_rewards - cumulative_payout_delta - ); - assert!( - registry.info.state.round_reward_info.cumulative_payout - == initial_reward_info.cumulative_payout + cumulative_payout_delta - ); - - // add incentives - let initial_reward_info = registry.info.state.round_reward_info; - let incentives_amount = initial_reward_info.remaining_rewards; - let registry_info = registry.info; - - let add_incentives_conditions = registry - .new_action::() - .spend(ctx, &mut registry, incentives_amount)?; - - // spend reserve and source cat together so deltas add up - let source_cat_spend = CatSpend::new( - source_cat, - cat_minter_p2.spend_with_conditions( - ctx, - add_incentives_conditions.create_coin( - cat_minter.puzzle_hash, - source_cat.coin.amount - incentives_amount, - Memos::None, - ), - )?, - ); - - 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()])?; - - assert_eq!( - registry.info.state.round_time_info.last_update, - first_epoch_start + 500 - ); - assert_eq!( - registry.info.state.round_reward_info.cumulative_payout, - registry_info.state.round_reward_info.cumulative_payout - ); - assert_eq!( - registry.info.state.round_reward_info.remaining_rewards, - registry_info.state.round_reward_info.remaining_rewards - + (incentives_amount - incentives_amount * constants.fee_bps / 10000) - ); - source_cat = source_cat.child( - cat_minter.puzzle_hash, - source_cat.coin.amount - incentives_amount, - ); - - // add second entry OR 2 more NFTs - 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 = registry - .new_action::() - .spend( - ctx, - &mut registry, - entry2_bls.puzzle_hash, - 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, - manager_or_did_singleton_proof, - manager_or_did_singleton_puzzle, - manager_conditions, - )?; - - registry = registry.finish_spend(ctx, vec![])?.0; - sim.pass_time(250); - // sim.spend_coins(ctx.take(), &[])?; - benchmark.add_spends(ctx, &mut sim, "add_entry", &[])?; - - (entry2_slot, None) - } else { - let nft2_launcher = - Launcher::new(manager_or_did_coin.coin_id(), 0).with_singleton_amount(1); - let nft2_launcher_coin = nft2_launcher.coin(); - let meta2 = ctx.alloc(&"nft2")?; - let meta2 = HashedPtr::from_ptr(ctx, meta2); - - let nft3_launcher = - Launcher::new(manager_or_did_coin.coin_id(), 2).with_singleton_amount(1); - let nft3_launcher_coin = nft3_launcher.coin(); - let meta3 = ctx.alloc(&"nft3")?; - let meta3 = HashedPtr::from_ptr(ctx, meta3); - - let (conds2, nft2) = nft2_launcher.mint_nft( - ctx, - NftMint::new(meta2, nft2_bls.puzzle_hash, 12, None) - .with_royalty_puzzle_hash(Bytes32::from([2; 32])) - .with_custom_metadata_updater(ANY_METADATA_UPDATER_HASH.into()), - )?; - - let (conds3, nft3) = nft3_launcher.mint_nft( - ctx, - NftMint::new(meta3, nft3_bls.puzzle_hash, 15, None) - .with_royalty_puzzle_hash(Bytes32::from([3; 32])), - )?; - - (manager_or_did_coin, manager_or_did_singleton_proof) = spend_manager_singleton( - ctx, - manager_or_did_coin, - manager_or_did_singleton_proof, - manager_or_did_singleton_puzzle, - conds2.extend(conds3), - )?; - - ensure_conditions_met( - ctx, - &mut sim, - Conditions::new() - .assert_concurrent_spend(nft2_launcher_coin.coin_id()) - .assert_concurrent_spend(nft3_launcher_coin.coin_id()), - 2, - )?; - - benchmark.add_spends(ctx, &mut sim, "mint_2_nfts", &[])?; - - let Proof::Lineage(did_proof) = manager_or_did_singleton_proof else { - panic!("did_proof is not a lineage proof"); - }; - let nft2_proof = NftLauncherProof { - did_proof, - intermediary_coin_proofs: vec![IntermediaryCoinProof { - full_puzzle_hash: nft2_launcher_coin.puzzle_hash, - amount: nft2_launcher_coin.amount, - }], - }; - let nft3_proof = NftLauncherProof { - did_proof, - intermediary_coin_proofs: vec![IntermediaryCoinProof { - full_puzzle_hash: nft3_launcher_coin.puzzle_hash, - amount: nft3_launcher_coin.amount, - }], - }; - - let (sec_conds2, notarized_payment2, locked_nft2) = registry - .new_action::() - .spend(ctx, &mut registry, nft2, nft2_proof, nft2_bls.puzzle_hash)?; - 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)?; - 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.child(SETTLEMENT_PAYMENT_HASH.into(), None, nft2.info.metadata, 1); - let offer3_nft = - 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, - Memos::None - )))?, - NodePtr::NIL, - ); - let nft2_inner_spend = - 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)?; - 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::()?, - ctx.alloc(&SettlementPaymentsSolution { - notarized_payments: vec![notarized_payment2], - })?, - ); - let _new_offer2_nft = offer2_nft.spend(ctx, nft2_inner_spend)?; - - let nft3_inner_spend = Spend::new( - ctx.alloc_mod::()?, - ctx.alloc(&SettlementPaymentsSolution { - notarized_payments: vec![notarized_payment3], - })?, - ); - 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()])?; - benchmark.add_spends( - ctx, - &mut sim, - "stake_2_nfts", - &[nft2_bls.sk.clone(), nft3_bls.sk.clone()], - )?; - - (entry2_slot, Some((entry3_slot, locked_nft2, locked_nft3))) - }; - assert_eq!(registry.info.state.active_shares, 3); - - // sync to 75% (so + 25%) - let initial_reward_info = registry.info.state.round_reward_info; - let sync_conditions = registry.new_action::().spend( - ctx, - &mut registry, - first_epoch_start + 750, - )?; - ensure_conditions_met(ctx, &mut sim, sync_conditions, 0)?; - - 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); - - let cumulative_payout_delta = initial_reward_info.remaining_rewards * 250 / (3 * 500); - assert!( - registry.info.state.round_reward_info.remaining_rewards - == initial_reward_info.remaining_rewards - cumulative_payout_delta * 3 - ); - assert!( - registry.info.state.round_reward_info.cumulative_payout - == initial_reward_info.cumulative_payout + cumulative_payout_delta - ); - - // remove 2nd entry/the 2 NFTs - 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 - .child(nft2_bls.puzzle_hash, None, locked_nft2.info.metadata, 1) - .coin - .coin_id(); - let nft3_return_coin_id = locked_nft3 - .child(nft3_bls.puzzle_hash, None, locked_nft3.info.metadata, 1) - .coin - .coin_id(); - - let (custody2_conds, payout2_amount) = registry - .new_action::() - .spend(ctx, &mut registry, entry2_slot.clone(), locked_nft2)?; - let (custody3_conds, payout3_amount) = registry - .new_action::() - .spend(ctx, &mut registry, entry3_slot.clone(), locked_nft3)?; - - 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![])?.0; - - // sim.spend_coins(spends, &[nft2_bls.sk.clone(), nft3_bls.sk.clone()])?; - benchmark.add_spends( - ctx, - &mut sim, - "unstake_2_nfts", - &[nft2_bls.sk.clone(), nft3_bls.sk.clone()], - )?; - - let payout_coin_id2 = reserve_cat - .child(nft2_bls.puzzle_hash, payout2_amount) - .coin - .coin_id(); - let payout_coin_id3 = reserve_cat - .child(nft3_bls.puzzle_hash, payout3_amount) - .coin - .coin_id(); - - assert!(sim.coin_state(payout_coin_id2).is_some()); - assert!(sim.coin_state(payout_coin_id3).is_some()); - assert!(sim - .coin_state(entry3_slot.coin.coin_id()) - .unwrap() - .spent_height - .is_some()); - assert!(sim.coin_state(nft2_return_coin_id).is_some()); - assert!(sim.coin_state(nft3_return_coin_id).is_some()); - } else { - let (remove_entry_manager_conditions, entry2_payout_amount) = registry - .new_action::() - .spend( - ctx, - &mut registry, - entry2_slot.clone(), - manager_or_did_singleton_inner_puzzle_hash, - )?; - - let (_manager_coin, _manager_singleton_proof) = spend_manager_singleton( - ctx, - manager_or_did_coin, - manager_or_did_singleton_proof, - manager_or_did_singleton_puzzle, - remove_entry_manager_conditions, - )?; - - 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 - .child(entry2_bls.puzzle_hash, entry2_payout_amount) - .coin - .coin_id(); - - assert!(sim.coin_state(payout_coin_id).is_some()); - } - assert!(registry.info.state.active_shares == 1); - assert!(sim - .coin_state(entry2_slot.coin.coin_id()) - .unwrap() - .spent_height - .is_some()); - - for epoch in 1..7 { - let update_time = registry.info.state.round_time_info.epoch_end; - let first_update_time = - (registry.info.state.round_time_info.last_update + update_time) / 2; - let sync_conditions1 = registry.new_action::().spend( - ctx, - &mut registry, - first_update_time, - )?; - - let sync_conditions2 = registry.new_action::().spend( - ctx, - &mut registry, - update_time, - )?; - - let reward_slot = incentive_slots - .iter() - .find(|s| { - s.info.value.epoch_start - == first_epoch_start - + if epoch <= 4 { epoch } else { 4 } * constants.epoch_seconds - }) - .unwrap() - .clone(); - - 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); - - ensure_conditions_met( - ctx, - &mut sim, - sync_conditions1 - .extend(sync_conditions2) - .extend(new_epoch_conditions), - 0, - )?; - - 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", &[])?; - } - - // 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 = registry - .new_action::() - .spend( - ctx, - &mut registry, - incentive_slots.last().unwrap().clone(), - tenth_epoch_start, - 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() - .map(|s| s.info.value.epoch_start) - .collect::>(); - incentive_slots.retain(|s| !new_value_keys.contains(&s.info.value.epoch_start)); - incentive_slots.extend(new_incentive_slots); - - // spend reserve and source cat together so deltas add up - let source_cat_spend = CatSpend::new( - source_cat, - cat_minter_p2.spend_with_conditions( - ctx, - secure_conditions.create_coin( - cat_minter.puzzle_hash, - source_cat.coin.amount - rewards_to_add, - Memos::None, - ), - )?, - ); - - 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.child( - cat_minter.puzzle_hash, - source_cat.coin.amount - rewards_to_add, - ); - assert!(sim - .coin_state(tenth_epoch_commitment_slot.coin.coin_id()) - .is_some()); - for incentive_slot in incentive_slots.iter() { - assert!(sim.coin_state(incentive_slot.coin.coin_id()).is_some()); - } - - for epoch in 7..10 { - let update_time = registry.info.state.round_time_info.epoch_end; - let sync_conditions = registry.new_action::().spend( - ctx, - &mut registry, - update_time, - )?; - - let reward_slot = incentive_slots - .iter() - .find(|s| { - s.info.value.epoch_start == first_epoch_start + epoch * constants.epoch_seconds - }) - .unwrap() - .clone(); - let (new_epoch_conditions, _manager_fee) = registry - .new_action::() - .spend( - ctx, - &mut registry, - 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); - - ensure_conditions_met( - ctx, - &mut sim, - sync_conditions.extend(new_epoch_conditions), - 0, - )?; - - 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", &[])?; - } - - let update_time = registry.info.state.round_time_info.epoch_end - 100; - let sync_conditions = registry.new_action::().spend( - ctx, - &mut registry, - update_time, - )?; - - // payout entry - let reserve_cat = registry.reserve.to_cat(); - 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![])?.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 - .child( - match manager_type { - RewardDistributorType::Manager => entry1_bls.puzzle_hash, - RewardDistributorType::Nft => nft_bls.puzzle_hash, - }, - withdrawal_amount, - ) - .coin - .coin_id(); - - assert!(sim.coin_state(payout_coin_id).is_some()); - assert_eq!(sim.coin_state(payout_coin_id).unwrap().coin.amount, 12602); - - benchmark.print_summary(Some(&format!( - "{}-reward-distributor.costs", - match manager_type { - RewardDistributorType::Manager => "manager", - RewardDistributorType::Nft => "nft", - } - ))); - - Ok(()) - } -} diff --git a/src/layers.rs b/src/layers.rs deleted file mode 100644 index f3425e3f..00000000 --- a/src/layers.rs +++ /dev/null @@ -1,19 +0,0 @@ -mod action; -mod action_layer; -mod actions; -mod conditions_layer; -mod m_of_n_layer; -mod p2_delegated_by_singleton_layer; -mod precommit_layer; -mod state_scheduler_layer; -mod verification_layer; - -pub use action::*; -pub use action_layer::*; -pub use actions::*; -pub use conditions_layer::*; -pub use m_of_n_layer::*; -pub use p2_delegated_by_singleton_layer::*; -pub use precommit_layer::*; -pub use state_scheduler_layer::*; -pub use verification_layer::*; diff --git a/src/layers/action.rs b/src/layers/action.rs deleted file mode 100644 index a90e62e1..00000000 --- a/src/layers/action.rs +++ /dev/null @@ -1,23 +0,0 @@ -pub trait Registry { - type State; - type Constants; -} - -pub trait Action { - fn from_constants(constants: &R::Constants) -> Self; - - // you may also add: - - // fn curry_tree_hash(constants: &R::Constants) -> TreeHash; - - // fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result; - - // fn spend( - // self, - // ctx: &mut SpendContext, - // registry: &Self::Registry, - // params: &Self::SpendParams, - // ) -> Result<(Option, Spend, Self::SpendReturnParams), DriverError>; - - // and a function to return the slots this action creates -} diff --git a/src/layers/action_layer.rs b/src/layers/action_layer.rs deleted file mode 100644 index fcc99612..00000000 --- a/src/layers/action_layer.rs +++ /dev/null @@ -1,620 +0,0 @@ -use std::{collections::HashMap, fmt::Debug}; - -use chia::{ - clvm_traits::{FromClvm, ToClvm}, - clvm_utils::{tree_hash, CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Layer, Puzzle, Spend, SpendContext}, - types::{run_puzzle, MerkleProof, MerkleTree}, -}; -use clvm_traits::{clvm_list, match_tuple}; -use clvmr::{Allocator, NodePtr}; -use hex_literal::hex; - -use crate::SpendContextExt; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum Finalizer

{ - Default { - hint: Bytes32, - }, - Reserve { - reserve_full_puzzle_hash: Bytes32, - reserve_inner_puzzle_hash: Bytes32, - reserve_amount_from_state_program: P, - hint: Bytes32, - }, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ActionLayer { - pub merkle_root: Bytes32, - pub state: S, - pub finalizer: Finalizer

, -} - -#[derive(Debug, Clone)] -pub struct ActionLayerSolution { - pub proofs: Vec, - pub action_spends: Vec, - pub finalizer_solution: F, -} - -impl ActionLayer { - pub fn new(merkle_root: Bytes32, state: S, finalizer: Finalizer

) -> Self { - Self { - merkle_root, - state, - finalizer, - } - } - - pub fn from_action_puzzle_hashes( - leaves: &[Bytes32], - state: S, - finalizer: Finalizer

, - ) -> Self { - let merkle_root = MerkleTree::new(leaves).root(); - - Self { - merkle_root, - state, - finalizer, - } - } - - pub fn get_proofs( - &self, - action_puzzle_hashes: &[Bytes32], - action_spends_puzzle_hashes: &[Bytes32], - ) -> Option> { - let merkle_tree = MerkleTree::new(action_puzzle_hashes); - - let proofs: Vec = action_spends_puzzle_hashes - .iter() - .filter_map(|puzzle_hash| { - let proof = merkle_tree.proof(*puzzle_hash)?; - - Some(proof) - }) - .collect(); - - if proofs.len() != action_spends_puzzle_hashes.len() { - return None; - } - - Some(proofs) - } - - pub fn extract_merkle_root_and_state( - allocator: &Allocator, - inner_puzzle: Puzzle, - ) -> Result, DriverError> - where - S: FromClvm, - { - let Some(puzzle) = inner_puzzle.as_curried() else { - return Ok(None); - }; - - if inner_puzzle.mod_hash() != ACTION_LAYER_PUZZLE_HASH { - return Ok(None); - } - - let args = ActionLayerArgs::::from_clvm(allocator, puzzle.args)?; - - Ok(Some((args.merkle_root, args.state))) - } - - pub fn get_new_state( - allocator: &mut Allocator, - initial_state: S, - action_layer_solution: NodePtr, - ) -> Result - where - S: ToClvm + FromClvm + Clone, - { - let solution = ActionLayer::::parse_solution(allocator, action_layer_solution)?; - - let mut state_incl_ephemeral: (NodePtr, S) = (NodePtr::NIL, initial_state); - for raw_action in solution.action_spends { - let actual_solution = - clvm_list!(state_incl_ephemeral, raw_action.solution).to_clvm(allocator)?; - - let output = run_puzzle(allocator, raw_action.puzzle, actual_solution)?; - - (state_incl_ephemeral, _) = - ::from_clvm(allocator, output)?; - } - - Ok(state_incl_ephemeral.1) - } -} - -impl Layer for ActionLayer -where - S: ToClvm + FromClvm + Clone, - P: ToClvm + FromClvm + Clone, -{ - type Solution = ActionLayerSolution; - - fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result, DriverError> { - let Some(puzzle) = puzzle.as_curried() else { - return Ok(None); - }; - - if puzzle.mod_hash != ACTION_LAYER_PUZZLE_HASH { - return Ok(None); - } - - let args = ActionLayerArgs::::from_clvm(allocator, puzzle.args)?; - let finalizer_2nd_curry = - CurriedProgram::::from_clvm(allocator, args.finalizer); - let Ok(finalizer_2nd_curry) = finalizer_2nd_curry else { - return Ok(None); - }; - - let finalizer_1st_curry = Puzzle::from_clvm(allocator, finalizer_2nd_curry.program)?; - let Some(finalizer_1st_curry) = finalizer_1st_curry.as_curried() else { - return Ok(None); - }; - - match finalizer_1st_curry.mod_hash { - DEFAULT_FINALIZER_PUZZLE_HASH => { - let finalizer_2nd_curry_args = - DefaultFinalizer2ndCurryArgs::from_clvm(allocator, finalizer_2nd_curry.args)?; - let finalizer_1st_curry_args = - DefaultFinalizer1stCurryArgs::from_clvm(allocator, finalizer_1st_curry.args)?; - - if finalizer_1st_curry.mod_hash != DEFAULT_FINALIZER_PUZZLE_HASH - || finalizer_1st_curry_args.action_layer_mod_hash - != ACTION_LAYER_PUZZLE_HASH.into() - || finalizer_2nd_curry_args.finalizer_self_hash - != DefaultFinalizer1stCurryArgs::curry_tree_hash( - finalizer_1st_curry_args.hint, - ) - .into() - { - return Err(DriverError::NonStandardLayer); - } - - Ok(Some(Self { - merkle_root: args.merkle_root, - state: args.state, - finalizer: Finalizer::Default { - hint: finalizer_1st_curry_args.hint, - }, - })) - } - RESERVE_FINALIZER_PUZZLE_HASH => { - let finalizer_2nd_curry_args = - ReserveFinalizer2ndCurryArgs::from_clvm(allocator, finalizer_2nd_curry.args)?; - let finalizer_1st_curry_args = ReserveFinalizer1stCurryArgs::::from_clvm( - allocator, - finalizer_1st_curry.args, - )?; - - let reserve_amount_from_state_program_hash = tree_hash( - allocator, - finalizer_1st_curry_args.reserve_amount_from_state_program, - ); - - if finalizer_1st_curry.mod_hash != RESERVE_FINALIZER_PUZZLE_HASH - || finalizer_1st_curry_args.action_layer_mod_hash - != ACTION_LAYER_PUZZLE_HASH.into() - || finalizer_2nd_curry_args.finalizer_self_hash - != ReserveFinalizer1stCurryArgs::::curry_tree_hash( - finalizer_1st_curry_args.reserve_full_puzzle_hash, - finalizer_1st_curry_args.reserve_inner_puzzle_hash, - reserve_amount_from_state_program_hash, - finalizer_1st_curry_args.hint, - ) - .into() - { - return Err(DriverError::NonStandardLayer); - } - - let reserve_amount_from_state_program =

::from_clvm( - allocator, - finalizer_1st_curry_args.reserve_amount_from_state_program, - )?; - - Ok(Some(Self { - merkle_root: args.merkle_root, - state: args.state, - finalizer: Finalizer::Reserve { - reserve_full_puzzle_hash: finalizer_1st_curry_args.reserve_full_puzzle_hash, - reserve_inner_puzzle_hash: finalizer_1st_curry_args - .reserve_inner_puzzle_hash, - reserve_amount_from_state_program, - hint: finalizer_1st_curry_args.hint, - }, - })) - } - _ => Err(DriverError::NonStandardLayer), - } - } - - fn parse_solution( - allocator: &Allocator, - solution: NodePtr, - ) -> Result { - let solution = - RawActionLayerSolution::::from_clvm(allocator, solution)?; - - let mut actions = Vec::::with_capacity(solution.solutions.len()); - let mut proofs = Vec::::with_capacity(solution.solutions.len()); - let mut selector_proofs = HashMap::::new(); - - for (selector, proof) in solution.selectors_and_proofs.into_iter() { - let proof = if let Some(existing_proof) = selector_proofs.get(&selector) { - existing_proof.clone() - } else { - let proof = proof.ok_or(DriverError::InvalidMerkleProof)?; - selector_proofs.insert(selector, proof.clone()); - proof - }; - - proofs.push(proof); - - let mut index = 0; - let mut remaining_selector = selector; - while remaining_selector > 2 { - index += 1; - remaining_selector /= 2; - } - actions.push(solution.puzzles[index as usize]); - } - - let action_spends = solution - .solutions - .iter() - .zip(actions.into_iter().rev()) - .map(|(action_solution, action_puzzle)| Spend::new(action_puzzle, *action_solution)) - .collect(); - let proofs = proofs.into_iter().rev().collect(); - - Ok(ActionLayerSolution { - proofs, - action_spends, - finalizer_solution: solution.finalizer_solution, - }) - } - - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - let finalizer_1st_curry = match &self.finalizer { - Finalizer::Default { hint } => CurriedProgram { - program: ctx.default_finalizer_puzzle()?, - args: DefaultFinalizer1stCurryArgs::new(*hint), - } - .to_clvm(ctx)?, - Finalizer::Reserve { - reserve_full_puzzle_hash, - reserve_inner_puzzle_hash, - reserve_amount_from_state_program, - hint, - } => CurriedProgram { - program: ctx.reserve_finalizer_puzzle()?, - args: ReserveFinalizer1stCurryArgs::

::new( - *reserve_full_puzzle_hash, - *reserve_inner_puzzle_hash, - reserve_amount_from_state_program.clone(), - *hint, - ), - } - .to_clvm(ctx)?, - }; - - let finalizer = match &self.finalizer { - Finalizer::Default { hint } => CurriedProgram { - program: finalizer_1st_curry, - args: DefaultFinalizer2ndCurryArgs::new(*hint), - } - .to_clvm(ctx)?, - Finalizer::Reserve { - reserve_full_puzzle_hash, - reserve_inner_puzzle_hash, - reserve_amount_from_state_program, - hint, - } => { - let reserve_amount_from_state_program = - ctx.alloc(&reserve_amount_from_state_program)?; - let reserve_amount_from_state_program_hash = - ctx.tree_hash(reserve_amount_from_state_program); - - CurriedProgram { - program: finalizer_1st_curry, - args: ReserveFinalizer2ndCurryArgs::new( - *reserve_full_puzzle_hash, - *reserve_inner_puzzle_hash, - reserve_amount_from_state_program_hash, - *hint, - ), - } - .to_clvm(ctx)? - } - }; - - Ok(CurriedProgram { - program: ctx.action_layer_puzzle()?, - args: ActionLayerArgs::::new( - finalizer, - self.merkle_root, - self.state.clone(), - ), - } - .to_clvm(ctx)?) - } - - fn construct_solution( - &self, - ctx: &mut SpendContext, - solution: Self::Solution, - ) -> Result { - let mut puzzle_to_selector = HashMap::::new(); - let mut next_selector = 2; - - let mut puzzles = Vec::::new(); - let mut selectors_and_proofs = Vec::<(u32, Option)>::new(); - let mut solutions = Vec::::new(); - - for (spend, proof) in solution.action_spends.into_iter().zip(solution.proofs) { - let puzzle_hash: Bytes32 = ctx.tree_hash(spend.puzzle).into(); - if let Some(selector) = puzzle_to_selector.get(&puzzle_hash) { - selectors_and_proofs.push((*selector, Some(proof.clone()))); - } else { - puzzles.push(spend.puzzle); - selectors_and_proofs.push((next_selector, Some(proof.clone()))); - puzzle_to_selector.insert(puzzle_hash, next_selector); - - next_selector = next_selector * 2 + 1; - } - - solutions.push(spend.solution); - } - - let mut proven_selectors = Vec::::new(); - let mut selectors_and_proofs: Vec<(u32, Option)> = - selectors_and_proofs.into_iter().rev().collect(); - #[allow(clippy::needless_range_loop)] - for i in 0..selectors_and_proofs.len() { - let selector = selectors_and_proofs[i].0; - - if proven_selectors.contains(&selector) { - selectors_and_proofs[i].1 = None; - } else { - proven_selectors.push(selector); - } - } - - Ok(RawActionLayerSolution { - puzzles, - selectors_and_proofs, - solutions, - finalizer_solution: solution.finalizer_solution, - } - .to_clvm(ctx)?) - } -} - -pub const DEFAULT_FINALIZER_PUZZLE: [u8; 617] = hex!("ff02ffff01ff04ffff04ff10ffff04ffff02ff12ffff04ff02ffff04ff05ffff04ffff02ff12ffff04ff02ffff04ff17ffff04ffff0bffff0101ff1780ff8080808080ffff04ffff0bffff0101ff2f80ffff04ffff02ff1effff04ff02ffff04ff82033fff80808080ff80808080808080ffff04ffff0101ffff04ffff04ff0bff8080ff8080808080ffff02ff1affff04ff02ffff04ff8201bfff8080808080ffff04ffff01ffffff3302ffff02ffff03ff05ffff01ff0bff7cffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff14ffff04ff02ffff04ff0dff80808080ff808080808080ffff016c80ff0180ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffffff0bff5cffff02ff16ffff04ff02ffff04ff05ffff04ffff02ff14ffff04ff02ffff04ff07ff80808080ff808080808080ff02ffff03ff09ffff01ff04ff11ffff02ff1affff04ff02ffff04ffff04ff19ff0d80ff8080808080ffff01ff02ffff03ff0dffff01ff02ff1affff04ff02ffff04ff0dff80808080ff8080ff018080ff0180ffff0bff18ffff0bff18ff6cff0580ffff0bff18ff0bff4c8080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080"); -pub const DEFAULT_FINALIZER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 34b1f957ca3ba935921c32625cd432316ae71344977d96b4ffc5243c7d08d781 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct DefaultFinalizer1stCurryArgs { - pub action_layer_mod_hash: Bytes32, - pub hint: Bytes32, -} - -impl DefaultFinalizer1stCurryArgs { - pub fn new(hint: Bytes32) -> Self { - Self { - action_layer_mod_hash: ACTION_LAYER_PUZZLE_HASH.into(), - hint, - } - } - - pub fn curry_tree_hash(hint: Bytes32) -> TreeHash { - CurriedProgram { - program: DEFAULT_FINALIZER_PUZZLE_HASH, - args: DefaultFinalizer1stCurryArgs::new(hint), - } - .tree_hash() - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct DefaultFinalizer2ndCurryArgs { - pub finalizer_self_hash: Bytes32, -} - -impl DefaultFinalizer2ndCurryArgs { - pub fn new(hint: Bytes32) -> Self { - Self { - finalizer_self_hash: DefaultFinalizer1stCurryArgs::curry_tree_hash(hint).into(), - } - } - - pub fn curry_tree_hash(hint: Bytes32) -> TreeHash { - let self_hash: TreeHash = DefaultFinalizer1stCurryArgs::curry_tree_hash(hint); - - CurriedProgram { - program: self_hash, - args: DefaultFinalizer2ndCurryArgs { - finalizer_self_hash: self_hash.into(), - }, - } - .tree_hash() - } -} - -pub const RESERVE_FINALIZER_PUZZLE: [u8; 884] = hex!("ff02ffff01ff04ffff04ff10ffff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff1affff04ff02ffff04ff81bfffff04ffff0bffff0101ff81bf80ff8080808080ffff04ffff0bffff0101ff82017f80ffff04ffff02ff3effff04ff02ffff04ff8219ffff80808080ff80808080808080ffff04ffff0101ffff04ffff04ff5fff8080ff8080808080ffff04ffff04ff18ffff04ffff0117ffff04ffff02ff3effff04ff02ffff04ffff04ffff0101ffff04ffff04ff10ffff04ff17ffff04ffff02ff2fff8219ff80ffff04ffff04ff17ff8080ff8080808080ffff06ffff02ff2effff04ff02ffff04ff820dffffff01ff80ff8080808080808080ff80808080ffff04ffff30ff8213ffff0bffff02ff2fff8202ff8080ff8080808080ffff05ffff02ff2effff04ff02ffff04ff820dffffff01ff80ff8080808080808080ffff04ffff01ffffff3342ff02ff02ffff03ff05ffff01ff0bff72ffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff1cffff04ff02ffff04ff0dff80808080ff808080808080ffff016280ff0180ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff0bff52ffff02ff16ffff04ff02ffff04ff05ffff04ffff02ff1cffff04ff02ffff04ff07ff80808080ff808080808080ffff0bff14ffff0bff14ff62ff0580ffff0bff14ff0bff428080ffff02ffff03ff09ffff01ff02ffff03ffff09ff21ffff0181d680ffff01ff02ff2effff04ff02ffff04ffff04ff19ff0d80ffff04ff0bffff04ffff04ff31ff1780ff808080808080ffff01ff02ff2effff04ff02ffff04ffff04ff19ff0d80ffff04ffff04ff11ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff03ff0dffff01ff02ff2effff04ff02ffff04ff0dffff04ff0bffff04ff17ff808080808080ffff01ff04ff0bff178080ff018080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080"); -pub const RESERVE_FINALIZER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - d277207ecea05d2b6a3874ef3bf5831cd224527eedab8c000a03b5511fb511de - " -)); - -// run '(mod state (f state))' -d -pub const RESERVE_FINALIZER_DEFAULT_RESERVE_AMOUNT_FROM_STATE_PROGRAM: [u8; 1] = hex!("02"); -pub const RESERVE_FINALIZER_DEFAULT_RESERVE_AMOUNT_FROM_STATE_PROGRAM_HASH: TreeHash = - TreeHash::new(hex!( - "a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222" - )); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct ReserveFinalizer1stCurryArgs

{ - pub action_layer_mod_hash: Bytes32, - pub reserve_full_puzzle_hash: Bytes32, - pub reserve_inner_puzzle_hash: Bytes32, - pub reserve_amount_from_state_program: P, - pub hint: Bytes32, -} - -impl

ReserveFinalizer1stCurryArgs

{ - pub fn new( - reserve_full_puzzle_hash: Bytes32, - reserve_inner_puzzle_hash: Bytes32, - reserve_amount_from_state_program: P, - hint: Bytes32, - ) -> Self { - Self { - action_layer_mod_hash: ACTION_LAYER_PUZZLE_HASH.into(), - reserve_full_puzzle_hash, - reserve_inner_puzzle_hash, - reserve_amount_from_state_program, - hint, - } - } - - pub fn curry_tree_hash( - reserve_full_puzzle_hash: Bytes32, - reserve_inner_puzzle_hash: Bytes32, - reserve_amount_from_state_program: TreeHash, - hint: Bytes32, - ) -> TreeHash { - CurriedProgram { - program: RESERVE_FINALIZER_PUZZLE_HASH, - args: ReserveFinalizer1stCurryArgs::new( - reserve_full_puzzle_hash, - reserve_inner_puzzle_hash, - reserve_amount_from_state_program, - hint, - ), - } - .tree_hash() - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct ReserveFinalizer2ndCurryArgs { - pub finalizer_self_hash: Bytes32, -} - -impl ReserveFinalizer2ndCurryArgs { - pub fn new

( - reserve_full_puzzle_hash: Bytes32, - reserve_inner_puzzle_hash: Bytes32, - reserve_amount_from_state_program: P, - hint: Bytes32, - ) -> Self - where - P: ToTreeHash, - { - Self { - finalizer_self_hash: ReserveFinalizer1stCurryArgs::::curry_tree_hash( - reserve_full_puzzle_hash, - reserve_inner_puzzle_hash, - reserve_amount_from_state_program.tree_hash(), - hint, - ) - .into(), - } - } - - pub fn curry_tree_hash( - reserve_full_puzzle_hash: Bytes32, - reserve_inner_puzzle_hash: Bytes32, - reserve_amount_from_state_program: TreeHash, - hint: Bytes32, - ) -> TreeHash { - let self_hash: TreeHash = ReserveFinalizer1stCurryArgs::::curry_tree_hash( - reserve_full_puzzle_hash, - reserve_inner_puzzle_hash, - reserve_amount_from_state_program, - hint, - ); - - CurriedProgram { - program: self_hash, - args: ReserveFinalizer2ndCurryArgs { - finalizer_self_hash: self_hash.into(), - }, - } - .tree_hash() - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct ReserveFinalizerSolution { - pub reserve_parent_id: Bytes32, -} - -pub const ACTION_LAYER_PUZZLE: [u8; 670] = hex!("ff02ffff01ff02ff05ffff04ff0bffff04ff17ffff04ffff02ff0affff04ff02ffff04ff2fffff04ff80ffff04ffff04ffff04ff80ff1780ff8080ffff04ffff02ff0cffff04ff02ffff04ff0bffff04ff2fffff04ff80ffff04ff5fff80808080808080ffff04ff81bfff8080808080808080ffff04ff82017fff808080808080ffff04ffff01ffffff02ffff03ffff09ff05ff1380ffff01ff0101ffff01ff02ff08ffff04ff02ffff04ff05ffff04ff1bff808080808080ff0180ff02ffff03ff2fffff01ff02ffff03ffff02ffff03ff81cfffff01ff09ff05ffff02ff1effff04ff02ffff04ffff0bffff0101ffff02ff16ffff04ff02ffff04ffff02ff818fff0b80ff8080808080ffff04ff81cfff808080808080ffff01ff02ff08ffff04ff02ffff04ff818fffff04ff17ff808080808080ff0180ffff01ff02ff0cffff04ff02ffff04ff05ffff04ff0bffff04ffff04ff818fff1780ffff04ff6fff80808080808080ffff01ff088080ff0180ffff011780ff0180ffff02ffff03ff2fffff01ff02ff0affff04ff02ffff04ff05ffff04ffff04ff37ff0b80ffff04ffff02ffff02ff4fff0580ffff04ff27ffff04ff819fff80808080ffff04ff6fffff04ff81dfff8080808080808080ffff01ff04ff27ffff04ff37ff0b808080ff0180ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff16ffff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff02ffff03ff1bffff01ff02ff1effff04ff02ffff04ffff02ffff03ffff18ffff0101ff1380ffff01ff0bffff0102ff2bff0580ffff01ff0bffff0102ff05ff2b8080ff0180ffff04ffff04ffff17ff13ffff0181ff80ff3b80ff8080808080ffff010580ff0180ff018080"); -pub const ACTION_LAYER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 2ad6e558c952fb62de6428fb8d627bcd21ddf37aa8aabb43a8620d98e922a163 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct ActionLayerArgs { - pub finalizer: F, - pub merkle_root: Bytes32, - pub state: S, -} - -impl ActionLayerArgs { - pub fn new(finalizer: F, merkle_root: Bytes32, state: S) -> Self { - Self { - finalizer, - merkle_root, - state, - } - } -} - -impl ActionLayerArgs { - pub fn curry_tree_hash( - finalizer: TreeHash, - merkle_root: Bytes32, - state_hash: TreeHash, - ) -> TreeHash { - CurriedProgram { - program: ACTION_LAYER_PUZZLE_HASH, - args: ActionLayerArgs::::new(finalizer, merkle_root, state_hash), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct RawActionLayerSolution { - pub puzzles: Vec

, - pub selectors_and_proofs: Vec<(u32, Option)>, - pub solutions: Vec, - pub finalizer_solution: F, -} diff --git a/src/layers/actions.rs b/src/layers/actions.rs deleted file mode 100644 index 3dc52fbf..00000000 --- a/src/layers/actions.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod catalog; -mod delegated_state; -mod reward_distributor; -mod xchandles; - -pub use catalog::*; -pub use delegated_state::*; -pub use reward_distributor::*; -pub use xchandles::*; diff --git a/src/layers/actions/catalog.rs b/src/layers/actions/catalog.rs deleted file mode 100644 index ab90b7fb..00000000 --- a/src/layers/actions/catalog.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod refund; -mod register; - -pub use refund::*; -pub use register::*; diff --git a/src/layers/actions/catalog/refund.rs b/src/layers/actions/catalog/refund.rs deleted file mode 100644 index 9b3e8e52..00000000 --- a/src/layers/actions/catalog/refund.rs +++ /dev/null @@ -1,206 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonStruct, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, CatalogPrecommitValue, CatalogRegistry, CatalogRegistryConstants, CatalogSlotValue, - DefaultCatMakerArgs, PrecommitCoin, PrecommitLayer, Slot, SlotNeigborsInfo, SpendContextExt, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CatalogRefundAction { - pub launcher_id: Bytes32, - pub relative_block_height: u32, - pub payout_puzzle_hash: Bytes32, -} - -impl ToTreeHash for CatalogRefundAction { - fn tree_hash(&self) -> TreeHash { - CatalogRefundActionArgs::curry_tree_hash( - self.launcher_id, - self.relative_block_height, - self.payout_puzzle_hash, - ) - } -} - -impl Action for CatalogRefundAction { - fn from_constants(constants: &CatalogRegistryConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - relative_block_height: constants.relative_block_height, - payout_puzzle_hash: constants.precommit_payout_puzzle_hash, - } - } -} - -impl CatalogRefundAction { - pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(CurriedProgram { - program: ctx.catalog_refund_action_puzzle()?, - args: CatalogRefundActionArgs::new( - self.launcher_id, - self.relative_block_height, - self.payout_puzzle_hash, - ), - } - .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, - ctx: &mut SpendContext, - catalog: &mut CatalogRegistry, - tail_hash: Bytes32, - neighbors: Option, - precommit_coin: PrecommitCoin, - slot: Option>, - ) -> Result { - // calculate announcement - let refund_announcement: Bytes32 = - clvm_tuple!(tail_hash, precommit_coin.value.initial_inner_puzzle_hash) - .tree_hash() - .into(); - let mut refund_announcement: Vec = refund_announcement.to_vec(); - refund_announcement.insert(0, b'$'); - - let secure_conditions = Conditions::new().assert_puzzle_announcement(announcement_id( - catalog.coin.puzzle_hash, - refund_announcement, - )); - - // spend precommit coin - let spender_inner_puzzle_hash: Bytes32 = catalog.info.inner_puzzle_hash().into(); - let initial_inner_puzzle_hash = precommit_coin.value.initial_inner_puzzle_hash; - precommit_coin.spend( - ctx, - 0, // mode 0 = refund - spender_inner_puzzle_hash, - )?; - - // 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)?; - } - - // then, create action spend - let action_solution = CatalogRefundActionSolution { - precommited_cat_maker_reveal: DefaultCatMakerArgs::get_puzzle( - ctx, - precommit_coin.asset_id.tree_hash().into(), - )?, - precommited_cat_maker_hash: DefaultCatMakerArgs::curry_tree_hash( - precommit_coin.asset_id.tree_hash().into(), - ) - .into(), - precommited_cat_maker_solution: (), - tail_hash, - initial_nft_owner_ph: initial_inner_puzzle_hash, - refund_puzzle_hash_hash: precommit_coin.refund_puzzle_hash.tree_hash().into(), - precommit_amount: precommit_coin.coin.amount, - neighbors, - }; - let action_solution = action_solution.to_clvm(ctx)?; - let action_puzzle = self.construct_puzzle(ctx)?; - - catalog.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - Ok(secure_conditions) - } -} - -pub const CATALOG_REFUND_PUZZLE: [u8; 922] = hex!("ff02ffff01ff02ffff03ffff09ff4fffff02ff2effff04ff02ffff04ff81afff8080808080ffff01ff04ff17ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ff8202efff821fef80ff80808080ffff04ffff22ffff09ff77ff8217ef80ffff09ff4fff578080ffff04ffff04ffff04ff28ffff04ffff0effff0124ffff02ff2effff04ff02ffff04ffff04ff8202efff8205ef80ff8080808080ff808080ffff04ffff04ff38ffff04ffff0113ffff04ff80ffff04ffff02ff81afffff04ffff02ff2affff04ff02ffff04ff05ffff04ff820befffff04ffff0bffff0102ff8202efffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ff8205efffff04ff4fff82016f8080ff808080808080ff808080808080ff82016f8080ffff04ff8217efff808080808080ff808080ff8080808080808080ffff01ff088080ff0180ffff04ffff01ffffff33ff3e42ff02ffff02ffff03ff05ffff01ff0bff81fcffff02ff3affff04ff02ffff04ff09ffff04ffff02ff2cffff04ff02ffff04ff0dff80808080ff808080808080ffff0181dc80ff0180ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffffff04ff10ffff04ffff02ff2affff04ff02ffff04ff05ffff04ffff0bffff0101ff0b80ff8080808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff0bff81bcffff02ff3affff04ff02ffff04ff05ffff04ffff02ff2cffff04ff02ffff04ff07ff80808080ff808080808080ff0bff14ffff0bff14ff81dcff0580ffff0bff14ff0bff819c8080ffff02ffff03ff17ffff01ff04ffff02ff3effff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff02ff12ffff04ff02ffff04ff05ffff04ff0bff8080808080ff2f8080ffff012f80ff0180ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff38ffff04ffff0112ffff04ff80ffff04ffff02ff2affff04ff02ffff04ff05ffff04ffff0bffff0101ff0b80ff8080808080ff8080808080ff018080"); - -pub const CATALOG_REFUND_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 3d4aefac7d53b8d36802d5e03aa4a12301fc7eadab60a497311fe7995c2ebf32 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct CatalogRefundActionArgs { - pub precommit_1st_curry_hash: Bytes32, - pub slot_1st_curry_hash: Bytes32, -} - -impl CatalogRefundActionArgs { - pub fn new( - launcher_id: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> Self { - Self { - precommit_1st_curry_hash: PrecommitLayer::<()>::first_curry_hash( - SingletonStruct::new(launcher_id).tree_hash().into(), - relative_block_height, - payout_puzzle_hash, - ) - .into(), - slot_1st_curry_hash: Slot::::first_curry_hash(launcher_id, 0).into(), - } - } -} - -impl CatalogRefundActionArgs { - pub fn curry_tree_hash( - launcher_id: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> TreeHash { - CurriedProgram { - program: CATALOG_REFUND_PUZZLE_HASH, - args: CatalogRefundActionArgs::new( - launcher_id, - relative_block_height, - payout_puzzle_hash, - ), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct CatalogRefundActionSolution { - pub precommited_cat_maker_hash: Bytes32, - pub precommited_cat_maker_reveal: P, - pub precommited_cat_maker_solution: S, - pub tail_hash: Bytes32, - pub initial_nft_owner_ph: Bytes32, - pub refund_puzzle_hash_hash: Bytes32, - pub precommit_amount: u64, - #[clvm(rest)] - pub neighbors: Option, -} diff --git a/src/layers/actions/catalog/register.rs b/src/layers/actions/catalog/register.rs deleted file mode 100644 index cb62ba11..00000000 --- a/src/layers/actions/catalog/register.rs +++ /dev/null @@ -1,315 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, -}; -use chia_puzzle_types::singleton::SingletonStruct; -use chia_puzzles::{ - NFT_OWNERSHIP_LAYER_HASH, NFT_OWNERSHIP_TRANSFER_PROGRAM_ONE_WAY_CLAIM_WITH_ROYALTIES_HASH, - NFT_STATE_LAYER_HASH, SINGLETON_LAUNCHER_HASH, SINGLETON_TOP_LAYER_V1_1_HASH, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, CatalogPrecommitValue, CatalogRegistry, CatalogRegistryConstants, CatalogSlotValue, - DefaultCatMakerArgs, PrecommitCoin, PrecommitLayer, Slot, SpendContextExt, - UniquenessPrelauncher, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct CatalogRegisterAction { - pub launcher_id: Bytes32, - pub royalty_puzzle_hash_hash: Bytes32, - pub trade_price_percentage: u16, - pub relative_block_height: u32, - pub payout_puzzle_hash: Bytes32, -} - -impl ToTreeHash for CatalogRegisterAction { - fn tree_hash(&self) -> TreeHash { - CatalogRegisterActionArgs::curry_tree_hash( - self.launcher_id, - self.royalty_puzzle_hash_hash, - self.trade_price_percentage, - self.relative_block_height, - self.payout_puzzle_hash, - ) - } -} - -impl Action for CatalogRegisterAction { - fn from_constants(constants: &CatalogRegistryConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - royalty_puzzle_hash_hash: constants.royalty_address.tree_hash().into(), - trade_price_percentage: constants.royalty_basis_points, - relative_block_height: constants.relative_block_height, - payout_puzzle_hash: constants.precommit_payout_puzzle_hash, - } - } -} - -impl CatalogRegisterAction { - pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(CurriedProgram { - program: ctx.catalog_register_action_puzzle()?, - args: CatalogRegisterActionArgs::new( - self.launcher_id, - self.royalty_puzzle_hash_hash, - self.trade_price_percentage, - self.relative_block_height, - self.payout_puzzle_hash, - ), - } - .to_clvm(ctx)?) - } - - 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, - ) -> Result<[CatalogSlotValue; 3], DriverError> { - let params = CatalogRegisterActionSolution::::from_clvm(ctx, solution)?; - - Ok([ - CatalogSlotValue::new( - params.left_tail_hash, - params.left_left_tail_hash, - params.tail_hash, - ), - CatalogSlotValue::new( - params.tail_hash, - params.left_tail_hash, - params.right_tail_hash, - ), - CatalogSlotValue::new( - params.right_tail_hash, - params.tail_hash, - params.right_right_tail_hash, - ), - ]) - } - - #[allow(clippy::too_many_arguments)] - pub fn spend( - self, - ctx: &mut SpendContext, - catalog: &mut CatalogRegistry, - tail_hash: Bytes32, - left_slot: Slot, - right_slot: Slot, - precommit_coin: PrecommitCoin, - eve_nft_inner_spend: Spend, - ) -> Result { - // calculate announcement - let register_announcement: Bytes32 = - clvm_tuple!(tail_hash, precommit_coin.value.initial_inner_puzzle_hash) - .tree_hash() - .into(); - let mut register_announcement: Vec = register_announcement.to_vec(); - register_announcement.insert(0, b'r'); - - // spend precommit coin - let initial_inner_puzzle_hash = precommit_coin.value.initial_inner_puzzle_hash; - let my_inner_puzzle_hash = catalog.info.inner_puzzle_hash().into(); - precommit_coin.spend( - ctx, - 1, // mode 1 = register - my_inner_puzzle_hash, - )?; - - // spend uniqueness prelauncher - let uniqueness_prelauncher = - UniquenessPrelauncher::::new(ctx, catalog.coin.coin_id(), tail_hash)?; - let nft_launcher = uniqueness_prelauncher.spend(ctx)?; - - // launch eve nft - let (_, nft) = nft_launcher.mint_eve_nft( - ctx, - initial_inner_puzzle_hash, - (), - ANY_METADATA_UPDATER_HASH.into(), - catalog.info.constants.royalty_address, - catalog.info.constants.royalty_basis_points, - )?; - - // spend nft launcher - 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, - precommit_coin.asset_id.tree_hash().into(), - )?, - cat_maker_solution: (), - tail_hash, - initial_nft_owner_ph: initial_inner_puzzle_hash, - refund_puzzle_hash_hash: precommit_coin.refund_puzzle_hash.tree_hash().into(), - left_tail_hash: left_slot.info.value.asset_id, - left_left_tail_hash: left_slot.info.value.neighbors.left_value, - right_tail_hash: right_slot.info.value.asset_id, - right_right_tail_hash: right_slot.info.value.neighbors.right_value, - my_id: catalog.coin.coin_id(), - }; - let my_solution = my_solution.to_clvm(ctx)?; - let my_puzzle = self.construct_puzzle(ctx)?; - - 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( - Conditions::new().assert_puzzle_announcement(announcement_id( - catalog.coin.puzzle_hash, - register_announcement, - )), - ) - } -} - -pub const ANY_METADATA_UPDATER: [u8; 23] = hex!("ff04ffff04ff0bffff04ff05ff808080ffff01ff808080"); - -pub const ANY_METADATA_UPDATER_HASH: TreeHash = TreeHash::new(hex!( - " - 9f28d55242a3bd2b3661c38ba8647392c26bb86594050ea6d33aad1725ca3eea - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct NftPack { - pub launcher_hash: Bytes32, - pub singleton_mod_hash: Bytes32, - pub state_layer_mod_hash: Bytes32, - pub metadata_updater_hash_hash: Bytes32, - pub nft_ownership_layer_mod_hash: Bytes32, - pub transfer_program_mod_hash: Bytes32, - pub royalty_puzzle_hash_hash: Bytes32, - pub trade_price_percentage: u16, -} - -impl NftPack { - pub fn new(royalty_puzzle_hash_hash: Bytes32, trade_price_percentage: u16) -> Self { - let meta_updater_hash: Bytes32 = ANY_METADATA_UPDATER_HASH.into(); - - Self { - launcher_hash: SINGLETON_LAUNCHER_HASH.into(), - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - state_layer_mod_hash: NFT_STATE_LAYER_HASH.into(), - metadata_updater_hash_hash: meta_updater_hash.tree_hash().into(), - nft_ownership_layer_mod_hash: NFT_OWNERSHIP_LAYER_HASH.into(), - transfer_program_mod_hash: - NFT_OWNERSHIP_TRANSFER_PROGRAM_ONE_WAY_CLAIM_WITH_ROYALTIES_HASH.into(), - royalty_puzzle_hash_hash, - trade_price_percentage, - } - } -} - -pub const CATALOG_REGISTER_PUZZLE: [u8; 1578] = hex!("ff02ffff01ff02ffff03ffff22ffff0aff8205bfff822fbf80ffff0aff82bfbfff8205bf80ffff09ffff02ff2effff04ff02ffff04ff82013fff80808080ff82015f8080ffff01ff04ff5fffff02ff32ffff04ff02ffff04ff05ffff04ff8301ffbfffff04ff820bbfffff04ffff02ff3affff04ff02ffff04ff0bffff04ffff0bffff0101ff8205bf80ff8080808080ffff04ffff04ffff04ff28ffff04ff8301ffbfff808080ffff04ffff04ff24ffff04ffff0effff0172ffff02ff2effff04ff02ffff04ffff04ff8205bfff820bbf80ff8080808080ff808080ffff04ffff02ff3effff04ff02ffff04ff2fffff04ffff02ff2effff04ff02ffff04ffff04ff822fbfffff04ff825fbfff82bfbf8080ff80808080ff8080808080ffff04ffff02ff3effff04ff02ffff04ff2fffff04ffff02ff2effff04ff02ffff04ffff04ff82bfbfffff04ff822fbfff83017fbf8080ff80808080ff8080808080ffff04ffff02ff2affff04ff02ffff04ff2fffff04ffff02ff2effff04ff02ffff04ffff04ff8205bfffff04ff822fbfff82bfbf8080ff80808080ff8080808080ffff04ffff02ff2affff04ff02ffff04ff2fffff04ffff02ff2effff04ff02ffff04ffff04ff822fbfffff04ff825fbfff8205bf8080ff80808080ff8080808080ffff04ffff02ff2affff04ff02ffff04ff2fffff04ffff02ff2effff04ff02ffff04ffff04ff82bfbfffff04ff8205bfff83017fbf8080ff80808080ff8080808080ffff04ffff04ff34ffff04ffff0113ffff04ffff0101ffff04ffff02ff82013fffff04ffff02ff3affff04ff02ffff04ff17ffff04ff8217bfffff04ffff0bffff0102ff8205bfffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ff820bbfffff04ff82015fff8202bf8080ff808080808080ff808080808080ff8202bf8080ffff04ff8201dfff808080808080ff808080808080808080ff808080808080808080ffff01ff088080ff0180ffff04ffff01ffffff40ff4633ffff3e42ff02ff02ffff03ff05ffff01ff0bff81e2ffff02ff26ffff04ff02ffff04ff09ffff04ffff02ff3cffff04ff02ffff04ff0dff80808080ff808080808080ffff0181c280ff0180ffffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ffff04ff38ffff04ff2fffff01ff80808080ffff04ffff02ff36ffff04ff02ffff04ff05ffff04ff17ffff04ffff30ffff30ff0bff2fff8080ff09ffff010180ff808080808080ff5f8080ffff04ff38ffff04ffff02ff3affff04ff02ffff04ff05ffff04ffff0bffff0101ff0b80ff8080808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ff0bff81a2ffff02ff26ffff04ff02ffff04ff05ffff04ffff02ff3cffff04ff02ffff04ff07ff80808080ff808080808080ffffff0bff2cffff0bff2cff81c2ff0580ffff0bff2cff0bff81828080ff04ff10ffff04ffff30ff17ffff02ff3affff04ff02ffff04ff15ffff04ffff02ff2effff04ff02ffff04ffff04ff15ffff04ff17ff098080ff80808080ffff04ffff02ff3affff04ff02ffff04ff2dffff04ffff0bffff0101ff2d80ffff04ff8182ffff04ff5dffff04ffff02ff3affff04ff02ffff04ff81bdffff04ffff0bffff0101ff81bd80ffff04ff8182ffff04ffff02ff3affff04ff02ffff04ff82017dffff04ffff02ff2effff04ff02ffff04ffff04ff15ffff04ff17ff098080ff80808080ffff04ff8202fdffff04ffff0bffff0101ff8205fd80ff80808080808080ffff04ff0bff8080808080808080ff8080808080808080ff808080808080ffff010180ff808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff34ffff04ffff0112ffff04ff80ffff04ffff02ff3affff04ff02ffff04ff05ffff04ffff0bffff0101ff0b80ff8080808080ff8080808080ff018080"); - -pub const CATALOG_REGISTER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 028d83ae6f75c1a1fa40ebc68efb7c983257d0cc3fc7161a3418f63cca934e20 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct CatalogRegisterActionArgs { - pub nft_pack: NftPack, - pub uniqueness_prelauncher_1st_curry_hash: Bytes32, - pub precommit_1st_curry_hash: Bytes32, - pub slot_1st_curry_hash: Bytes32, -} - -impl CatalogRegisterActionArgs { - pub fn new( - launcher_id: Bytes32, - royalty_puzzle_hash_hash: Bytes32, - trade_price_percentage: u16, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> Self { - Self { - nft_pack: NftPack::new(royalty_puzzle_hash_hash, trade_price_percentage), - uniqueness_prelauncher_1st_curry_hash: UniquenessPrelauncher::<()>::first_curry_hash() - .into(), - precommit_1st_curry_hash: PrecommitLayer::<()>::first_curry_hash( - SingletonStruct::new(launcher_id).tree_hash().into(), - relative_block_height, - payout_puzzle_hash, - ) - .into(), - slot_1st_curry_hash: Slot::::first_curry_hash(launcher_id, 0).into(), - } - } -} - -impl CatalogRegisterActionArgs { - pub fn curry_tree_hash( - launcher_id: Bytes32, - royalty_puzzle_hash_hash: Bytes32, - trade_price_percentage: u16, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> TreeHash { - CurriedProgram { - program: CATALOG_REGISTER_PUZZLE_HASH, - args: CatalogRegisterActionArgs::new( - launcher_id, - royalty_puzzle_hash_hash, - trade_price_percentage, - relative_block_height, - payout_puzzle_hash, - ), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct CatalogRegisterActionSolution { - pub cat_maker_reveal: P, - pub cat_maker_solution: S, - pub tail_hash: Bytes32, - pub initial_nft_owner_ph: Bytes32, - pub refund_puzzle_hash_hash: Bytes32, - pub left_tail_hash: Bytes32, - pub left_left_tail_hash: Bytes32, - pub right_tail_hash: Bytes32, - pub right_right_tail_hash: Bytes32, - #[clvm(rest)] - pub my_id: Bytes32, -} diff --git a/src/layers/actions/delegated_state.rs b/src/layers/actions/delegated_state.rs deleted file mode 100644 index 383676ec..00000000 --- a/src/layers/actions/delegated_state.rs +++ /dev/null @@ -1,127 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::{Bytes32, Coin}, - puzzles::singleton::SingletonStruct, -}; -use chia_puzzles::SINGLETON_TOP_LAYER_V1_1_HASH; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::Conditions, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; -use hex_literal::hex; - -use crate::{ - Action, CatalogRegistry, CatalogRegistryConstants, SpendContextExt, XchandlesConstants, - XchandlesRegistry, -}; - -pub struct DelegatedStateAction { - pub other_launcher_id: Bytes32, -} - -impl ToTreeHash for DelegatedStateAction { - fn tree_hash(&self) -> TreeHash { - DelegatedStateActionArgs::curry_tree_hash(self.other_launcher_id) - } -} - -impl Action for DelegatedStateAction { - fn from_constants(constants: &CatalogRegistryConstants) -> Self { - Self { - other_launcher_id: constants.price_singleton_launcher_id, - } - } -} - -impl Action for DelegatedStateAction { - fn from_constants(constants: &XchandlesConstants) -> Self { - Self { - other_launcher_id: constants.price_singleton_launcher_id, - } - } -} - -impl DelegatedStateAction { - pub fn curry_tree_hash(price_singleton_launcher_id: Bytes32) -> TreeHash { - DelegatedStateActionArgs::curry_tree_hash(price_singleton_launcher_id) - } - - pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(CurriedProgram { - program: ctx.delegated_state_action_puzzle()?, - args: DelegatedStateActionArgs::new(self.other_launcher_id), - } - .to_clvm(ctx)?) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - my_coin: Coin, - new_state: S, - other_singleton_inner_puzzle_hash: Bytes32, - ) -> Result<(Conditions, Spend), DriverError> - where - S: ToClvm, - { - let state = new_state.to_clvm(ctx)?; - let my_solution = DelegatedStateActionSolution:: { - new_state: state, - other_singleton_inner_puzzle_hash, - } - .to_clvm(ctx)?; - let my_puzzle = self.construct_puzzle(ctx)?; - - let message: Bytes32 = ctx.tree_hash(state).into(); - let conds = Conditions::new().send_message( - 18, - message.into(), - vec![ctx.alloc(&my_coin.puzzle_hash)?], - ); - Ok((conds, Spend::new(my_puzzle, my_solution))) - } -} - -pub const DELEGATED_STATE_ACTION_PUZZLE: [u8; 387] = hex!("ff02ffff01ff04ffff04ff27ff4f80ffff04ffff04ff08ffff04ffff0112ffff04ffff02ff0effff04ff02ffff04ff4fff80808080ffff04ffff0bff2affff0bff0cffff0bff0cff32ff0580ffff0bff0cffff0bff3affff0bff0cffff0bff0cff32ff0b80ffff0bff0cffff0bff3affff0bff0cffff0bff0cff32ff6f80ffff0bff0cff32ff22808080ff22808080ff22808080ff8080808080ff808080ffff04ffff01ffff4302ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff0effff04ff02ffff04ff09ff80808080ffff02ff0effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080"); - -pub const DELEGATED_STATE_ACTION_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 145e54a297466100f202690d58bded6074834e2ae8cd4dfbcf66e33bb8b77c05 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct DelegatedStateActionArgs { - pub singleton_mod_hash: Bytes32, - pub other_singleton_struct_hash: Bytes32, -} - -impl DelegatedStateActionArgs { - pub fn new(other_launcher_id: Bytes32) -> Self { - Self { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - other_singleton_struct_hash: SingletonStruct::new(other_launcher_id).tree_hash().into(), - } - } -} - -impl DelegatedStateActionArgs { - pub fn curry_tree_hash(other_launcher_id: Bytes32) -> TreeHash { - CurriedProgram { - program: DELEGATED_STATE_ACTION_PUZZLE_HASH, - args: DelegatedStateActionArgs::new(other_launcher_id), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct DelegatedStateActionSolution { - pub new_state: S, - #[clvm(rest)] - pub other_singleton_inner_puzzle_hash: Bytes32, -} diff --git a/src/layers/actions/reward_distributor.rs b/src/layers/actions/reward_distributor.rs deleted file mode 100644 index 2b94af3b..00000000 --- a/src/layers/actions/reward_distributor.rs +++ /dev/null @@ -1,21 +0,0 @@ -mod add_entry; -mod add_incentives; -mod commit_incentives; -mod initiate_payout; -mod new_epoch; -mod remove_entry; -mod stake; -mod sync; -mod unstake; -mod withdraw_incentives; - -pub use add_entry::*; -pub use add_incentives::*; -pub use commit_incentives::*; -pub use initiate_payout::*; -pub use new_epoch::*; -pub use remove_entry::*; -pub use stake::*; -pub use sync::*; -pub use unstake::*; -pub use withdraw_incentives::*; diff --git a/src/layers/actions/reward_distributor/add_entry.rs b/src/layers/actions/reward_distributor/add_entry.rs deleted file mode 100644 index c6d010cf..00000000 --- a/src/layers/actions/reward_distributor/add_entry.rs +++ /dev/null @@ -1,165 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonStruct, -}; -use chia_puzzles::SINGLETON_TOP_LAYER_V1_1_HASH; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::Conditions, -}; -use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, RewardDistributor, RewardDistributorConstants, RewardDistributorEntrySlotValue, - RewardDistributorSlotNonce, RewardDistributorState, Slot, SpendContextExt, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDistributorAddEntryAction { - pub launcher_id: Bytes32, - pub manager_launcher_id: Bytes32, - pub max_second_offset: u64, -} - -impl ToTreeHash for RewardDistributorAddEntryAction { - fn tree_hash(&self) -> TreeHash { - RewardDistributorAddEntryActionArgs::curry_tree_hash( - self.launcher_id, - self.manager_launcher_id, - self.max_second_offset, - ) - } -} - -impl Action for RewardDistributorAddEntryAction { - fn from_constants(constants: &RewardDistributorConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - manager_launcher_id: constants.manager_or_collection_did_launcher_id, - max_second_offset: constants.max_seconds_offset, - } - } -} - -impl RewardDistributorAddEntryAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.reward_distributor_add_entry_action_puzzle()?, - args: RewardDistributorAddEntryActionArgs::new( - self.launcher_id, - self.manager_launcher_id, - self.max_second_offset, - ), - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - pub fn created_slot_value( - ctx: &SpendContext, - state: &RewardDistributorState, - solution: NodePtr, - ) -> Result { - let solution = ctx.extract::(solution)?; - - Ok(RewardDistributorEntrySlotValue { - payout_puzzle_hash: solution.entry_payout_puzzle_hash, - initial_cumulative_payout: state.round_reward_info.cumulative_payout, - shares: solution.entry_shares, - }) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - distributor: &mut RewardDistributor, - payout_puzzle_hash: Bytes32, - shares: u64, - manager_singleton_inner_puzzle_hash: Bytes32, - ) -> 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(); - add_entry_message.insert(0, b'a'); - let add_entry_message = Conditions::new().send_message( - 18, - add_entry_message.into(), - vec![ctx.alloc(&distributor.coin.puzzle_hash)?], - ); - - // spend self - let action_solution = ctx.alloc(&RewardDistributorAddEntryActionSolution { - manager_singleton_inner_puzzle_hash, - entry_payout_puzzle_hash: payout_puzzle_hash, - entry_shares: shares, - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - Ok(add_entry_message) - } -} - -pub const REWARD_DISTRIBUTOR_ADD_ENTRY_PUZZLE: [u8; 590] = hex!("ff02ffff01ff04ffff04ff819fffff04ff82015fffff04ffff10ff8202dfff8203bf80ffff04ff8205dfffff04ff820bdfff808080808080ffff04ffff04ff1cffff04ffff0112ffff04ffff0effff0161ffff0bffff0102ffff0bffff0101ff8202bf80ffff0bffff0101ff8203bf808080ffff04ffff0bff56ffff0bff0affff0bff0aff66ff0580ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ff0b80ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ff82013f80ffff0bff0aff66ff46808080ff46808080ff46808080ff8080808080ffff04ffff02ff1effff04ff02ffff04ff17ffff04ffff0bffff0102ffff0bffff0101ff8202bf80ffff0bffff0102ffff0bffff0101ff8209df80ffff0bffff0101ff8203bf808080ffff04ff8202bfff808080808080ffff04ffff04ff08ffff04ffff10ff8213dfff2f80ff808080ff8080808080ffff04ffff01ffff55ff3343ff02ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff14ffff04ffff0bff56ffff0bff0affff0bff0aff66ff0580ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ffff0bffff0101ff0b8080ffff0bff0aff66ff46808080ff46808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ff018080"); - -pub const REWARD_DISTRIBUTOR_ADD_ENTRY_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 90eef279e5389305ed3ff673fa5c766258e5ea04ff7abcec1ed551060bca8aa0 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct RewardDistributorAddEntryActionArgs { - pub singleton_mod_hash: Bytes32, - pub manager_singleton_struct_hash: Bytes32, - pub entry_slot_1st_curry_hash: Bytes32, - pub max_second_offset: u64, -} - -impl RewardDistributorAddEntryActionArgs { - pub fn new(launcher_id: Bytes32, manager_launcher_id: Bytes32, max_second_offset: u64) -> Self { - Self { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - manager_singleton_struct_hash: SingletonStruct::new(manager_launcher_id) - .tree_hash() - .into(), - entry_slot_1st_curry_hash: Slot::<()>::first_curry_hash( - launcher_id, - RewardDistributorSlotNonce::ENTRY.to_u64(), - ) - .into(), - max_second_offset, - } - } -} - -impl RewardDistributorAddEntryActionArgs { - pub fn curry_tree_hash( - launcher_id: Bytes32, - manager_launcher_id: Bytes32, - max_second_offset: u64, - ) -> TreeHash { - CurriedProgram { - program: REWARD_DISTRIBUTOR_ADD_ENTRY_PUZZLE_HASH, - args: RewardDistributorAddEntryActionArgs::new( - launcher_id, - manager_launcher_id, - max_second_offset, - ), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorAddEntryActionSolution { - pub manager_singleton_inner_puzzle_hash: Bytes32, - pub entry_payout_puzzle_hash: Bytes32, - #[clvm(rest)] - pub entry_shares: u64, -} diff --git a/src/layers/actions/reward_distributor/add_incentives.rs b/src/layers/actions/reward_distributor/add_incentives.rs deleted file mode 100644 index 29f33463..00000000 --- a/src/layers/actions/reward_distributor/add_incentives.rs +++ /dev/null @@ -1,116 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{Action, RewardDistributor, RewardDistributorConstants, SpendContextExt}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDistributorAddIncentivesAction { - pub fee_payout_puzzle_hash: Bytes32, - pub fee_bps: u64, -} - -impl ToTreeHash for RewardDistributorAddIncentivesAction { - fn tree_hash(&self) -> TreeHash { - RewardDistributorAddIncentivesActionArgs::curry_tree_hash( - self.fee_payout_puzzle_hash, - self.fee_bps, - ) - } -} - -impl Action for RewardDistributorAddIncentivesAction { - fn from_constants(constants: &RewardDistributorConstants) -> Self { - Self { - fee_payout_puzzle_hash: constants.fee_payout_puzzle_hash, - fee_bps: constants.fee_bps, - } - } -} - -impl RewardDistributorAddIncentivesAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.reward_distributor_add_incentives_action_puzzle()?, - args: RewardDistributorAddIncentivesActionArgs { - fee_payout_puzzle_hash: self.fee_payout_puzzle_hash, - fee_bps: self.fee_bps, - }, - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - distributor: &mut RewardDistributor, - amount: u64, - ) -> Result { - 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 = - clvm_tuple!(amount, my_state.round_time_info.epoch_end) - .tree_hash() - .to_vec(); - add_incentives_announcement.insert(0, b'i'); - let add_incentives_announcement = Conditions::new().assert_puzzle_announcement( - announcement_id(distributor.coin.puzzle_hash, add_incentives_announcement), - ); - - // spend self - let action_solution = ctx.alloc(&RewardDistributorAddIncentivesActionSolution { - amount, - manager_fee: amount * distributor.info.constants.fee_bps / 10000, - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - Ok(add_incentives_announcement) - } -} - -pub const REWARD_DISTRIBUTOR_ADD_INCENTIVES_PUZZLE: [u8; 261] = hex!("ff02ffff01ff02ffff03ffff22ffff15ff8206f7ff8204f780ffff15ff4fff8080ffff09ff6fffff05ffff14ffff12ff4fff0b80ffff0182271080808080ffff01ff04ffff04ff27ffff04ffff10ff57ffff11ff4fff6f8080ffff04ff81b7ffff04ffff04ff820277ffff10ff820377ffff11ff4fff6f808080ffff04ff8202f7ff808080808080ffff04ffff04ff06ffff04ffff0effff0169ffff0bffff0102ffff0bffff0101ff4f80ffff0bffff0101ff8206f7808080ff808080ffff04ffff04ffff0181d6ffff04ff04ffff04ff05ffff04ff6fffff04ffff04ff05ff8080ff808080808080ff80808080ffff01ff088080ff0180ffff04ffff01ff333eff018080"); - -pub const REWARD_DISTRIBUTOR_ADD_INCENTIVES_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - eb999158d98d1013b072b7443acca10a1bdfef2eab824ea25f0d71e2e30cec7e - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct RewardDistributorAddIncentivesActionArgs { - pub fee_payout_puzzle_hash: Bytes32, - pub fee_bps: u64, -} - -impl RewardDistributorAddIncentivesActionArgs { - pub fn curry_tree_hash(fee_payout_puzzle_hash: Bytes32, fee_bps: u64) -> TreeHash { - CurriedProgram { - program: REWARD_DISTRIBUTOR_ADD_INCENTIVES_PUZZLE_HASH, - args: RewardDistributorAddIncentivesActionArgs { - fee_payout_puzzle_hash, - fee_bps, - }, - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorAddIncentivesActionSolution { - pub amount: u64, - #[clvm(rest)] - pub manager_fee: u64, -} diff --git a/src/layers/actions/reward_distributor/commit_incentives.rs b/src/layers/actions/reward_distributor/commit_incentives.rs deleted file mode 100644 index 608c48c8..00000000 --- a/src/layers/actions/reward_distributor/commit_incentives.rs +++ /dev/null @@ -1,224 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, RewardDistributor, RewardDistributorCommitmentSlotValue, RewardDistributorConstants, - RewardDistributorRewardSlotValue, RewardDistributorSlotNonce, Slot, SpendContextExt, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDistributorCommitIncentivesAction { - pub launcher_id: Bytes32, - pub epoch_seconds: u64, -} - -impl ToTreeHash for RewardDistributorCommitIncentivesAction { - fn tree_hash(&self) -> TreeHash { - RewardDistributorCommitIncentivesActionArgs::curry_tree_hash( - self.launcher_id, - self.epoch_seconds, - ) - } -} - -impl Action for RewardDistributorCommitIncentivesAction { - fn from_constants(constants: &RewardDistributorConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - epoch_seconds: constants.epoch_seconds, - } - } -} - -impl RewardDistributorCommitIncentivesAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.reward_distributor_commit_incentives_action_puzzle()?, - args: RewardDistributorCommitIncentivesActionArgs::new( - self.launcher_id, - self.epoch_seconds, - ), - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - pub fn created_slot_values( - ctx: &SpendContext, - epoch_seconds: u64, - solution: NodePtr, - ) -> Result< - ( - RewardDistributorCommitmentSlotValue, - Vec, - ), - DriverError, - > { - let solution = ctx.extract::(solution)?; - - let commitment_slot_value = RewardDistributorCommitmentSlotValue { - epoch_start: solution.epoch_start, - clawback_ph: solution.clawback_ph, - rewards: solution.rewards_to_add, - }; - - let mut reward_slot_values: Vec = vec![]; - - if solution.slot_epoch_time == solution.epoch_start { - reward_slot_values.push(RewardDistributorRewardSlotValue { - epoch_start: solution.epoch_start, - next_epoch_initialized: solution.slot_next_epoch_initialized, - rewards: solution.slot_total_rewards + solution.rewards_to_add, - }) - } else { - reward_slot_values.push(RewardDistributorRewardSlotValue { - epoch_start: solution.slot_epoch_time, - next_epoch_initialized: true, - rewards: solution.slot_total_rewards, - }); - reward_slot_values.push(RewardDistributorRewardSlotValue { - epoch_start: solution.epoch_start, - next_epoch_initialized: false, - rewards: solution.rewards_to_add, - }); - - let mut start_epoch_time = solution.slot_epoch_time + epoch_seconds; - let end_epoch_time = solution.epoch_start; - while end_epoch_time > start_epoch_time { - reward_slot_values.push(RewardDistributorRewardSlotValue { - epoch_start: start_epoch_time, - next_epoch_initialized: true, - rewards: 0, - }); - - start_epoch_time += epoch_seconds; - } - } - - Ok((commitment_slot_value, reward_slot_values)) - } - - 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)] - pub fn spend( - self, - ctx: &mut SpendContext, - distributor: &mut RewardDistributor, - reward_slot: Slot, - epoch_start: u64, - clawback_ph: Bytes32, - rewards_to_add: u64, - ) -> Result { - let reward_slot = distributor.actual_reward_slot_value(reward_slot); - - let new_commitment_slot_value = RewardDistributorCommitmentSlotValue { - epoch_start, - clawback_ph, - rewards: rewards_to_add, - }; - - // calculate announcement - let mut commit_reward_announcement: Vec = - new_commitment_slot_value.tree_hash().to_vec(); - commit_reward_announcement.insert(0, b'c'); - - // spend self - let action_solution = ctx.alloc(&RewardDistributorCommitIncentivesActionSolution { - slot_epoch_time: reward_slot.info.value.epoch_start, - slot_next_epoch_initialized: reward_slot.info.value.next_epoch_initialized, - slot_total_rewards: reward_slot.info.value.rewards, - epoch_start, - clawback_ph, - rewards_to_add, - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - // spend reward slot - reward_slot.spend(ctx, distributor.info.inner_puzzle_hash().into())?; - - 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, - )), - ) - } -} - -pub const REWARD_DISTRIBUTOR_COMMIT_INCENTIVES_PUZZLE: [u8; 1209] = hex!("ff02ffff01ff02ffff03ffff22ffff20ffff15ff820defff8205df8080ffff15ff820fdfff808080ffff01ff04ffff04ff4fffff04ffff10ff81afff820fdf80ffff04ff82016fffff04ff8202efffff04ff8205efff808080808080ffff02ff12ffff04ff02ffff04ff0bffff04ffff0bffff0102ffff0bffff0101ff8205df80ffff0bffff0102ffff0bffff0101ff820bdf80ffff0bffff0101ff820fdf808080ffff04ff820bdfffff04ffff04ffff02ff3effff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff819fffff04ff82015fffff04ff8202dfff808080808080ff8080808080ffff02ffff03ffff09ff8205dfff819f80ffff01ff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff819fffff04ff82015fffff04ffff10ff8202dfff820fdf80ff808080808080ffff04ffff0bffff0101ff819f80ff808080808080ff8080ffff01ff02ffff03ff82015fffff01ff0880ffff01ff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff819fffff04ffff0101ffff04ff8202dfff808080808080ffff04ffff0bffff0101ff819f80ff808080808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff8205dfffff04ff80ffff04ff820fdfff808080808080ffff04ffff0bffff0101ff8205df80ff808080808080ffff02ff2effff04ff02ffff04ff05ffff04ff17ffff04ffff10ff819fff1780ffff04ff8205dfff80808080808080808080ff018080ff018080ff8080808080808080ffff01ff088080ff0180ffff04ffff01ffffff333eff42ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffffff04ffff04ff18ffff04ffff0effff0163ff0b80ff808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ff0bffff04ff17ff808080808080ff2f8080ff04ff10ffff04ffff0bff81bcffff0bff2cffff0bff2cff81dcff0580ffff0bff2cffff0bff81fcffff0bff2cffff0bff2cff81dcffff0bffff0101ff0b8080ffff0bff2cff81dcff819c808080ff819c808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ffff0bffff0102ffff0bffff0101ff0580ffff0bffff0102ffff0bffff0101ff0b80ffff0bffff0101ff17808080ffff02ffff03ffff09ff17ff2f80ff80ffff01ff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff17ffff01ff01ff8080808080ffff04ffff0bffff0101ff1780ff808080808080ffff02ff2effff04ff02ffff04ff05ffff04ff0bffff04ffff10ff17ff0b80ffff04ff2fff808080808080808080ff0180ff04ff14ffff04ffff0112ffff04ff80ffff04ffff0bff81bcffff0bff2cffff0bff2cff81dcff0580ffff0bff2cffff0bff81fcffff0bff2cffff0bff2cff81dcffff0bffff0101ff0b8080ffff0bff2cff81dcff819c808080ff819c808080ff8080808080ff018080"); - -pub const REWARD_DISTRIBUTOR_COMMIT_INCENTIVES_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 2c49bc36a8ec2f2703fddf92e4ae3dcbed849bb07cf6d3264f6714d04413acc0 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct RewardDistributorCommitIncentivesActionArgs { - pub reward_slot_1st_curry_hash: Bytes32, - pub commitment_slot_1st_curry_hash: Bytes32, - pub epoch_seconds: u64, -} - -impl RewardDistributorCommitIncentivesActionArgs { - pub fn new(launcher_id: Bytes32, epoch_seconds: u64) -> Self { - Self { - reward_slot_1st_curry_hash: Slot::<()>::first_curry_hash( - launcher_id, - RewardDistributorSlotNonce::REWARD.to_u64(), - ) - .into(), - commitment_slot_1st_curry_hash: Slot::<()>::first_curry_hash( - launcher_id, - RewardDistributorSlotNonce::COMMITMENT.to_u64(), - ) - .into(), - epoch_seconds, - } - } -} - -impl RewardDistributorCommitIncentivesActionArgs { - pub fn curry_tree_hash(launcher_id: Bytes32, epoch_seconds: u64) -> TreeHash { - CurriedProgram { - program: REWARD_DISTRIBUTOR_COMMIT_INCENTIVES_PUZZLE_HASH, - args: RewardDistributorCommitIncentivesActionArgs::new(launcher_id, epoch_seconds), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorCommitIncentivesActionSolution { - pub slot_epoch_time: u64, - pub slot_next_epoch_initialized: bool, - pub slot_total_rewards: u64, - pub epoch_start: u64, - pub clawback_ph: Bytes32, - #[clvm(rest)] - pub rewards_to_add: u64, -} diff --git a/src/layers/actions/reward_distributor/initiate_payout.rs b/src/layers/actions/reward_distributor/initiate_payout.rs deleted file mode 100644 index d7af0ca7..00000000 --- a/src/layers/actions/reward_distributor/initiate_payout.rs +++ /dev/null @@ -1,183 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, RewardDistributor, RewardDistributorConstants, RewardDistributorEntrySlotValue, - RewardDistributorSlotNonce, RewardDistributorState, Slot, SpendContextExt, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDistributorInitiatePayoutAction { - pub launcher_id: Bytes32, - pub payout_threshold: u64, -} - -impl ToTreeHash for RewardDistributorInitiatePayoutAction { - fn tree_hash(&self) -> TreeHash { - RewardDistributorInitiatePayoutAction::curry_tree_hash( - self.launcher_id, - self.payout_threshold, - ) - } -} - -impl Action for RewardDistributorInitiatePayoutAction { - fn from_constants(constants: &RewardDistributorConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - payout_threshold: constants.payout_threshold, - } - } -} - -impl RewardDistributorInitiatePayoutAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.reward_distributor_initiate_payout_action_puzzle()?, - args: RewardDistributorInitiatePayoutActionArgs::new( - self.launcher_id, - self.payout_threshold, - ), - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - pub fn created_slot_value( - ctx: &SpendContext, - current_state: &RewardDistributorState, - solution: NodePtr, - ) -> Result { - let solution = ctx.extract::(solution)?; - - Ok(RewardDistributorEntrySlotValue { - payout_puzzle_hash: solution.entry_payout_puzzle_hash, - initial_cumulative_payout: current_state.round_reward_info.cumulative_payout, - shares: solution.entry_shares, - }) - } - - 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, - }) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - distributor: &mut RewardDistributor, - entry_slot: Slot, - ) -> 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 - - entry_slot.info.value.initial_cumulative_payout); - - // this announcement should be asserted to ensure everything goes according to plan - let initiate_payout_announcement: Bytes32 = - clvm_tuple!(entry_slot.info.value.payout_puzzle_hash, withdrawal_amount) - .tree_hash() - .into(); - let mut initiate_payout_announcement: Vec = initiate_payout_announcement.to_vec(); - initiate_payout_announcement.insert(0, b'p'); - - // spend self - let action_solution = ctx.alloc(&RewardDistributorInitiatePayoutActionSolution { - entry_payout_amount: withdrawal_amount, - entry_payout_puzzle_hash: entry_slot.info.value.payout_puzzle_hash, - entry_initial_cumulative_payout: entry_slot.info.value.initial_cumulative_payout, - entry_shares: entry_slot.info.value.shares, - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - // spend entry slot - entry_slot.spend(ctx, distributor.info.inner_puzzle_hash().into())?; - - 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, - )), - withdrawal_amount, - )) - } -} - -impl RewardDistributorInitiatePayoutAction { - pub fn curry_tree_hash(launcher_id: Bytes32, payout_threshold: u64) -> TreeHash { - CurriedProgram { - program: REWARD_DISTRIBUTOR_INITIATE_PAYOUT_PUZZLE_HASH, - args: RewardDistributorInitiatePayoutActionArgs::new(launcher_id, payout_threshold), - } - .tree_hash() - } -} - -pub const REWARD_DISTRIBUTOR_INITIATE_PAYOUT_PUZZLE: [u8; 724] = hex!("ff02ffff01ff02ffff03ffff22ffff09ffff12ffff11ff820277ff82016f80ff8201ef80ff4f80ffff20ffff15ff0bff4f808080ffff01ff04ffff04ff27ffff04ffff11ff57ff4f80ff778080ffff04ffff02ff1effff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff81afffff04ff82016fffff04ff8201efff808080808080ff8080808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ffff02ff16ffff04ff02ffff04ff81afffff04ff820277ffff04ff8201efff808080808080ffff04ff81afff808080808080ffff04ffff04ff18ffff04ffff0effff0170ffff0bffff0102ffff0bffff0101ff81af80ffff0bffff0101ff4f808080ff808080ffff04ffff04ffff0181d6ffff04ff10ffff04ff81afffff04ff4fffff04ffff04ff81afff8080ff808080808080ff808080808080ffff01ff088080ff0180ffff04ffff01ffffff333eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff10ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ffff0bffff0102ffff0bffff0101ff0580ffff0bffff0102ffff0bffff0101ff0b80ffff0bffff0101ff17808080ff04ff14ffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ff8080808080ff018080"); - -pub const REWARD_DISTRIBUTOR_INITIATE_PAYOUT_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - ae41bf077dfbfdb93069d841dac67f8856a5637e45cefc9e1ecd00e0025266a9 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct RewardDistributorInitiatePayoutActionArgs { - pub entry_slot_1st_curry_hash: Bytes32, - pub payout_threshold: u64, -} - -impl RewardDistributorInitiatePayoutActionArgs { - pub fn new(launcher_id: Bytes32, payout_threshold: u64) -> Self { - Self { - entry_slot_1st_curry_hash: Slot::<()>::first_curry_hash( - launcher_id, - RewardDistributorSlotNonce::ENTRY.to_u64(), - ) - .into(), - payout_threshold, - } - } -} - -impl RewardDistributorInitiatePayoutActionArgs { - pub fn curry_tree_hash(launcher_id: Bytes32, payout_threshold: u64) -> TreeHash { - CurriedProgram { - program: REWARD_DISTRIBUTOR_INITIATE_PAYOUT_PUZZLE_HASH, - args: RewardDistributorInitiatePayoutActionArgs::new(launcher_id, payout_threshold), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorInitiatePayoutActionSolution { - pub entry_payout_amount: u64, - pub entry_payout_puzzle_hash: Bytes32, - pub entry_initial_cumulative_payout: u64, - #[clvm(rest)] - pub entry_shares: u64, -} diff --git a/src/layers/actions/reward_distributor/new_epoch.rs b/src/layers/actions/reward_distributor/new_epoch.rs deleted file mode 100644 index da16cc85..00000000 --- a/src/layers/actions/reward_distributor/new_epoch.rs +++ /dev/null @@ -1,202 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, RewardDistributor, RewardDistributorConstants, RewardDistributorRewardSlotValue, - RewardDistributorSlotNonce, Slot, SpendContextExt, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDistributorNewEpochAction { - pub launcher_id: Bytes32, - pub fee_payout_puzzle_hash: Bytes32, - pub fee_bps: u64, - pub epoch_seconds: u64, -} - -impl ToTreeHash for RewardDistributorNewEpochAction { - fn tree_hash(&self) -> TreeHash { - RewardDistributorNewEpochAction::curry_tree_hash( - self.launcher_id, - self.fee_payout_puzzle_hash, - self.fee_bps, - self.epoch_seconds, - ) - } -} - -impl Action for RewardDistributorNewEpochAction { - fn from_constants(constants: &RewardDistributorConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - fee_payout_puzzle_hash: constants.fee_payout_puzzle_hash, - fee_bps: constants.fee_bps, - epoch_seconds: constants.epoch_seconds, - } - } -} - -impl RewardDistributorNewEpochAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.reward_distributor_new_epoch_action_puzzle()?, - args: RewardDistributorNewEpochActionArgs::new( - self.launcher_id, - self.fee_payout_puzzle_hash, - self.fee_bps, - self.epoch_seconds, - ), - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - pub fn created_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 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( - self, - ctx: &mut SpendContext, - distributor: &mut RewardDistributor, - reward_slot: Slot, - ) -> Result<(Conditions, u64), DriverError> { - // also returns fee - 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 { - reward_slot.info.value.rewards - } else { - 0 - }; - let fee = epoch_total_rewards * distributor.info.constants.fee_bps / 10000; - - // calculate announcement needed to ensure everything's happening as expected - let mut new_epoch_announcement: Vec = - my_state.round_time_info.epoch_end.tree_hash().to_vec(); - new_epoch_announcement.insert(0, b'e'); - let new_epoch_conditions = Conditions::new() - .assert_puzzle_announcement(announcement_id( - distributor.coin.puzzle_hash, - new_epoch_announcement, - )) - .assert_concurrent_puzzle(reward_slot.coin.puzzle_hash); - - // spend self - let action_solution = ctx.alloc(&RewardDistributorNewEpochActionSolution { - slot_epoch_time: reward_slot.info.value.epoch_start, - slot_next_epoch_initialized: reward_slot.info.value.next_epoch_initialized, - slot_total_rewards: reward_slot.info.value.rewards, - epoch_total_rewards, - fee, - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - // spend slot - reward_slot.spend(ctx, distributor.info.inner_puzzle_hash().into())?; - - distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - Ok((new_epoch_conditions, fee)) - } -} - -impl RewardDistributorNewEpochAction { - pub fn curry_tree_hash( - launcher_id: Bytes32, - fee_payout_puzzle_hash: Bytes32, - fee_bps: u64, - epoch_seconds: u64, - ) -> TreeHash { - CurriedProgram { - program: REWARD_DISTRIBUTOR_NEW_EPOCH_PUZZLE_HASH, - args: RewardDistributorNewEpochActionArgs::new( - launcher_id, - fee_payout_puzzle_hash, - fee_bps, - epoch_seconds, - ), - } - .tree_hash() - } -} - -pub const REWARD_DISTRIBUTOR_NEW_EPOCH_PUZZLE: [u8; 839] = hex!("ff02ffff01ff02ffff03ffff22ffff09ff8213dfff821bdf80ffff09ffff05ffff14ffff12ff820bbfff1780ffff018227108080ff820fbf80ffff21ffff22ffff09ff82013fff821bdf80ffff09ff820bbfff8205bf8080ffff22ffff15ff821bdfff82013f80ffff20ff8202bf80ffff09ff820bbfff8080808080ffff01ff04ffff04ff819fffff04ffff11ff82015fff820fbf80ffff04ff8202dfffff04ffff04ff8209dfffff10ff820ddfffff11ff820bbfff820fbf808080ffff04ffff04ff821bdfffff10ff821bdfff2f8080ff808080808080ffff04ffff04ff14ffff04ffff0effff0165ffff0bffff0101ff821bdf8080ff808080ffff04ffff04ffff0181d6ffff04ff08ffff04ff0bffff04ff820fbfffff04ffff04ff0bff8080ff808080808080ffff04ffff02ff1effff04ff02ffff04ff05ffff04ffff0bffff0102ffff0bffff0101ff82013f80ffff0bffff0102ffff0bffff0101ff8202bf80ffff0bffff0101ff8205bf808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff05ffff04ffff0bffff0102ffff0bffff0101ff82013f80ffff0bffff0102ffff0bffff0101ff8202bf80ffff0bffff0101ff8205bf808080ffff04ffff0bffff0101ff82013f80ff808080808080ff808080808080ffff01ff088080ff0180ffff04ffff01ffff33ff3e42ffff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff08ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ff04ff1cffff04ffff0112ffff04ff80ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ff8080808080ff018080"); - -pub const REWARD_DISTRIBUTOR_NEW_EPOCH_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - ac01b2b3c3c137fa08662cf51e7eb28a238de85dbb8759050f39ef3dc461bfb9 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct RewardDistributorNewEpochActionArgs { - pub reward_slot_1st_curry_hash: Bytes32, - pub fee_payout_puzzle_hash: Bytes32, - pub fee_bps: u64, - pub epoch_seconds: u64, -} - -impl RewardDistributorNewEpochActionArgs { - pub fn new( - launcher_id: Bytes32, - fee_payout_puzzle_hash: Bytes32, - fee_bps: u64, - epoch_seconds: u64, - ) -> Self { - Self { - reward_slot_1st_curry_hash: Slot::<()>::first_curry_hash( - launcher_id, - RewardDistributorSlotNonce::REWARD.to_u64(), - ) - .into(), - fee_payout_puzzle_hash, - fee_bps, - epoch_seconds, - } - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorNewEpochActionSolution { - pub slot_epoch_time: u64, - pub slot_next_epoch_initialized: bool, - pub slot_total_rewards: u64, - pub epoch_total_rewards: u64, - #[clvm(rest)] - pub fee: u64, -} diff --git a/src/layers/actions/reward_distributor/remove_entry.rs b/src/layers/actions/reward_distributor/remove_entry.rs deleted file mode 100644 index 9ca84c72..00000000 --- a/src/layers/actions/reward_distributor/remove_entry.rs +++ /dev/null @@ -1,189 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonStruct, -}; -use chia_puzzles::SINGLETON_TOP_LAYER_V1_1_HASH; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::Conditions, -}; -use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, RewardDistributor, RewardDistributorConstants, RewardDistributorEntrySlotValue, - RewardDistributorSlotNonce, Slot, SpendContextExt, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDistributorRemoveEntryAction { - pub launcher_id: Bytes32, - pub manager_launcher_id: Bytes32, - pub max_seconds_offset: u64, -} - -impl ToTreeHash for RewardDistributorRemoveEntryAction { - fn tree_hash(&self) -> TreeHash { - RewardDistributorRemoveEntryActionArgs::curry_tree_hash( - self.launcher_id, - self.manager_launcher_id, - self.max_seconds_offset, - ) - } -} - -impl Action for RewardDistributorRemoveEntryAction { - fn from_constants(constants: &RewardDistributorConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - manager_launcher_id: constants.manager_or_collection_did_launcher_id, - max_seconds_offset: constants.max_seconds_offset, - } - } -} - -impl RewardDistributorRemoveEntryAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.reward_distributor_remove_entry_action_puzzle()?, - args: RewardDistributorRemoveEntryActionArgs::new( - self.launcher_id, - self.manager_launcher_id, - self.max_seconds_offset, - ), - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - distributor: &mut RewardDistributor, - entry_slot: Slot, - 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!( - entry_slot.info.value.payout_puzzle_hash, - entry_slot.info.value.shares - ) - .tree_hash() - .into(); - let mut remove_entry_message: Vec = remove_entry_message.to_vec(); - remove_entry_message.insert(0, b'r'); - - let remove_entry_conditions = Conditions::new() - .send_message( - 18, - remove_entry_message.into(), - vec![ctx.alloc(&distributor.coin.puzzle_hash)?], - ) - .assert_concurrent_puzzle(entry_slot.coin.puzzle_hash); - - // spend self - let entry_payout_amount = entry_slot.info.value.shares - * (my_state.round_reward_info.cumulative_payout - - entry_slot.info.value.initial_cumulative_payout); - let action_solution = ctx.alloc(&RewardDistributorRemoveEntryActionSolution { - manager_singleton_inner_puzzle_hash, - entry_payout_amount, - entry_payout_puzzle_hash: entry_slot.info.value.payout_puzzle_hash, - entry_initial_cumulative_payout: entry_slot.info.value.initial_cumulative_payout, - entry_shares: entry_slot.info.value.shares, - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - // spend entry slot - entry_slot.spend(ctx, distributor.info.inner_puzzle_hash().into())?; - - distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - Ok((remove_entry_conditions, entry_payout_amount)) - } - - 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, - }) - } -} - -pub const REWARD_DISTRIBUTOR_REMOVE_ENTRY_PUZZLE: [u8; 671] = hex!("ff02ffff01ff02ffff03ffff09ff8202bfffff12ffff11ff8209dfff820bbf80ff820fbf8080ffff01ff04ffff04ff819fffff04ffff11ff82015fff8202bf80ffff04ffff11ff8202dfff820fbf80ff8203df808080ffff04ffff04ff1cffff04ffff0112ffff04ffff0effff0172ffff0bffff0102ffff0bffff0101ff8205bf80ffff0bffff0101ff820fbf808080ffff04ffff0bff56ffff0bff1affff0bff1aff66ff0580ffff0bff1affff0bff76ffff0bff1affff0bff1aff66ff0b80ffff0bff1affff0bff76ffff0bff1affff0bff1aff66ff82013f80ffff0bff1aff66ff46808080ff46808080ff46808080ff8080808080ffff04ffff04ff08ffff04ffff10ff8213dfff2f80ff808080ffff04ffff02ff1effff04ff02ffff04ff17ffff04ffff0bffff0102ffff0bffff0101ff8205bf80ffff0bffff0102ffff0bffff0101ff820bbf80ffff0bffff0101ff820fbf808080ff8080808080ffff04ffff04ffff0181d6ffff04ff14ffff04ff8205bfffff04ff8202bfffff04ffff04ff8205bfff8080ff808080808080ff808080808080ffff01ff088080ff0180ffff04ffff01ffff55ff3343ffff4202ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff12ffff04ffff0112ffff04ff80ffff04ffff0bff56ffff0bff1affff0bff1aff66ff0580ffff0bff1affff0bff76ffff0bff1affff0bff1aff66ffff0bffff0101ff0b8080ffff0bff1aff66ff46808080ff46808080ff8080808080ff018080"); - -pub const REWARD_DISTRIBUTOR_REMOVE_ENTRY_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 4cb611d7003037ead2cf96a08989f0f063db05dfc548fc68cee23fbcd6887bed - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct RewardDistributorRemoveEntryActionArgs { - pub singleton_mod_hash: Bytes32, - pub manager_singleton_struct_hash: Bytes32, - pub entry_slot_1st_curry_hash: Bytes32, - pub max_seconds_offset: u64, -} - -impl RewardDistributorRemoveEntryActionArgs { - pub fn new( - launcher_id: Bytes32, - manager_launcher_id: Bytes32, - max_seconds_offset: u64, - ) -> Self { - Self { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - manager_singleton_struct_hash: SingletonStruct::new(manager_launcher_id) - .tree_hash() - .into(), - entry_slot_1st_curry_hash: Slot::<()>::first_curry_hash( - launcher_id, - RewardDistributorSlotNonce::ENTRY.to_u64(), - ) - .into(), - max_seconds_offset, - } - } -} - -impl RewardDistributorRemoveEntryActionArgs { - pub fn curry_tree_hash( - launcher_id: Bytes32, - manager_launcher_id: Bytes32, - max_seconds_offset: u64, - ) -> TreeHash { - CurriedProgram { - program: REWARD_DISTRIBUTOR_REMOVE_ENTRY_PUZZLE_HASH, - args: RewardDistributorRemoveEntryActionArgs::new( - launcher_id, - manager_launcher_id, - max_seconds_offset, - ), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorRemoveEntryActionSolution { - pub manager_singleton_inner_puzzle_hash: Bytes32, - pub entry_payout_amount: u64, - pub entry_payout_puzzle_hash: Bytes32, - pub entry_initial_cumulative_payout: u64, - #[clvm(rest)] - pub entry_shares: u64, -} diff --git a/src/layers/actions/reward_distributor/stake.rs b/src/layers/actions/reward_distributor/stake.rs deleted file mode 100644 index dc0c2cff..00000000 --- a/src/layers/actions/reward_distributor/stake.rs +++ /dev/null @@ -1,260 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonStruct, -}; -use chia_puzzle_types::{ - nft::NftRoyaltyTransferPuzzleArgs, - offer::{NotarizedPayment, Payment}, - LineageProof, -}; -use chia_puzzles::{NFT_OWNERSHIP_LAYER_HASH, NFT_STATE_LAYER_HASH, SETTLEMENT_PAYMENT_HASH}; -use chia_wallet_sdk::{ - driver::{Asset, DriverError, HashedPtr, Nft, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, P2DelegatedBySingletonLayerArgs, RewardDistributor, RewardDistributorConstants, - RewardDistributorEntrySlotValue, RewardDistributorSlotNonce, RewardDistributorState, Slot, - SpendContextExt, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDistributorStakeAction { - pub launcher_id: Bytes32, - pub did_launcher_id: Bytes32, - pub max_second_offset: u64, -} - -impl ToTreeHash for RewardDistributorStakeAction { - fn tree_hash(&self) -> TreeHash { - RewardDistributorStakeActionArgs::curry_tree_hash( - self.launcher_id, - self.did_launcher_id, - self.max_second_offset, - ) - } -} - -impl Action for RewardDistributorStakeAction { - fn from_constants(constants: &RewardDistributorConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - did_launcher_id: constants.manager_or_collection_did_launcher_id, - max_second_offset: constants.max_seconds_offset, - } - } -} - -impl RewardDistributorStakeAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.reward_distributor_stake_action_puzzle()?, - args: RewardDistributorStakeActionArgs::new( - self.launcher_id, - self.did_launcher_id, - self.max_second_offset, - ), - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - pub fn created_slot_value( - ctx: &SpendContext, - state: &RewardDistributorState, - solution: NodePtr, - ) -> Result { - let solution = ctx.extract::(solution)?; - - Ok(RewardDistributorEntrySlotValue { - payout_puzzle_hash: solution.entry_custody_puzzle_hash, - initial_cumulative_payout: state.round_reward_info.cumulative_payout, - shares: 1, - }) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - distributor: &mut RewardDistributor, - current_nft: Nft, - nft_launcher_proof: NftLauncherProof, - entry_custody_puzzle_hash: Bytes32, - ) -> 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 - let my_p2_treehash: TreeHash = - RewardDistributorStakeActionArgs::my_p2_puzzle_hash(self.launcher_id).into(); - let payment_puzzle_hash: Bytes32 = CurriedProgram { - program: NONCE_WRAPPER_PUZZLE_HASH, - args: NonceWrapperArgs:: { - nonce: entry_custody_puzzle_hash, - inner_puzzle: my_p2_treehash, - }, - } - .tree_hash() - .into(); - let notarized_payment = NotarizedPayment { - nonce: clvm_tuple!(ephemeral_counter.tree_hash(), my_id) - .tree_hash() - .into(), - payments: vec![Payment::new( - payment_puzzle_hash, - 1, - ctx.hint(payment_puzzle_hash)?, - )], - }; - - // spend self - 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, - nft_metadata_hash: nft.info.metadata.tree_hash().into(), - nft_metadata_updater_hash_hash: nft - .info - .metadata_updater_puzzle_hash - .tree_hash() - .into(), - nft_transfer_porgram_hash: NftRoyaltyTransferPuzzleArgs::curry_tree_hash( - nft.info.launcher_id, - nft.info.royalty_puzzle_hash, - nft.info.royalty_basis_points, - ) - .into(), - nft_launcher_proof, - entry_custody_puzzle_hash, - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - 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, - nft.child(payment_puzzle_hash, None, nft.info.metadata, nft.amount()), - )) - } -} - -pub const REWARD_DISTRIBUTOR_STAKE_PUZZLE: [u8; 1170] = hex!("ff02ffff01ff04ffff04ffff10ff8209ffffff010180ffff04ff8215ffffff04ffff10ff822dffffff010180ffff04ff825dffffff04ff82bdffff808080808080ffff02ff3cffff04ff02ffff04ffff0bffff02ff3affff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ffff04ff09ffff04ffff02ff36ffff04ff02ffff04ffff30ff83047bffffff02ff3affff04ff02ffff04ff09ffff04ffff02ff3effff04ff02ffff04ff05ff80808080ffff04ff830a7bffff808080808080ff83167bff80ffff04ff83037bffff8080808080ff1d8080ff80808080ffff04ffff02ff3affff04ff02ffff04ff0bffff04ffff0bffff0101ff0b80ffff04ff822bffffff04ff825bffffff04ffff02ff3affff04ff02ffff04ff17ffff04ffff0bffff0101ff1780ffff04ff8192ffff04ff82bbffffff04ff2fff8080808080808080ff8080808080808080ff808080808080ffff02ff3effff04ff02ffff04ffff04ffff02ff3effff04ff02ffff04ffff04ff8209ffff8213ff80ff80808080ffff04ffff02ff2effff04ff02ffff04ffff02ff3affff04ff02ffff04ff5fffff04ffff0bffff0101ff8301fbff80ffff04ff81bfff808080808080ff80808080ff808080ff8080808080ffff04ffff04ffff04ff28ffff04ff8213ffff808080ffff04ffff02ff2affff04ff02ffff04ff82017fffff04ffff02ff3effff04ff02ffff04ffff04ff8301fbffffff04ff829dffffff01018080ff80808080ffff04ff8301fbffff808080808080ffff04ffff04ff10ffff04ffff10ff83013dffff8202ff80ff808080ff80808080ff808080808080ffff04ffff01ffffff55ff463fffff333eff02ff04ffff04ff38ffff04ff05ff808080ffff04ffff04ff34ffff04ff05ff808080ff0b8080ffffffff02ffff03ff05ffff01ff0bff81f2ffff02ff26ffff04ff02ffff04ff09ffff04ffff02ff22ffff04ff02ffff04ff0dff80808080ff808080808080ffff0181d280ff0180ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff24ffff04ffff02ff3affff04ff02ffff04ff05ffff04ffff0bffff0101ff0b80ff8080808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ff0bff81b2ffff02ff26ffff04ff02ffff04ff05ffff04ffff02ff22ffff04ff02ffff04ff07ff80808080ff808080808080ffffff0bff2cffff0bff2cff81d2ff0580ffff0bff2cff0bff81928080ff02ffff03ff0bffff01ff30ffff02ff36ffff04ff02ffff04ff05ffff04ff1bff8080808080ff23ff3380ffff010580ff0180ffff04ff05ffff04ffff0101ffff04ffff04ff05ff8080ff80808080ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff3effff04ff02ffff04ff09ff80808080ffff02ff3effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080"); - -pub const REWARD_DISTRIBUTOR_STAKE_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - b092c8a9a97f69a906230663bffaf52a6d435ee57fd93a5e84862a1f935ea101 - " -)); - -// run '(mod (NONCE INNER_PUZZLE . inner_solution) (a INNER_PUZZLE inner_solution))' -d -pub const NONCE_WRAPPER_PUZZLE: [u8; 7] = hex!("ff02ff05ff0780"); -pub const NONCE_WRAPPER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - "847d971ef523417d555ea9854b1612837155d34d453298defcd310774305f657" -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct NonceWrapperArgs { - pub nonce: N, - pub inner_puzzle: I, -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct RewardDistributorStakeActionArgs { - pub did_singleton_struct: SingletonStruct, - pub nft_state_layer_mod_hash: Bytes32, - pub nft_ownership_layer_mod_hash: Bytes32, - pub offer_mod_hash: Bytes32, - pub nonce_mod_hash: Bytes32, - pub my_p2_puzzle_hash: Bytes32, - pub entry_slot_1st_curry_hash: Bytes32, - pub max_second_offset: u64, -} - -impl RewardDistributorStakeActionArgs { - pub fn new(launcher_id: Bytes32, did_launcher_id: Bytes32, max_second_offset: u64) -> Self { - Self { - did_singleton_struct: SingletonStruct::new(did_launcher_id), - nft_state_layer_mod_hash: NFT_STATE_LAYER_HASH.into(), - nft_ownership_layer_mod_hash: NFT_OWNERSHIP_LAYER_HASH.into(), - offer_mod_hash: SETTLEMENT_PAYMENT_HASH.into(), - nonce_mod_hash: NONCE_WRAPPER_PUZZLE_HASH.into(), - my_p2_puzzle_hash: Self::my_p2_puzzle_hash(launcher_id), - entry_slot_1st_curry_hash: Slot::<()>::first_curry_hash( - launcher_id, - RewardDistributorSlotNonce::ENTRY.to_u64(), - ) - .into(), - max_second_offset, - } - } - - pub fn my_p2_puzzle_hash(launcher_id: Bytes32) -> Bytes32 { - P2DelegatedBySingletonLayerArgs::curry_tree_hash( - SingletonStruct::new(launcher_id).tree_hash().into(), - 1, - ) - .into() - } -} - -impl RewardDistributorStakeActionArgs { - pub fn curry_tree_hash( - launcher_id: Bytes32, - did_launcher_id: Bytes32, - max_second_offset: u64, - ) -> TreeHash { - CurriedProgram { - program: REWARD_DISTRIBUTOR_STAKE_PUZZLE_HASH, - args: RewardDistributorStakeActionArgs::new( - launcher_id, - did_launcher_id, - max_second_offset, - ), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct IntermediaryCoinProof { - pub full_puzzle_hash: Bytes32, - #[clvm(rest)] - pub amount: u64, -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct NftLauncherProof { - pub did_proof: LineageProof, - #[clvm(rest)] - pub intermediary_coin_proofs: Vec, -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorStakeActionSolution { - pub my_id: Bytes32, - pub nft_metadata_hash: Bytes32, - pub nft_metadata_updater_hash_hash: Bytes32, - pub nft_transfer_porgram_hash: Bytes32, - pub nft_launcher_proof: NftLauncherProof, - #[clvm(rest)] - pub entry_custody_puzzle_hash: Bytes32, -} diff --git a/src/layers/actions/reward_distributor/sync.rs b/src/layers/actions/reward_distributor/sync.rs deleted file mode 100644 index 29d65543..00000000 --- a/src/layers/actions/reward_distributor/sync.rs +++ /dev/null @@ -1,78 +0,0 @@ -use chia::clvm_utils::{ToTreeHash, TreeHash}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{Action, RewardDistributor, RewardDistributorConstants, SpendContextExt}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDistributorSyncAction {} - -impl ToTreeHash for RewardDistributorSyncAction { - fn tree_hash(&self) -> TreeHash { - RewardDistributorSyncActionArgs::curry_tree_hash() - } -} - -impl Action for RewardDistributorSyncAction { - fn from_constants(_constants: &RewardDistributorConstants) -> Self { - Self {} - } -} - -impl RewardDistributorSyncAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - ctx.reward_distributor_sync_action_puzzle() - } - - pub fn spend( - self, - ctx: &mut SpendContext, - distributor: &mut RewardDistributor, - update_time: u64, - ) -> Result { - // calculate announcement needed to ensure everything's happening as expected - 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() - .to_vec(); - new_epoch_announcement.insert(0, b's'); - let new_epoch_conditions = Conditions::new().assert_puzzle_announcement(announcement_id( - distributor.coin.puzzle_hash, - new_epoch_announcement, - )); - - // spend self - let action_solution = ctx.alloc(&RewardDistributorSyncActionSolution { update_time })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - Ok(new_epoch_conditions) - } -} - -pub const REWARD_DISTRIBUTOR_SYNC_PUZZLE: [u8; 308] = hex!("ff02ffff01ff02ffff03ffff22ffff20ffff15ff13ff8201bd8080ffff15ff13ff82013d8080ffff01ff04ffff04ff09ffff04ff15ffff04ff2dffff04ffff02ff0effff04ff02ffff04ff2dffff04ff819dffff04ff81ddffff04ffff02ffff03ffff15ff2dff8080ffff01ff05ffff14ffff12ff81ddffff11ff13ff82013d8080ffff12ff2dffff11ff8201bdff82013d80808080ff8080ff0180ff80808080808080ffff04ffff04ff13ff8201bd80ff808080808080ffff04ffff04ff04ffff04ff13ff808080ffff04ffff04ff0affff04ffff0effff0173ffff0bffff0102ffff0bffff0101ff1380ffff0bffff0101ff8201bd808080ff808080ff80808080ffff01ff088080ff0180ffff04ffff01ff51ff3eff04ffff10ff0bff2f80ffff11ff17ffff12ff2fff05808080ff018080"); - -pub const REWARD_DISTRIBUTOR_SYNC_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 9e2707ff8a4f5b52feb763a80c5c23073e588172c6220b4146f72b484c064546 - " -)); - -pub struct RewardDistributorSyncActionArgs {} -impl RewardDistributorSyncActionArgs { - pub fn curry_tree_hash() -> TreeHash { - REWARD_DISTRIBUTOR_SYNC_PUZZLE_HASH - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[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 deleted file mode 100644 index 89df0e6b..00000000 --- a/src/layers/actions/reward_distributor/unstake.rs +++ /dev/null @@ -1,233 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonStruct, -}; -use chia_puzzle_types::nft::NftRoyaltyTransferPuzzleArgs; -use chia_puzzles::{ - NFT_OWNERSHIP_LAYER_HASH, NFT_STATE_LAYER_HASH, SINGLETON_LAUNCHER_HASH, - SINGLETON_TOP_LAYER_V1_1_HASH, -}; -use chia_wallet_sdk::{ - driver::{DriverError, HashedPtr, Layer, Nft, Spend, SpendContext}, - types::Conditions, -}; -use clvm_traits::{clvm_quote, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, NonceWrapperArgs, P2DelegatedBySingletonLayer, P2DelegatedBySingletonLayerArgs, - P2DelegatedBySingletonLayerSolution, RewardDistributor, RewardDistributorConstants, - RewardDistributorEntrySlotValue, RewardDistributorSlotNonce, Slot, SpendContextExt, - NONCE_WRAPPER_PUZZLE_HASH, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDistributorUnstakeAction { - pub launcher_id: Bytes32, - pub max_second_offset: u64, -} - -impl ToTreeHash for RewardDistributorUnstakeAction { - fn tree_hash(&self) -> TreeHash { - RewardDistributorUnstakeActionArgs::curry_tree_hash( - self.launcher_id, - self.max_second_offset, - ) - } -} - -impl Action for RewardDistributorUnstakeAction { - fn from_constants(constants: &RewardDistributorConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - max_second_offset: constants.max_seconds_offset, - } - } -} - -impl RewardDistributorUnstakeAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.reward_distributor_unstake_action_puzzle()?, - args: RewardDistributorUnstakeActionArgs::new(self.launcher_id, self.max_second_offset), - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - pub fn spent_slot_value( - ctx: &SpendContext, - solution: NodePtr, - ) -> Result { - let solution = ctx.extract::(solution)?; - - Ok(RewardDistributorEntrySlotValue { - payout_puzzle_hash: solution.entry_custody_puzzle_hash, - initial_cumulative_payout: solution.entry_initial_cumulative_payout, - shares: 1, - }) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - distributor: &mut RewardDistributor, - entry_slot: Slot, - 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; - let unstake_message: Vec = unstake_message.to_vec(); - - let remove_entry_conditions = Conditions::new() - .send_message( - 18, - unstake_message.into(), - vec![ctx.alloc(&distributor.coin.puzzle_hash)?], - ) - .assert_concurrent_puzzle(entry_slot.coin.puzzle_hash); - - // spend self - let entry_payout_amount = entry_slot.info.value.shares - * (my_state.round_reward_info.cumulative_payout - - entry_slot.info.value.initial_cumulative_payout); - let action_solution = ctx.alloc(&RewardDistributorUnstakeActionSolution { - nft_launcher_id: locked_nft.info.launcher_id, - nft_parent_id: locked_nft.coin.parent_coin_info, - nft_metadata_hash: locked_nft.info.metadata.tree_hash().into(), - nft_metadata_updater_hash_hash: locked_nft - .info - .metadata_updater_puzzle_hash - .tree_hash() - .into(), - nft_transfer_porgram_hash: NftRoyaltyTransferPuzzleArgs::curry_tree_hash( - locked_nft.info.launcher_id, - locked_nft.info.royalty_puzzle_hash, - locked_nft.info.royalty_basis_points, - ) - .into(), - entry_initial_cumulative_payout: entry_slot.info.value.initial_cumulative_payout, - entry_custody_puzzle_hash: entry_slot.info.value.payout_puzzle_hash, - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - let registry_inner_puzzle_hash = distributor.info.inner_puzzle_hash(); - distributor.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - - // spend NFT - let my_p2 = P2DelegatedBySingletonLayer::new( - SingletonStruct::new(self.launcher_id).tree_hash().into(), - 1, - ); - let nft_inner_puzzle = my_p2.construct_puzzle(ctx)?; - // don't forget about the nonce wrapper! - let nft_inner_puzzle = CurriedProgram { - program: ctx.nonce_wrapper_puzzle()?, - args: NonceWrapperArgs:: { - nonce: entry_slot.info.value.payout_puzzle_hash, - inner_puzzle: nft_inner_puzzle, - }, - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm)?; - - 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, - hint, - )))?; - let nft_inner_solution = my_p2.construct_solution( - ctx, - P2DelegatedBySingletonLayerSolution:: { - singleton_inner_puzzle_hash: registry_inner_puzzle_hash.into(), - delegated_puzzle, - delegated_solution: NodePtr::NIL, - }, - )?; - - 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())?; - - Ok((remove_entry_conditions, entry_payout_amount)) - } -} - -pub const REWARD_DISTRIBUTOR_UNSTAKE_PUZZLE: [u8; 1031] = hex!("ff02ffff01ff04ffff04ff8209ffffff04ffff11ff8215ffffff11ff829dffff8302fbff8080ffff04ffff11ff822dffffff010180ff823dff808080ffff04ffff04ff2cffff04ffff0117ffff04ffff02ff2effff04ff02ffff04ffff04ffff0101ffff04ffff04ff18ffff04ff8303fbffffff04ffff0101ffff04ffff04ff8303fbffff8080ff8080808080ff808080ff80808080ffff04ffff30ff822bffffff02ff3affff04ff02ffff04ff05ffff04ffff02ff2effff04ff02ffff04ffff04ff05ffff04ff8213ffff0b8080ff80808080ffff04ffff02ff3affff04ff02ffff04ff17ffff04ffff0bffff0101ff1780ffff04ff825bffffff04ff82bbffffff04ffff02ff3affff04ff02ffff04ff2fffff04ffff0bffff0101ff2f80ffff04ff818affff04ff83017bffffff04ffff02ff3affff04ff02ffff04ff5fffff04ffff0bffff0101ff8303fbff80ffff04ff81bfff808080808080ff8080808080808080ff8080808080808080ff808080808080ffff010180ff8080808080ffff04ffff04ff14ffff04ffff0112ffff04ff8213ffffff04ff8303fbffff8080808080ffff04ffff04ff10ffff04ffff10ff83013dffff8202ff80ff808080ffff04ffff02ff3effff04ff02ffff04ff82017fffff04ffff02ff2effff04ff02ffff04ffff04ff8303fbffffff04ff8302fbffffff01018080ff80808080ff8080808080ffff04ffff04ffff0181d6ffff04ff18ffff04ff8303fbffffff04ffff11ff829dffff8302fbff80ffff04ffff04ff8303fbffff8080ff808080808080ff80808080808080ffff04ffff01ffffff5533ff43ff4202ffffff02ffff03ff05ffff01ff0bff81eaffff02ff16ffff04ff02ffff04ff09ffff04ffff02ff12ffff04ff02ffff04ff0dff80808080ff808080808080ffff0181ca80ff0180ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff0bff81aaffff02ff16ffff04ff02ffff04ff05ffff04ffff02ff12ffff04ff02ffff04ff07ff80808080ff808080808080ffff0bff3cffff0bff3cff81caff0580ffff0bff3cff0bff818a8080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff2cffff04ffff0112ffff04ff80ffff04ffff02ff3affff04ff02ffff04ff05ffff04ffff0bffff0101ff0b80ff8080808080ff8080808080ff018080"); - -pub const REWARD_DISTRIBUTOR_UNSTAKE_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 5ea6690901ecc9932c463041090e37afe56c9be3e8a6ff0cbb37a7ad157802e2 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct RewardDistributorUnstakeActionArgs { - pub singleton_mod_hash: Bytes32, - pub singleton_launcher_hash: Bytes32, - pub nft_state_layer_mod_hash: Bytes32, - pub nft_ownership_layer_mod_hash: Bytes32, - pub nonce_mod_hash: Bytes32, - pub my_p2_puzzle_hash: Bytes32, - pub entry_slot_1st_curry_hash: Bytes32, - pub max_second_offset: u64, -} - -impl RewardDistributorUnstakeActionArgs { - pub fn new(launcher_id: Bytes32, max_second_offset: u64) -> Self { - Self { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - singleton_launcher_hash: SINGLETON_LAUNCHER_HASH.into(), - nft_state_layer_mod_hash: NFT_STATE_LAYER_HASH.into(), - nft_ownership_layer_mod_hash: NFT_OWNERSHIP_LAYER_HASH.into(), - nonce_mod_hash: NONCE_WRAPPER_PUZZLE_HASH.into(), - my_p2_puzzle_hash: Self::my_p2_puzzle_hash(launcher_id), - entry_slot_1st_curry_hash: Slot::<()>::first_curry_hash( - launcher_id, - RewardDistributorSlotNonce::ENTRY.to_u64(), - ) - .into(), - max_second_offset, - } - } - - pub fn my_p2_puzzle_hash(launcher_id: Bytes32) -> Bytes32 { - P2DelegatedBySingletonLayerArgs::curry_tree_hash( - SingletonStruct::new(launcher_id).tree_hash().into(), - 1, - ) - .into() - } -} - -impl RewardDistributorUnstakeActionArgs { - pub fn curry_tree_hash(launcher_id: Bytes32, max_second_offset: u64) -> TreeHash { - CurriedProgram { - program: REWARD_DISTRIBUTOR_UNSTAKE_PUZZLE_HASH, - args: RewardDistributorUnstakeActionArgs::new(launcher_id, max_second_offset), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorUnstakeActionSolution { - pub nft_launcher_id: Bytes32, - pub nft_parent_id: Bytes32, - pub nft_metadata_hash: Bytes32, - pub nft_metadata_updater_hash_hash: Bytes32, - pub nft_transfer_porgram_hash: Bytes32, - pub entry_initial_cumulative_payout: u64, - #[clvm(rest)] - pub entry_custody_puzzle_hash: Bytes32, -} diff --git a/src/layers/actions/reward_distributor/withdraw_incentives.rs b/src/layers/actions/reward_distributor/withdraw_incentives.rs deleted file mode 100644 index 349a85c6..00000000 --- a/src/layers/actions/reward_distributor/withdraw_incentives.rs +++ /dev/null @@ -1,202 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::{Bytes, Bytes32}, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::Conditions, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, RewardDistributor, RewardDistributorCommitmentSlotValue, RewardDistributorConstants, - RewardDistributorRewardSlotValue, RewardDistributorSlotNonce, Slot, SpendContextExt, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct RewardDistributorWithdrawIncentivesAction { - pub launcher_id: Bytes32, - pub withdrawal_share_bps: u64, -} - -impl ToTreeHash for RewardDistributorWithdrawIncentivesAction { - fn tree_hash(&self) -> TreeHash { - RewardDistributorWithdrawIncentivesActionArgs::curry_tree_hash( - self.launcher_id, - self.withdrawal_share_bps, - ) - } -} - -impl Action for RewardDistributorWithdrawIncentivesAction { - fn from_constants(constants: &RewardDistributorConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - withdrawal_share_bps: constants.withdrawal_share_bps, - } - } -} - -impl RewardDistributorWithdrawIncentivesAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.reward_distributor_withdraw_incentives_action_puzzle()?, - args: RewardDistributorWithdrawIncentivesActionArgs::new( - self.launcher_id, - self.withdrawal_share_bps, - ), - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - 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, - solution: NodePtr, - ) -> Result< - ( - RewardDistributorRewardSlotValue, - RewardDistributorCommitmentSlotValue, - ), - DriverError, - > { - let solution = - ctx.extract::(solution)?; - - 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 commitment_slot_value = RewardDistributorCommitmentSlotValue { - epoch_start: solution.reward_slot_epoch_time, - clawback_ph: solution.clawback_ph, - rewards: solution.committed_value, - }; - - Ok((old_reward_slot_value, commitment_slot_value)) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - distributor: &mut RewardDistributor, - commitment_slot: Slot, - reward_slot: Slot, - ) -> 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; - - // calculate message that the withdrawer needs to send - let withdraw_incentives_conditions = Conditions::new() - .send_message( - 18, - Bytes::new(Vec::new()), - vec![ctx.alloc(&distributor.coin.puzzle_hash)?], - ) - .assert_concurrent_puzzle(commitment_slot.coin.puzzle_hash); - - // spend self - let action_solution = ctx.alloc(&RewardDistributorWithdrawIncentivesActionSolution { - reward_slot_epoch_time: reward_slot.info.value.epoch_start, - reward_slot_next_epoch_initialized: reward_slot.info.value.next_epoch_initialized, - reward_slot_total_rewards: reward_slot.info.value.rewards, - clawback_ph: commitment_slot.info.value.clawback_ph, - committed_value: commitment_slot.info.value.rewards, - withdrawal_share, - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - 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, withdrawal_share)) - } -} - -pub const REWARD_DISTRIBUTOR_WITHDRAW_INCENTIVES_PUZZLE: [u8; 805] = hex!("ff02ffff01ff04ffff04ff4fffff04ffff11ff81afffff02ffff03ffff09ff820fdfffff05ffff14ffff12ff17ff820bdf80ffff01822710808080ffff01820fdfffff01ff088080ff018080ff81ef8080ffff04ffff04ff10ffff04ff819fff808080ffff04ffff02ff3effff04ff02ffff04ff05ffff04ffff02ff2effff04ff02ffff04ff819fffff04ff82015fffff04ff8202dfff808080808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff05ffff04ffff02ff2effff04ff02ffff04ff819fffff04ff82015fffff04ffff11ff8202dfff820fdf80ff808080808080ffff04ffff0bffff0101ff819f80ff808080808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ff819fffff04ff8205dfffff04ff820bdfff808080808080ff8080808080ffff04ffff04ff14ffff04ffff0112ffff04ff80ffff04ff8205dfff8080808080ffff04ffff04ffff0181d6ffff04ff18ffff04ff8205dfffff04ff820fdfffff04ffff04ff8205dfff8080ff808080808080ff8080808080808080ffff04ffff01ffffff5533ff4342ffff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff18ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ffff04ff80ffff04ffff04ff17ff8080ff8080808080ffff0bffff0102ffff0bffff0101ff0580ffff0bffff0102ffff0bffff0101ff0b80ffff0bffff0101ff17808080ff04ff1cffff04ffff0112ffff04ff80ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ff8080808080ff018080"); - -pub const REWARD_DISTRIBUTOR_WITHDRAW_INCENTIVES_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - bb70077a60a28a4e262b286af3253ac52f977e1f9413b142a2efd83044a041f0 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct RewardDistributorWithdrawIncentivesActionArgs { - pub reward_slot_1st_curry_hash: Bytes32, - pub commitment_slot_1st_curry_hash: Bytes32, - pub withdrawal_share_bps: u64, -} - -impl RewardDistributorWithdrawIncentivesActionArgs { - pub fn new(launcher_id: Bytes32, withdrawal_share_bps: u64) -> Self { - Self { - reward_slot_1st_curry_hash: Slot::<()>::first_curry_hash( - launcher_id, - RewardDistributorSlotNonce::REWARD.to_u64(), - ) - .into(), - commitment_slot_1st_curry_hash: Slot::<()>::first_curry_hash( - launcher_id, - RewardDistributorSlotNonce::COMMITMENT.to_u64(), - ) - .into(), - withdrawal_share_bps, - } - } -} - -impl RewardDistributorWithdrawIncentivesActionArgs { - pub fn curry_tree_hash(launcher_id: Bytes32, withdrawal_share_bps: u64) -> TreeHash { - CurriedProgram { - program: REWARD_DISTRIBUTOR_WITHDRAW_INCENTIVES_PUZZLE_HASH, - args: RewardDistributorWithdrawIncentivesActionArgs::new( - launcher_id, - withdrawal_share_bps, - ), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorWithdrawIncentivesActionSolution { - pub reward_slot_epoch_time: u64, - pub reward_slot_next_epoch_initialized: bool, - pub reward_slot_total_rewards: u64, - pub clawback_ph: Bytes32, - pub committed_value: u64, - #[clvm(rest)] - pub withdrawal_share: u64, -} diff --git a/src/layers/actions/xchandles.rs b/src/layers/actions/xchandles.rs deleted file mode 100644 index db5d5f98..00000000 --- a/src/layers/actions/xchandles.rs +++ /dev/null @@ -1,13 +0,0 @@ -mod expire; -mod extend; -mod oracle; -mod refund; -mod register; -mod update; - -pub use expire::*; -pub use extend::*; -pub use oracle::*; -pub use refund::*; -pub use register::*; -pub use update::*; diff --git a/src/layers/actions/xchandles/expire.rs b/src/layers/actions/xchandles/expire.rs deleted file mode 100644 index 69c1572b..00000000 --- a/src/layers/actions/xchandles/expire.rs +++ /dev/null @@ -1,472 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonStruct, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, DefaultCatMakerArgs, PrecommitCoin, PrecommitLayer, Slot, SlotNeigborsInfo, - SpendContextExt, XchandlesConstants, XchandlesDataValue, XchandlesPrecommitValue, - XchandlesRegistry, XchandlesSlotValue, -}; - -use super::{XchandlesFactorPricingPuzzleArgs, XchandlesPricingSolution}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct XchandlesExpireAction { - pub launcher_id: Bytes32, - pub relative_block_height: u32, - pub payout_puzzle_hash: Bytes32, -} - -impl ToTreeHash for XchandlesExpireAction { - fn tree_hash(&self) -> TreeHash { - XchandlesExpireActionArgs::curry_tree_hash( - self.launcher_id, - self.relative_block_height, - self.payout_puzzle_hash, - ) - } -} - -impl Action for XchandlesExpireAction { - fn from_constants(constants: &XchandlesConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - relative_block_height: constants.relative_block_height, - payout_puzzle_hash: constants.precommit_payout_puzzle_hash, - } - } -} - -impl XchandlesExpireAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(CurriedProgram { - program: ctx.xchandles_expire_puzzle()?, - args: XchandlesExpireActionArgs::new( - self.launcher_id, - self.relative_block_height, - self.payout_puzzle_hash, - ), - } - .to_clvm(ctx)?) - } - - pub fn spent_slot_value( - ctx: &SpendContext, - solution: NodePtr, - ) -> Result { - // truths for epired solution are: Buy_Time, Current_Expiration, Handle - let solution = XchandlesExpireActionSolution::< - NodePtr, - NodePtr, - NodePtr, - (NodePtr, (u64, (String, NodePtr))), - NodePtr, - >::from_clvm(ctx, solution)?; - - let handle = solution.expired_handle_pricing_puzzle_solution.1 .1 .0; - let current_expiration = solution.expired_handle_pricing_puzzle_solution.1 .0; - - Ok(XchandlesSlotValue::new( - handle.tree_hash().into(), - solution.neighbors.left_value, - solution.neighbors.right_value, - current_expiration, - solution.old_rest.owner_launcher_id, - solution.old_rest.resolved_data, - )) - } - - pub fn created_slot_value( - ctx: &mut SpendContext, - solution: NodePtr, - ) -> Result { - let solution = ctx.extract::>(solution)?; - - let pricing_output = ctx.run( - solution.expired_handle_pricing_puzzle_reveal, - solution.expired_handle_pricing_puzzle_solution, - )?; - let registration_time_delta = <(NodePtr, u64)>::from_clvm(ctx, pricing_output)?.1; - - // truths are: Buy_Time, Current_Expiration, Handle - let (buy_time, (_, (handle, _))) = ctx.extract::<(u64, (NodePtr, (String, NodePtr)))>( - solution.expired_handle_pricing_puzzle_solution, - )?; - - Ok(XchandlesSlotValue::new( - handle.tree_hash().into(), - solution.neighbors.left_value, - solution.neighbors.right_value, - buy_time + registration_time_delta, - solution.new_rest.owner_launcher_id, - solution.new_rest.resolved_data, - )) - } - - #[allow(clippy::too_many_arguments)] - pub fn spend( - self, - ctx: &mut SpendContext, - registry: &mut XchandlesRegistry, - slot: Slot, - num_periods: u64, - base_handle_price: u64, - registration_period: u64, - precommit_coin: PrecommitCoin, - start_time: u64, - ) -> Result { - let my_inner_puzzle_hash: Bytes32 = registry.info.inner_puzzle_hash().into(); - - // announcement is simply premcommitment coin ph - let expire_ann: Bytes32 = precommit_coin.coin.puzzle_hash; - - // spend precommit coin - precommit_coin.spend( - ctx, - 1, // mode 1 = register/expire (use value) - my_inner_puzzle_hash, - )?; - - // spend self - let slot = registry.actual_slot(slot); - let action_solution = XchandlesExpireActionSolution { - cat_maker_puzzle_reveal: DefaultCatMakerArgs::get_puzzle( - ctx, - precommit_coin.asset_id.tree_hash().into(), - )?, - cat_maker_puzzle_solution: (), - expired_handle_pricing_puzzle_reveal: - XchandlesExponentialPremiumRenewPuzzleArgs::from_scale_factor( - ctx, - base_handle_price, - registration_period, - 1000, - )? - .get_puzzle(ctx)?, - 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, - old_rest: slot.info.value.rest_data(), - new_rest: XchandlesDataValue { - owner_launcher_id: precommit_coin.value.owner_launcher_id, - resolved_data: precommit_coin.value.resolved_data, - }, - } - .to_clvm(ctx)?; - let action_puzzle = self.construct_puzzle(ctx)?; - - registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - - // spend slot - 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))) - } -} - -pub const XCHANDLES_EXPIRE_PUZZLE: [u8; 1073] = - hex!("ff02ffff01ff02ffff03ffff22ffff09ffff02ff16ffff04ff02ffff04ff4fff80808080ff5780ffff09ffff02ff16ffff04ff02ffff04ff82016fff80808080ff81f780ffff09ffff0dff825fef80ffff012080ffff15ffff0141ffff0dff827fef808080ffff01ff04ff17ffff02ff2effff04ff02ffff04ffff02ff4fffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff8205ef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff16ffff04ff02ffff04ffff04ffff04ffff04ff57ff81af80ffff04ff81f7ff8202ef8080ffff04ffff04ff8216efff820bef80ffff04ff825fefff827fef808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff81af8080ffff04ffff05ffff02ff82016fff8202ef8080ffff04ffff04ffff04ff10ffff04ff8204efff808080ffff04ffff04ff10ffff04ff820aefff808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff16ffff04ff02ffff04ffff04ffff04ffff0bffff0101ff8216ef80ff8217ef80ffff04ff820aefff822fef8080ff80808080ff8080808080ffff04ffff02ff1affff04ff02ffff04ff0bffff04ffff02ff16ffff04ff02ffff04ffff04ffff04ffff0bffff0101ff8216ef80ff8217ef80ffff04ffff10ffff06ffff02ff82016fff8202ef8080ff8204ef80ff823fef8080ff80808080ff8080808080ff8080808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff5133ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff16ffff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ffff04ffff04ff2cffff04ffff0113ffff04ffff0101ffff04ff05ffff04ff0bff808080808080ffff04ffff04ff14ffff04ffff0effff0178ff0580ff808080ff178080ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080"); - -pub const XCHANDLES_EXPIRE_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 514d248262b0b1607f305a26bf315f6ecb7d7705bfcf5856f12a9a22344af728 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct XchandlesExpireActionArgs { - pub precommit_1st_curry_hash: Bytes32, - pub slot_1st_curry_hash: Bytes32, -} - -impl XchandlesExpireActionArgs { - pub fn new( - launcher_id: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> Self { - Self { - precommit_1st_curry_hash: PrecommitLayer::<()>::first_curry_hash( - SingletonStruct::new(launcher_id).tree_hash().into(), - relative_block_height, - payout_puzzle_hash, - ) - .into(), - slot_1st_curry_hash: Slot::<()>::first_curry_hash(launcher_id, 0).into(), - } - } -} - -impl XchandlesExpireActionArgs { - pub fn curry_tree_hash( - launcher_id: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> TreeHash { - CurriedProgram { - program: XCHANDLES_EXPIRE_PUZZLE_HASH, - args: XchandlesExpireActionArgs::new( - launcher_id, - relative_block_height, - payout_puzzle_hash, - ), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct XchandlesExpireActionSolution { - pub cat_maker_puzzle_reveal: CMP, - pub cat_maker_puzzle_solution: CMS, - pub expired_handle_pricing_puzzle_reveal: EP, - pub expired_handle_pricing_puzzle_solution: ES, - pub refund_puzzle_hash_hash: Bytes32, - pub secret: S, - pub neighbors: SlotNeigborsInfo, - pub old_rest: XchandlesDataValue, - #[clvm(rest)] - pub new_rest: XchandlesDataValue, -} - -pub const XCHANDLES_EXPONENTIAL_PREMIUM_RENEW_PUZZLE: [u8; 333] = - hex!("ff02ffff01ff04ffff10ffff05ffff02ff05ff81ff8080ffff02ff06ffff04ff02ffff04ffff02ff04ffff04ff02ffff04ff5fffff04ff81bfffff04ffff0101ffff04ffff05ffff14ffff12ffff0183010000ffff3dffff11ff82017fff8202ff80ff0b8080ff0b8080ffff04ffff05ffff14ff17ffff17ffff0101ffff05ffff14ffff11ff82017fff8202ff80ff0b8080808080ff8080808080808080ffff04ff2fff808080808080ffff06ffff02ff05ff81ff808080ffff04ffff01ffff02ffff03ff0bffff01ff02ff04ffff04ff02ffff04ff05ffff04ff1bffff04ffff17ff17ffff010180ffff04ff2fffff04ffff02ffff03ffff18ff2fff1780ffff01ff05ffff14ffff12ff5fff1380ff058080ffff015f80ff0180ff8080808080808080ffff015f80ff0180ff02ffff03ffff15ff05ff0b80ffff01ff11ff05ff0b80ff8080ff0180ff018080"); - -pub const XCHANDLES_EXPONENTIAL_PREMIUM_RENEW_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - b54c0f4b73e63e78470366bd4006ca629d94f36c8ea58abacf8cc1cbb7724907 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(curry)] -pub struct XchandlesExponentialPremiumRenewPuzzleArgs

{ - pub base_program: P, - pub halving_period: u64, - pub start_premium: u64, - pub end_value: u64, - pub precision: u64, - pub bits_list: Vec, -} - -pub const PREMIUM_PRECISION: u64 = 1_000_000_000_000_000_000; // 10^18 - -// https://github.com/ensdomains/ens-contracts/blob/master/contracts/ethregistrar/ExponentialPremiumPriceOracle.sol -pub const PREMIUM_BITS_LIST: [u64; 16] = [ - 999989423469314432, // 0.5 ^ 1/65536 * (10 ** 18) - 999978847050491904, // 0.5 ^ 2/65536 * (10 ** 18) - 999957694548431104, - 999915390886613504, - 999830788931929088, - 999661606496243712, - 999323327502650752, - 998647112890970240, - 997296056085470080, - 994599423483633152, - 989228013193975424, - 978572062087700096, - 957603280698573696, - 917004043204671232, - 840896415253714560, - 707106781186547584, -]; - -impl XchandlesExponentialPremiumRenewPuzzleArgs { - pub fn get_start_premium(scale_factor: u64) -> u64 { - 100000000 * scale_factor // start auction at $100 million - } - - pub fn get_end_value(scale_factor: u64) -> u64 { - // 100000000 * 10 ** 18 // 2 ** 28 = 372529029846191406 - (372529029846191406_u128 * scale_factor as u128 / 1_000_000_000_000_000_000) as u64 - } - - // A scale factor is how many units of the payment token equate to $1 - // For exampe, you'd use scale_factor=1000 for wUSDC.b - pub fn from_scale_factor( - ctx: &mut SpendContext, - base_price: u64, - registration_period: u64, - scale_factor: u64, - ) -> Result { - Ok(Self { - base_program: XchandlesFactorPricingPuzzleArgs::get_puzzle( - ctx, - base_price, - registration_period, - )?, - halving_period: 86400, // one day = 86400 = 60 * 60 * 24 seconds - start_premium: Self::get_start_premium(scale_factor), - end_value: Self::get_end_value(scale_factor), - precision: PREMIUM_PRECISION, - bits_list: PREMIUM_BITS_LIST.to_vec(), - }) - } - - pub fn curry_tree_hash( - base_price: u64, - registration_period: u64, - scale_factor: u64, - ) -> TreeHash { - CurriedProgram { - program: XCHANDLES_EXPONENTIAL_PREMIUM_RENEW_PUZZLE_HASH, - args: XchandlesExponentialPremiumRenewPuzzleArgs:: { - base_program: XchandlesFactorPricingPuzzleArgs::curry_tree_hash( - base_price, - registration_period, - ), - halving_period: 86400, // one day = 86400 = 60 * 60 * 24 seconds - start_premium: Self::get_start_premium(scale_factor), - end_value: Self::get_end_value(scale_factor), - precision: PREMIUM_PRECISION, - bits_list: PREMIUM_BITS_LIST.to_vec(), - }, - } - .tree_hash() - } - - pub fn get_puzzle(self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.xchandles_exponential_premium_renew_puzzle()?, - args: self, - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - pub fn get_price( - self, - ctx: &mut SpendContext, - handle: String, - expiration: u64, - buy_time: u64, - num_periods: u64, - ) -> Result { - let puzzle = self.get_puzzle(ctx)?; - let solution = ctx.alloc(&XchandlesPricingSolution { - buy_time, - current_expiration: expiration, - handle, - num_periods, - })?; - let output = ctx.run(puzzle, solution)?; - - Ok(ctx.extract::<(u128, u64)>(output)?.0) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] - #[clvm(list)] - pub struct XchandlesPricingOutput { - pub price: u128, - #[clvm(rest)] - pub registered_time: u64, - } - - #[test] - fn test_exponential_premium_puzzle() -> Result<(), DriverError> { - let mut ctx = SpendContext::new(); - - let registration_period = 366 * 24 * 60 * 60; - let puzzle = XchandlesExponentialPremiumRenewPuzzleArgs::from_scale_factor( - &mut ctx, - 0, - registration_period, - 1000, - )? - .get_puzzle(&mut ctx)?; - - let mut last_price = 100_000_000_000; - for day in 0..28 { - for hour in 0..24 { - let buy_time = day * 24 * 60 * 60 + hour * 60 * 60; - let solution = ctx.alloc(&XchandlesPricingSolution { - buy_time, - current_expiration: 0, - handle: "yakuhito".to_string(), - num_periods: 1, - })?; - - let output = ctx.run(puzzle, solution)?; - let output = ctx.extract::(output)?; - - assert_eq!(output.registered_time, 366 * 24 * 60 * 60); - - if hour == 0 { - let scale_factor = - 372529029846191406_u128 * 1000_u128 / 1_000_000_000_000_000_000_u128; - assert_eq!( - output.price, - (100_000_000 * 1000) / (1 << day) - scale_factor - ); - } - - assert!(output.price < last_price); - last_price = output.price; - - assert_eq!( - XchandlesExponentialPremiumRenewPuzzleArgs::from_scale_factor( - &mut ctx, - 0, - registration_period, - 1000 - )? - .get_price( - &mut ctx, - "yakuhito".to_string(), - 0, - buy_time, - 1 - )?, - output.price - ); - } - } - - // check premium after auction is 0 - let solution = ctx.alloc(&XchandlesPricingSolution { - buy_time: 28 * 24 * 60 * 60, - current_expiration: 0, - handle: "yakuhito".to_string(), - num_periods: 1, - })?; - - let output = ctx.run(puzzle, solution)?; - let output = ctx.extract::(output)?; - - assert_eq!(output.registered_time, 366 * 24 * 60 * 60); - assert_eq!(output.price, 0); - - Ok(()) - } -} diff --git a/src/layers/actions/xchandles/extend.rs b/src/layers/actions/xchandles/extend.rs deleted file mode 100644 index 6d13683c..00000000 --- a/src/layers/actions/xchandles/extend.rs +++ /dev/null @@ -1,223 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::offer::{NotarizedPayment, Payment}, -}; -use chia_puzzles::SETTLEMENT_PAYMENT_HASH; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, DefaultCatMakerArgs, Slot, SlotNeigborsInfo, SpendContextExt, XchandlesConstants, - XchandlesDataValue, XchandlesRegistry, XchandlesSlotValue, -}; - -use super::{XchandlesFactorPricingPuzzleArgs, XchandlesPricingSolution}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct XchandlesExtendAction { - pub launcher_id: Bytes32, - pub payout_puzzle_hash: Bytes32, -} - -impl ToTreeHash for XchandlesExtendAction { - fn tree_hash(&self) -> TreeHash { - XchandlesExtendActionArgs::curry_tree_hash(self.launcher_id, self.payout_puzzle_hash) - } -} - -impl Action for XchandlesExtendAction { - fn from_constants(constants: &XchandlesConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - payout_puzzle_hash: constants.precommit_payout_puzzle_hash, - } - } -} - -impl XchandlesExtendAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(CurriedProgram { - program: ctx.xchandles_extend_puzzle()?, - args: XchandlesExtendActionArgs::new(self.launcher_id, self.payout_puzzle_hash), - } - .to_clvm(ctx)?) - } - - pub fn spent_slot_value( - ctx: &mut SpendContext, - solution: NodePtr, - ) -> Result { - let solution = ctx.extract::>(solution)?; - - // 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 .1 .0.tree_hash().into(), - solution.neighbors.left_value, - solution.neighbors.right_value, - current_expiration, - solution.rest.owner_launcher_id, - solution.rest.resolved_data, - )) - } - - pub fn created_slot_value( - ctx: &mut SpendContext, - solution: NodePtr, - ) -> Result { - let solution = ctx - .extract::>( - solution, - )?; - - 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, (NodePtr, (String, NodePtr)))>(solution.pricing_solution)?; - - // 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(), - solution.neighbors.left_value, - solution.neighbors.right_value, - current_expiration + registration_time_delta, - solution.rest.owner_launcher_id, - solution.rest.resolved_data, - )) - } - - #[allow(clippy::too_many_arguments)] - pub fn spend( - self, - ctx: &mut SpendContext, - registry: &mut XchandlesRegistry, - handle: String, - slot: Slot, - payment_asset_id: Bytes32, - base_handle_price: u64, - registration_period: u64, - num_periods: u64, - buy_time: u64, - ) -> Result<(Conditions, NotarizedPayment), DriverError> { - let spender_inner_puzzle_hash: Bytes32 = registry.info.inner_puzzle_hash().into(); - - // spend self - let cat_maker_puzzle_reveal = - DefaultCatMakerArgs::get_puzzle(ctx, payment_asset_id.tree_hash().into())?; - let pricing_puzzle_reveal = XchandlesFactorPricingPuzzleArgs::get_puzzle( - ctx, - base_handle_price, - registration_period, - )?; - - let slot = registry.actual_slot(slot); - let action_solution = ctx.alloc(&XchandlesExtendActionSolution { - pricing_puzzle_reveal, - pricing_solution: XchandlesPricingSolution { - buy_time, - current_expiration: slot.info.value.expiration, - handle: handle.clone(), - num_periods, - }, - cat_maker_puzzle_reveal, - cat_maker_solution: (), - neighbors: slot.info.value.neighbors, - rest: slot.info.value.rest_data(), - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - - let renew_amount = - XchandlesFactorPricingPuzzleArgs::get_price(base_handle_price, &handle, num_periods); - - let notarized_payment = NotarizedPayment { - nonce: clvm_tuple!(handle.clone(), slot.info.value.expiration) - .tree_hash() - .into(), - payments: vec![Payment::new( - registry.info.constants.precommit_payout_puzzle_hash, - renew_amount, - ctx.hint(registry.info.constants.precommit_payout_puzzle_hash)?, - )], - }; - - // spend slot - 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'); - - Ok(( - Conditions::new() - .assert_puzzle_announcement(announcement_id(registry.coin.puzzle_hash, extend_ann)), - notarized_payment, - )) - } -} - -pub const XCHANDLES_EXTEND_PUZZLE: [u8; 964] = hex!("ff02ffff01ff02ffff03ffff22ffff09ff81afffff02ff2effff04ff02ffff04ff8202dfff8080808080ffff09ff82016fffff02ff2effff04ff02ffff04ff819fff808080808080ffff01ff04ff2fffff04ffff02ff3effff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ffff0bffff0101ff820b5f80ff820bdf80ffff04ff82055fff820fdf8080ff80808080ff8080808080ffff04ffff04ff3cffff04ffff0effff0165ffff02ff2effff04ff02ffff04ffff04ffff05ffff02ff819fff82015f8080ff820b5f80ff8080808080ff808080ffff04ffff04ff10ffff04ff82055fff808080ffff04ffff04ff14ffff04ff82025fff808080ffff04ffff02ff16ffff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ffff0bffff0101ff820b5f80ff820bdf80ffff04ffff10ff82055fffff06ffff02ff819fff82015f808080ff820fdf8080ff80808080ff8080808080ffff04ffff04ff18ffff04ffff0bffff02ff8202dfffff04ff05ff8205df8080ffff02ff2effff04ff02ffff04ffff04ffff02ff2effff04ff02ffff04ffff04ff820b5fff82055f80ff80808080ffff04ffff04ff0bffff04ffff05ffff02ff819fff82015f8080ffff04ffff04ff0bff8080ff80808080ff808080ff8080808080ff808080ff8080808080808080ffff01ff088080ff0180ffff04ffff01ffffff553fff51ff333effff42ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff2cffff04ffff0bff81baffff0bff2affff0bff2aff81daff0580ffff0bff2affff0bff81faffff0bff2affff0bff2aff81daffff0bffff0101ff0b8080ffff0bff2aff81daff819a808080ff819a808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff12ffff04ffff0112ffff04ff80ffff04ffff0bff81baffff0bff2affff0bff2aff81daff0580ffff0bff2affff0bff81faffff0bff2affff0bff2aff81daffff0bffff0101ff0b8080ffff0bff2aff81daff819a808080ff819a808080ff8080808080ff018080"); - -pub const XCHANDLES_EXTEND_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - caa665c939f3de5d90dd22b00d092ba7c794300bf994b9ddcea536fa77843e08 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct XchandlesExtendActionArgs { - pub offer_mod_hash: Bytes32, - pub payout_puzzle_hash: Bytes32, - pub slot_1st_curry_hash: Bytes32, -} - -impl XchandlesExtendActionArgs { - pub fn new(launcher_id: Bytes32, payout_puzzle_hash: Bytes32) -> Self { - Self { - offer_mod_hash: SETTLEMENT_PAYMENT_HASH.into(), - payout_puzzle_hash, - slot_1st_curry_hash: Slot::<()>::first_curry_hash(launcher_id, 0).into(), - } - } -} - -impl XchandlesExtendActionArgs { - pub fn curry_tree_hash(launcher_id: Bytes32, payout_puzzle_hash: Bytes32) -> TreeHash { - CurriedProgram { - program: XCHANDLES_EXTEND_PUZZLE_HASH, - args: XchandlesExtendActionArgs::new(launcher_id, payout_puzzle_hash), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct XchandlesExtendActionSolution { - pub pricing_puzzle_reveal: PP, - pub pricing_solution: PS, - pub cat_maker_puzzle_reveal: CMP, - pub cat_maker_solution: CMS, - pub neighbors: SlotNeigborsInfo, - #[clvm(rest)] - pub rest: XchandlesDataValue, -} diff --git a/src/layers/actions/xchandles/oracle.rs b/src/layers/actions/xchandles/oracle.rs deleted file mode 100644 index b63fb11e..00000000 --- a/src/layers/actions/xchandles/oracle.rs +++ /dev/null @@ -1,113 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, Slot, SpendContextExt, XchandlesConstants, XchandlesRegistry, XchandlesSlotValue, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct XchandlesOracleAction { - pub launcher_id: Bytes32, -} - -impl ToTreeHash for XchandlesOracleAction { - fn tree_hash(&self) -> TreeHash { - XchandlesOracleActionArgs::curry_tree_hash(self.launcher_id) - } -} - -impl Action for XchandlesOracleAction { - fn from_constants(constants: &XchandlesConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - } - } -} - -impl XchandlesOracleAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(CurriedProgram { - program: ctx.xchandles_oracle_puzzle()?, - args: XchandlesOracleActionArgs::new(self.launcher_id), - } - .to_clvm(ctx)?) - } - - pub fn spent_slot_value( - ctx: &SpendContext, - solution: NodePtr, - ) -> Result { - let slot_value = ctx.extract::(solution)?; - - Ok(slot_value) - } - - pub fn created_slot_value(spent_slot_value: XchandlesSlotValue) -> XchandlesSlotValue { - spent_slot_value - } - - pub fn spend( - self, - ctx: &mut SpendContext, - registry: &mut XchandlesRegistry, - slot: Slot, - ) -> 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_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - - let new_slot = Self::created_slot_value(slot.info.value.clone()); - - // spend slot - 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))) - } -} - -pub const XCHANDLES_ORACLE_PUZZLE: [u8; 571] = hex!("ff02ffff01ff04ff0bffff02ff16ffff04ff02ffff04ff05ffff04ffff02ff2effff04ff02ffff04ff17ff80808080ff808080808080ffff04ffff01ffffff333eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff10ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff04ffff02ff3effff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff04ff18ffff04ffff0effff016fff0b80ff808080ff80808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff14ffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff1cffff0bff1cff62ff0580ffff0bff1cffff0bff72ffff0bff1cffff0bff1cff62ffff0bffff0101ff0b8080ffff0bff1cff62ff42808080ff42808080ff8080808080ff018080"); - -pub const XCHANDLES_ORACLE_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 1ba03341b929f37687610644f24a0cd36cb6ef019dc7289a0c2172d61482c23c - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct XchandlesOracleActionArgs { - pub slot_1st_curry_hash: Bytes32, -} - -impl XchandlesOracleActionArgs { - pub fn new(launcher_id: Bytes32) -> Self { - Self { - slot_1st_curry_hash: Slot::<()>::first_curry_hash(launcher_id, 0).into(), - } - } -} - -impl XchandlesOracleActionArgs { - pub fn curry_tree_hash(launcher_id: Bytes32) -> TreeHash { - CurriedProgram { - program: XCHANDLES_ORACLE_PUZZLE_HASH, - args: XchandlesOracleActionArgs::new(launcher_id), - } - .tree_hash() - } -} diff --git a/src/layers/actions/xchandles/refund.rs b/src/layers/actions/xchandles/refund.rs deleted file mode 100644 index 70196a5e..00000000 --- a/src/layers/actions/xchandles/refund.rs +++ /dev/null @@ -1,211 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::{Bytes, Bytes32}, - puzzles::singleton::SingletonStruct, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, DefaultCatMakerArgs, PrecommitCoin, PrecommitLayer, Slot, SpendContextExt, - XchandlesConstants, XchandlesPrecommitValue, XchandlesRegistry, XchandlesSlotValue, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct XchandlesRefundAction { - pub launcher_id: Bytes32, - pub relative_block_height: u32, - pub payout_puzzle_hash: Bytes32, -} - -impl ToTreeHash for XchandlesRefundAction { - fn tree_hash(&self) -> TreeHash { - XchandlesRefundActionArgs::curry_tree_hash( - self.launcher_id, - self.relative_block_height, - self.payout_puzzle_hash, - ) - } -} - -impl Action for XchandlesRefundAction { - fn from_constants(constants: &XchandlesConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - relative_block_height: constants.relative_block_height, - payout_puzzle_hash: constants.precommit_payout_puzzle_hash, - } - } -} - -impl XchandlesRefundAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(CurriedProgram { - program: ctx.xchandles_refund_puzzle()?, - args: XchandlesRefundActionArgs::new( - self.launcher_id, - self.relative_block_height, - self.payout_puzzle_hash, - ), - } - .to_clvm(ctx)?) - } - - pub fn spent_slot_value( - ctx: &SpendContext, - solution: NodePtr, - ) -> Result, DriverError> { - let solution = - XchandlesRefundActionSolution::::from_clvm( - ctx, solution, - )?; - - Ok(solution.slot_value) - } - - pub fn created_slot_value( - spent_slot_value: Option, - ) -> Option { - spent_slot_value // nothing changed; just oracle - } - - pub fn spend( - self, - ctx: &mut SpendContext, - registry: &mut XchandlesRegistry, - precommit_coin: PrecommitCoin, - precommited_pricing_puzzle_reveal: NodePtr, - precommited_pricing_puzzle_solution: NodePtr, - slot: Option>, - ) -> Result { - // calculate announcement - let mut refund_announcement: Vec = precommit_coin.coin.puzzle_hash.to_vec(); - refund_announcement.insert(0, b'$'); - - // spend precommit coin - let my_inner_puzzle_hash: Bytes32 = registry.info.inner_puzzle_hash().into(); - precommit_coin.spend( - ctx, - 0, // mode 0 = refund - my_inner_puzzle_hash, - )?; - - // spend self - let slot = slot.map(|s| registry.actual_slot(s)); - let action_solution = XchandlesRefundActionSolution { - precommited_cat_maker_reveal: DefaultCatMakerArgs::get_puzzle( - ctx, - precommit_coin.asset_id.tree_hash().into(), - )?, - precommited_cat_maker_hash: DefaultCatMakerArgs::curry_tree_hash( - precommit_coin.asset_id.tree_hash().into(), - ) - .into(), - precommited_cat_maker_solution: (), - precommited_pricing_puzzle_reveal, - precommited_pricing_puzzle_hash: ctx - .tree_hash(precommited_pricing_puzzle_reveal) - .into(), - precommited_pricing_puzzle_solution, - handle: precommit_coin.value.handle.clone(), - secret: precommit_coin.value.secret, - 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(), - precommit_amount: precommit_coin.coin.amount, - slot_value: slot.as_ref().map(|slot| slot.info.value.clone()), - } - .to_clvm(ctx)?; - let action_puzzle = self.construct_puzzle(ctx)?; - - registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - - // if there's a slot, spend it - if let Some(slot) = slot { - slot.spend(ctx, my_inner_puzzle_hash)?; - } - - Ok( - Conditions::new().assert_puzzle_announcement(announcement_id( - registry.coin.puzzle_hash, - refund_announcement, - )), - ) - } -} - -pub const XCHANDLES_REFUND_PUZZLE: [u8; 1075] = - hex!("ff02ffff01ff02ffff03ffff22ffff09ff81afffff02ff2effff04ff02ffff04ff4fff8080808080ffff09ff8205efffff02ff2effff04ff02ffff04ff8202efff8080808080ffff02ffff03ff8303ffefffff01ff09ff8309ffefffff0bffff0101ff8217ef8080ffff01ff010180ff018080ffff01ff04ff17ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ff8303ffefff80808080ffff04ffff02ffff03ffff22ffff09ff81afff5780ffff09ff8217efff825bef80ffff21ffff09ff8205efff81b780ffff09ff8205efff81f78080ffff09ff8302ffefffff05ffff02ff8202efff820bef80808080ffff01830bffefff8080ff0180ffff04ffff02ff4fffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff83017fef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ffff04ffff04ff81afff82016f80ffff04ff8205efff820bef8080ffff04ffff04ff8217efff822fef80ffff04ff825fefff82bfef808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff82016f8080ffff04ff8302ffefff808080808080808080ffff01ff088080ff0180ffff04ffff01ffffff5533ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff04ffff04ff2cffff04ffff0113ffff04ff80ffff04ff2fffff04ff5fff808080808080ffff04ffff04ff14ffff04ffff0effff0124ff2f80ff808080ffff02ffff03ff17ffff01ff04ffff04ff10ffff04ff17ff808080ffff04ffff02ff3effff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff02ff1affff04ff02ffff04ff05ffff04ff0bff8080808080ff80808080ff8080ff01808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080"); - -pub const XCHANDLES_REFUND_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - c1469c124abadf18b0deee827c57f5189bc81d0f59aa07e2290676d0000b20a1 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct XchandlesRefundActionArgs { - pub precommit_1st_curry_hash: Bytes32, - pub slot_1st_curry_hash: Bytes32, -} - -impl XchandlesRefundActionArgs { - pub fn new( - launcher_id: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> Self { - Self { - precommit_1st_curry_hash: PrecommitLayer::<()>::first_curry_hash( - SingletonStruct::new(launcher_id).tree_hash().into(), - relative_block_height, - payout_puzzle_hash, - ) - .into(), - slot_1st_curry_hash: Slot::<()>::first_curry_hash(launcher_id, 0).into(), - } - } -} - -impl XchandlesRefundActionArgs { - pub fn curry_tree_hash( - launcher_id: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> TreeHash { - CurriedProgram { - program: XCHANDLES_REFUND_PUZZLE_HASH, - args: XchandlesRefundActionArgs::new( - launcher_id, - relative_block_height, - payout_puzzle_hash, - ), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct XchandlesRefundActionSolution { - pub precommited_cat_maker_reveal: CMP, - pub precommited_cat_maker_hash: Bytes32, - pub precommited_cat_maker_solution: CMS, - pub precommited_pricing_puzzle_reveal: PP, - pub precommited_pricing_puzzle_hash: Bytes32, - pub precommited_pricing_puzzle_solution: PS, - pub handle: String, - pub secret: S, - pub precommited_owner_launcher_id: Bytes32, - pub precommited_resolved_data: Bytes, - pub refund_puzzle_hash_hash: Bytes32, - pub precommit_amount: u64, - #[clvm(rest)] - pub slot_value: Option, -} diff --git a/src/layers/actions/xchandles/register.rs b/src/layers/actions/xchandles/register.rs deleted file mode 100644 index c9fc6e7f..00000000 --- a/src/layers/actions/xchandles/register.rs +++ /dev/null @@ -1,480 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonStruct, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::{announcement_id, Conditions}, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, DefaultCatMakerArgs, PrecommitCoin, PrecommitLayer, Slot, SlotNeigborsInfo, - SpendContextExt, XchandlesConstants, XchandlesDataValue, XchandlesPrecommitValue, - XchandlesRegistry, XchandlesSlotValue, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct XchandlesRegisterAction { - pub launcher_id: Bytes32, - pub relative_block_height: u32, - pub payout_puzzle_hash: Bytes32, -} - -impl ToTreeHash for XchandlesRegisterAction { - fn tree_hash(&self) -> TreeHash { - XchandlesRegisterActionArgs::curry_tree_hash( - self.launcher_id, - self.relative_block_height, - self.payout_puzzle_hash, - ) - } -} - -impl Action for XchandlesRegisterAction { - fn from_constants(constants: &XchandlesConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - relative_block_height: constants.relative_block_height, - payout_puzzle_hash: constants.precommit_payout_puzzle_hash, - } - } -} - -impl XchandlesRegisterAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(CurriedProgram { - program: ctx.xchandles_register_puzzle()?, - args: XchandlesRegisterActionArgs::new( - self.launcher_id, - self.relative_block_height, - self.payout_puzzle_hash, - ), - } - .to_clvm(ctx)?) - } - - pub fn spent_slot_values( - ctx: &SpendContext, - solution: NodePtr, - ) -> Result<[XchandlesSlotValue; 2], DriverError> { - let solution = XchandlesRegisterActionSolution::< - NodePtr, - NodePtr, - NodePtr, - NodePtr, - NodePtr, - >::from_clvm(ctx, solution)?; - - Ok([ - XchandlesSlotValue::new( - solution.neighbors.left_value, - solution.left_left_value, - solution.neighbors.right_value, - solution.left_expiration, - solution.left_data.owner_launcher_id, - solution.left_data.resolved_data, - ), - XchandlesSlotValue::new( - solution.neighbors.right_value, - solution.neighbors.left_value, - solution.right_right_value, - solution.right_expiration, - solution.right_data.owner_launcher_id, - solution.right_data.resolved_data, - ), - ]) - } - - pub fn created_slot_values( - ctx: &mut SpendContext, - solution: NodePtr, - ) -> Result<[XchandlesSlotValue; 3], DriverError> { - let solution = XchandlesRegisterActionSolution::< - NodePtr, - NodePtr, - NodePtr, - NodePtr, - NodePtr, - >::from_clvm(ctx, solution)?; - - let pricing_output = ctx.run( - solution.pricing_puzzle_reveal, - solution.pricing_puzzle_solution, - )?; - 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, - solution.left_left_value, - solution.handle_hash, - solution.left_expiration, - solution.left_data.owner_launcher_id, - solution.left_data.resolved_data, - ), - XchandlesSlotValue::new( - solution.handle_hash, - solution.neighbors.left_value, - solution.neighbors.right_value, - start_time + registration_time_delta, - solution.data.owner_launcher_id, - solution.data.resolved_data, - ), - XchandlesSlotValue::new( - solution.neighbors.right_value, - solution.handle_hash, - solution.right_right_value, - solution.right_expiration, - solution.right_data.owner_launcher_id, - solution.right_data.resolved_data, - ), - ]) - } - - #[allow(clippy::too_many_arguments)] - pub fn spend( - self, - ctx: &mut SpendContext, - registry: &mut XchandlesRegistry, - left_slot: Slot, - right_slot: Slot, - precommit_coin: PrecommitCoin, - base_handle_price: u64, - registration_period: u64, - 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 num_periods = precommit_coin.coin.amount - / XchandlesFactorPricingPuzzleArgs::get_price(base_handle_price, &handle, 1); - - // calculate announcement - let mut register_announcement: Vec = precommit_coin.coin.puzzle_hash.to_vec(); - register_announcement.insert(0, b'r'); - - // spend precommit coin - let my_inner_puzzle_hash: Bytes32 = registry.info.inner_puzzle_hash().into(); - precommit_coin.spend( - ctx, - 1, // mode 1 = register/expire (use value) - my_inner_puzzle_hash, - )?; - - // spend self - let action_solution = XchandlesRegisterActionSolution { - handle_hash, - pricing_puzzle_reveal: XchandlesFactorPricingPuzzleArgs::get_puzzle( - ctx, - base_handle_price, - registration_period, - )?, - pricing_puzzle_solution: XchandlesPricingSolution { - buy_time: start_time, - current_expiration: 0, - handle: handle.clone(), - num_periods, - }, - cat_maker_reveal: DefaultCatMakerArgs::get_puzzle( - ctx, - precommit_coin.asset_id.tree_hash().into(), - )?, - cat_maker_solution: (), - neighbors: SlotNeigborsInfo { - left_value: left_slot.info.value.handle_hash, - right_value: right_slot.info.value.handle_hash, - }, - left_left_value: left_slot.info.value.neighbors.left_value, - left_expiration: left_slot.info.value.expiration, - left_data: left_slot.info.value.rest_data(), - 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(), - data: XchandlesDataValue { - owner_launcher_id: precommit_coin.value.owner_launcher_id, - resolved_data: precommit_coin.value.resolved_data, - }, - refund_puzzle_hash_hash: precommit_coin.refund_puzzle_hash.tree_hash().into(), - secret, - } - .to_clvm(ctx)?; - let action_puzzle = self.construct_puzzle(ctx)?; - - registry.insert_action_spend(ctx, Spend::new(action_puzzle, action_solution))?; - - // spend slots - left_slot.spend(ctx, my_inner_puzzle_hash)?; - right_slot.spend(ctx, my_inner_puzzle_hash)?; - - Ok( - Conditions::new().assert_puzzle_announcement(announcement_id( - registry.coin.puzzle_hash, - register_announcement, - )), - ) - } -} - -pub const XCHANDLES_REGISTER_PUZZLE: [u8; 1345] = hex!("ff02ffff01ff02ffff03ffff22ffff09ff4fffff0bffff0101ff820b6f8080ffff20ff82056f80ffff0aff4fff8213ef80ffff0aff821befff4f80ffff09ff57ffff02ff2effff04ff02ffff04ff8202efff8080808080ffff09ff81b7ffff02ff2effff04ff02ffff04ff81afff8080808080ffff09ffff0dff8309ffef80ffff012080ffff15ffff0141ffff0dff830dffef808080ffff01ff04ff17ffff02ff1affff04ff02ffff04ffff02ff8202efffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ff830bffef80ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ffff02ff2effff04ff02ffff04ffff04ffff04ffff04ff57ff8205ef80ffff04ff81b7ff82016f8080ffff04ffff04ff820b6fff8317ffef80ffff04ff8309ffefff830dffef808080ff808080808080ffff0bff3cff62ff42808080ff42808080ff42808080ff8205ef8080ffff04ffff05ffff02ff81afff82016f8080ffff04ffff04ffff04ff10ffff04ff82026fff808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff8213efffff04ff8217efff821bef8080ffff04ff822fefff825fef8080ff80808080ff8080808080ffff04ffff02ff3effff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff821befffff04ff8213efff82bfef8080ffff04ff83017fefff8302ffef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff4fff820bef80ffff04ffff10ff82026fffff06ffff02ff81afff82016f808080ff8305ffef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff8213efffff04ff8217efff4f8080ffff04ff822fefff825fef8080ff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff0bffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff821befffff04ff4fff82bfef8080ffff04ff83017fefff8302ffef8080ff80808080ff8080808080ff80808080808080ff80808080808080ffff01ff088080ff0180ffff04ffff01ffffff5133ff3eff4202ffffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff04ffff04ff2cffff04ffff0113ffff04ffff0101ffff04ff05ffff04ff0bff808080808080ffff04ffff04ff14ffff04ffff0effff0172ff0580ff808080ff178080ffff04ff18ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff2cffff04ffff0112ffff04ff80ffff04ffff0bff52ffff0bff3cffff0bff3cff62ff0580ffff0bff3cffff0bff72ffff0bff3cffff0bff3cff62ffff0bffff0101ff0b8080ffff0bff3cff62ff42808080ff42808080ff8080808080ff018080"); - -pub const XCHANDLES_REGISTER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 07848cf0db85d13490c15331a065364add5f5b52d8059c410f1ff7aa87e66722 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct XchandlesRegisterActionArgs { - pub precommit_1st_curry_hash: Bytes32, - pub slot_1st_curry_hash: Bytes32, -} - -impl XchandlesRegisterActionArgs { - pub fn new( - launcher_id: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> Self { - Self { - precommit_1st_curry_hash: PrecommitLayer::<()>::first_curry_hash( - SingletonStruct::new(launcher_id).tree_hash().into(), - relative_block_height, - payout_puzzle_hash, - ) - .into(), - slot_1st_curry_hash: Slot::<()>::first_curry_hash(launcher_id, 0).into(), - } - } -} - -impl XchandlesRegisterActionArgs { - pub fn curry_tree_hash( - launcher_id: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> TreeHash { - CurriedProgram { - program: XCHANDLES_REGISTER_PUZZLE_HASH, - args: XchandlesRegisterActionArgs::new( - launcher_id, - relative_block_height, - payout_puzzle_hash, - ), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct XchandlesRegisterActionSolution { - pub handle_hash: Bytes32, - pub pricing_puzzle_reveal: PP, - pub pricing_puzzle_solution: PS, - pub cat_maker_reveal: CMP, - pub cat_maker_solution: CMS, - pub neighbors: SlotNeigborsInfo, - pub left_left_value: Bytes32, - pub left_expiration: u64, - pub left_data: XchandlesDataValue, - pub right_right_value: Bytes32, - pub right_expiration: u64, - pub right_data: XchandlesDataValue, - pub data: XchandlesDataValue, - pub refund_puzzle_hash_hash: Bytes32, - pub secret: S, -} - -pub const XCHANDLES_FACTOR_PRICING_PUZZLE: [u8; 475] = hex!("ff02ffff01ff02ffff03ffff15ff7fff8080ffff01ff04ffff12ff7fff05ffff02ff06ffff04ff02ffff04ffff0dff5f80ffff04ffff02ff04ffff04ff02ffff04ff5fff80808080ff808080808080ffff12ff7fff0b8080ffff01ff088080ff0180ffff04ffff01ffff02ffff03ff05ffff01ff02ffff03ffff22ffff15ffff0cff05ff80ffff010180ffff016080ffff15ffff017bffff0cff05ff80ffff0101808080ffff01ff02ff04ffff04ff02ffff04ffff0cff05ffff010180ff80808080ffff01ff02ffff03ffff22ffff15ffff0cff05ff80ffff010180ffff012f80ffff15ffff013affff0cff05ff80ffff0101808080ffff01ff10ffff0101ffff02ff04ffff04ff02ffff04ffff0cff05ffff010180ff8080808080ffff01ff088080ff018080ff0180ff8080ff0180ff05ffff14ffff02ffff03ffff15ff05ffff010280ffff01ff02ffff03ffff15ff05ffff010480ffff01ff02ffff03ffff09ff05ffff010580ffff01ff0110ffff01ff02ffff03ffff15ff05ffff011f80ffff01ff0880ffff01ff010280ff018080ff0180ffff01ff02ffff03ffff09ff05ffff010380ffff01ff01820080ffff01ff014080ff018080ff0180ffff01ff088080ff0180ffff03ff0bffff0102ffff0101808080ff018080"); - -pub const XCHANDLES_FACTOR_PRICING_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - a7edc890e6c256e4e729e826e7b45ad0616ec8d431e4e051ee68ddf4cae868bb - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct XchandlesFactorPricingPuzzleArgs { - pub base_price: u64, - pub registration_period: u64, -} - -impl XchandlesFactorPricingPuzzleArgs { - pub fn new(base_price: u64, registration_period: u64) -> Self { - Self { - base_price, - registration_period, - } - } - - pub fn get_puzzle( - ctx: &mut SpendContext, - base_price: u64, - registration_period: u64, - ) -> Result { - CurriedProgram { - program: ctx.xchandles_factor_pricing_puzzle()?, - args: XchandlesFactorPricingPuzzleArgs::new(base_price, registration_period), - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - pub fn get_price(base_price: u64, handle: &str, num_periods: u64) -> u64 { - base_price - * match handle.len() { - 3 => 128, - 4 => 64, - 5 => 16, - _ => 2, - } - / if handle.contains(|c: char| c.is_numeric()) { - 2 - } else { - 1 - } - * num_periods - } -} - -impl XchandlesFactorPricingPuzzleArgs { - pub fn curry_tree_hash(base_price: u64, registration_period: u64) -> TreeHash { - CurriedProgram { - program: XCHANDLES_FACTOR_PRICING_PUZZLE_HASH, - args: XchandlesFactorPricingPuzzleArgs::new(base_price, registration_period), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct XchandlesPricingSolution { - pub buy_time: u64, - pub current_expiration: u64, - pub handle: String, - #[clvm(rest)] - pub num_periods: u64, -} - -#[cfg(test)] -mod tests { - use clvmr::reduction::EvalErr; - - use super::*; - - #[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] - #[clvm(list)] - pub struct XchandlesFactorPricingOutput { - pub price: u64, - #[clvm(rest)] - pub registered_time: u64, - } - - #[test] - fn test_factor_pricing_puzzle() -> Result<(), DriverError> { - let mut ctx = SpendContext::new(); - let base_price = 1; // puzzle will only spit out factors - let registration_period = 366 * 24 * 60 * 60; // one year - - let puzzle = XchandlesFactorPricingPuzzleArgs::get_puzzle( - &mut ctx, - base_price, - registration_period, - )?; - - for handle_length in 3..=31 { - for num_periods in 1..=3 { - for has_number in [false, true] { - let handle = if has_number { - "a".repeat(handle_length - 1) + "1" - } else { - "a".repeat(handle_length) - }; - - let solution = ctx.alloc(&XchandlesPricingSolution { - buy_time: 0, - current_expiration: (handle_length - 3) as u64, // shouldn't matter - handle, - num_periods, - })?; - - let output = ctx.run(puzzle, solution)?; - let output = ctx.extract::(output)?; - - let mut expected_price = if handle_length == 3 { - 128 - } else if handle_length == 4 { - 64 - } else if handle_length == 5 { - 16 - } else { - 2 - }; - if has_number { - expected_price /= 2; - } - expected_price *= num_periods; - - assert_eq!(output.price, expected_price); - assert_eq!(output.registered_time, num_periods * registration_period); - } - } - } - - // make sure the puzzle won't let us register a handle of length 2 - - let solution = ctx.alloc(&XchandlesPricingSolution { - buy_time: 0, - current_expiration: 0, - handle: "aa".to_string(), - num_periods: 1, - })?; - - let Err(DriverError::Eval(EvalErr(_, s))) = ctx.run(puzzle, solution) else { - panic!("Expected error"); - }; - assert_eq!(s, "clvm raise"); - - // make sure the puzzle won't let us register a handle of length 32 - - let solution = ctx.alloc(&XchandlesPricingSolution { - buy_time: 0, - current_expiration: 0, - handle: "a".repeat(32), - num_periods: 1, - })?; - - let Err(DriverError::Eval(EvalErr(_, s))) = ctx.run(puzzle, solution) else { - panic!("Expected error"); - }; - assert_eq!(s, "clvm raise"); - - // make sure the puzzle won't let us register a handle with invalid characters - - let solution = ctx.alloc(&XchandlesPricingSolution { - buy_time: 0, - current_expiration: 0, - handle: "yak@test".to_string(), - num_periods: 1, - })?; - - let Err(DriverError::Eval(EvalErr(_, s))) = ctx.run(puzzle, solution) else { - panic!("Expected error"); - }; - assert_eq!(s, "clvm raise"); - - Ok(()) - } -} diff --git a/src/layers/actions/xchandles/update.rs b/src/layers/actions/xchandles/update.rs deleted file mode 100644 index 20de56d6..00000000 --- a/src/layers/actions/xchandles/update.rs +++ /dev/null @@ -1,154 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::{Bytes, Bytes32}, -}; -use chia_puzzles::{SINGLETON_LAUNCHER_HASH, SINGLETON_TOP_LAYER_V1_1_HASH}; -use chia_wallet_sdk::{ - driver::{DriverError, Spend, SpendContext}, - types::Conditions, -}; -use clvm_traits::{clvm_tuple, FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::{ - Action, Slot, SpendContextExt, XchandlesConstants, XchandlesDataValue, XchandlesRegistry, - XchandlesSlotValue, -}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct XchandlesUpdateAction { - pub launcher_id: Bytes32, -} - -impl ToTreeHash for XchandlesUpdateAction { - fn tree_hash(&self) -> TreeHash { - XchandlesUpdateActionArgs::curry_tree_hash(self.launcher_id) - } -} - -impl Action for XchandlesUpdateAction { - fn from_constants(constants: &XchandlesConstants) -> Self { - Self { - launcher_id: constants.launcher_id, - } - } -} - -impl XchandlesUpdateAction { - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(CurriedProgram { - program: ctx.xchandles_update_puzzle()?, - args: XchandlesUpdateActionArgs::new(self.launcher_id), - } - .to_clvm(ctx)?) - } - - pub fn spent_slot_value( - ctx: &SpendContext, - solution: NodePtr, - ) -> Result { - let solution = ctx.extract::(solution)?; - - Ok(solution.current_slot_value) - } - - pub fn created_slot_value( - ctx: &mut SpendContext, - solution: NodePtr, - ) -> Result { - let solution = ctx.extract::(solution)?; - - Ok(solution.current_slot_value.with_data( - solution.new_data.owner_launcher_id, - solution.new_data.resolved_data, - )) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - registry: &mut XchandlesRegistry, - slot: Slot, - new_owner_launcher_id: Bytes32, - new_resolved_data: Bytes, - announcer_inner_puzzle_hash: Bytes32, - ) -> 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 { - owner_launcher_id: new_owner_launcher_id, - resolved_data: new_resolved_data.clone(), - }, - announcer_inner_puzzle_hash, - })?; - let action_puzzle = self.construct_puzzle(ctx)?; - - 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(); - - let msg: Bytes32 = clvm_tuple!( - slot.info.value.handle_hash, - clvm_tuple!(new_owner_launcher_id, new_resolved_data.clone()) - ) - .tree_hash() - .into(); - - slot.spend(ctx, my_inner_puzzle_hash)?; - - Ok(Conditions::new().send_message( - 18, - msg.into(), - vec![ctx.alloc(®istry.coin.puzzle_hash)?], - )) - } -} - -pub const XCHANDLES_UPDATE_PUZZLE: [u8; 824] = hex!("ff02ffff01ff02ffff03ffff22ffff09ffff0dff82025f80ffff012080ffff15ffff0141ffff0dff82035f808080ffff01ff04ff2fffff04ffff04ff10ffff04ff82029fff808080ffff04ffff02ff3effff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ff819fff80808080ff8080808080ffff04ffff02ff16ffff04ff02ffff04ff17ffff04ffff02ff2effff04ff02ffff04ffff04ffff04ff82021fff82031f80ffff04ff82029fff82015f8080ff80808080ff8080808080ffff04ffff04ff14ffff04ffff0112ffff04ffff02ff2effff04ff02ffff04ffff04ff82021fff82015f80ff80808080ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff02ff2effff04ff02ffff04ffff04ff05ffff04ff82059fff0b8080ff8080808080ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6aff8201df80ffff0bff12ff6aff4a808080ff4a808080ff4a808080ff8080808080ff808080808080ffff01ff088080ff0180ffff04ffff01ffffff5533ff4342ffff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff04ff18ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ffff04ff80ffff04ffff04ff05ff8080ff8080808080ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff2effff04ff02ffff04ff09ff80808080ffff02ff2effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff04ff1cffff04ffff0112ffff04ff80ffff04ffff0bff5affff0bff12ffff0bff12ff6aff0580ffff0bff12ffff0bff7affff0bff12ffff0bff12ff6affff0bffff0101ff0b8080ffff0bff12ff6aff4a808080ff4a808080ff8080808080ff018080"); - -pub const XCHANDLES_UPDATE_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 66824757990b68234d4540b28ea8442bfdb2e875952222f002ea93cd6f8d93cb - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct XchandlesUpdateActionArgs { - pub singleton_mod_hash: Bytes32, - pub singleton_launcher_mod_hash: Bytes32, - pub slot_1st_curry_hash: Bytes32, -} - -impl XchandlesUpdateActionArgs { - pub fn new(launcher_id: Bytes32) -> Self { - Self { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - singleton_launcher_mod_hash: SINGLETON_LAUNCHER_HASH.into(), - slot_1st_curry_hash: Slot::<()>::first_curry_hash(launcher_id, 0).into(), - } - } -} - -impl XchandlesUpdateActionArgs { - pub fn curry_tree_hash(launcher_id: Bytes32) -> TreeHash { - CurriedProgram { - program: XCHANDLES_UPDATE_PUZZLE_HASH, - args: XchandlesUpdateActionArgs::new(launcher_id), - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct XchandlesUpdateActionSolution { - pub current_slot_value: XchandlesSlotValue, - pub new_data: XchandlesDataValue, - #[clvm(rest)] - pub announcer_inner_puzzle_hash: Bytes32, -} diff --git a/src/layers/conditions_layer.rs b/src/layers/conditions_layer.rs deleted file mode 100644 index 6b99e7dc..00000000 --- a/src/layers/conditions_layer.rs +++ /dev/null @@ -1,65 +0,0 @@ -use chia_wallet_sdk::{ - driver::{DriverError, Layer, Puzzle, Spend, SpendContext}, - types::{Condition, Conditions}, -}; -use clvm_traits::{clvm_quote, match_quote, FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; - -/// The Conditions [`Layer`] is a puzzle that simply returns the conditions -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct ConditionsLayer { - pub conditions: Conditions, -} - -impl ConditionsLayer { - pub fn new(conditions: Conditions) -> Self { - Self { conditions } - } -} - -impl Layer for ConditionsLayer -where - T: FromClvm + ToClvm + Clone, -{ - type Solution = (); - - fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result, DriverError> { - let Some(puzzle) = puzzle.as_raw() else { - return Ok(None); - }; - - let (_q, conditions) = >)>::from_clvm(allocator, puzzle.ptr)?; - - Ok(Some(Self::new( - Conditions::::default().extend(conditions), - ))) - } - - fn parse_solution(_: &Allocator, _: NodePtr) -> Result { - Ok(()) - } - - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(clvm_quote!(self.conditions.clone()).to_clvm(ctx)?) - } - - fn construct_solution( - &self, - _: &mut SpendContext, - (): Self::Solution, - ) -> Result { - Ok(NodePtr::NIL) - } -} - -impl ConditionsLayer -where - T: FromClvm + ToClvm + Clone, -{ - pub fn spend(self, ctx: &mut SpendContext) -> Result { - let puzzle = self.construct_puzzle(ctx)?; - let solution = self.construct_solution(ctx, ())?; - - Ok(Spend { puzzle, solution }) - } -} diff --git a/src/layers/m_of_n_layer.rs b/src/layers/m_of_n_layer.rs deleted file mode 100644 index 6e34024a..00000000 --- a/src/layers/m_of_n_layer.rs +++ /dev/null @@ -1,181 +0,0 @@ -use chia::{ - bls::PublicKey, - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::{Bytes32, Coin}, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Layer, Puzzle, Spend, SpendContext}, - types::{Condition, Conditions}, -}; -use clvm_traits::{clvm_quote, FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; -use hex_literal::hex; - -use crate::SpendContextExt; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MOfNLayer { - pub m: usize, - pub public_key_list: Vec, -} - -impl Layer for MOfNLayer { - type Solution = P2MOfNDelegateDirectSolution; - - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - CurriedProgram { - program: ctx.p2_m_of_n_delegate_direct_puzzle()?, - args: P2MOfNDelegateDirectArgs::new(self.m, self.public_key_list.clone()), - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - fn construct_solution( - &self, - ctx: &mut SpendContext, - solution: Self::Solution, - ) -> Result { - ctx.alloc(&solution) - } - - fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result, DriverError> { - let Some(puzzle) = puzzle.as_curried() else { - return Ok(None); - }; - - if puzzle.mod_hash != P2_M_OF_N_DELEGATE_DIRECT_PUZZLE_HASH { - return Ok(None); - } - - let args = P2MOfNDelegateDirectArgs::from_clvm(allocator, puzzle.args)?; - - Ok(Some(Self { - m: args.m, - public_key_list: args.public_key_list, - })) - } - - fn parse_solution( - allocator: &Allocator, - solution: NodePtr, - ) -> Result { - Ok(P2MOfNDelegateDirectSolution::from_clvm( - allocator, solution, - )?) - } -} - -impl MOfNLayer { - pub fn new(m: usize, public_key_list: Vec) -> Self { - Self { m, public_key_list } - } - - pub fn ensure_non_replayable( - conditions: Conditions, - coin_id: Bytes32, - genesis_challenge: NodePtr, - ) -> Conditions { - let found_condition = conditions.clone().into_iter().find(|c| { - matches!(c, Condition::AssertMyCoinId(..)) - || matches!(c, Condition::AssertMyParentId(..)) - }); - - if found_condition.is_some() { - conditions - } else { - conditions.assert_my_coin_id(coin_id) - } - .remark(genesis_challenge) - } - - pub fn spend( - &self, - ctx: &mut SpendContext, - coin: Coin, - conditions: Conditions, - used_pubkeys: &[PublicKey], - genesis_challenge: Bytes32, - ) -> Result<(), DriverError> { - let genesis_challenge = ctx.alloc(&genesis_challenge)?; - let spend = self.spend_with_conditions( - ctx, - Self::ensure_non_replayable(conditions, coin.coin_id(), genesis_challenge), - used_pubkeys, - )?; - ctx.spend(coin, spend) - } - - pub fn spend_with_conditions( - &self, - ctx: &mut SpendContext, - conditions: Conditions, - used_pubkeys: &[PublicKey], - ) -> Result { - let delegated_puzzle = ctx.alloc(&clvm_quote!(conditions))?; - self.construct_spend( - ctx, - P2MOfNDelegateDirectSolution { - selectors: P2MOfNDelegateDirectArgs::selectors_for_used_pubkeys( - &self.public_key_list, - used_pubkeys, - ), - delegated_puzzle, - delegated_solution: NodePtr::NIL, - }, - ) - } -} - -impl ToTreeHash for MOfNLayer { - fn tree_hash(&self) -> TreeHash { - P2MOfNDelegateDirectArgs::curry_tree_hash(self.m, self.public_key_list.clone()) - } -} - -pub const P2_M_OF_N_DELEGATE_DIRECT_PUZZLE: [u8; 453] = hex!("ff02ffff01ff02ffff03ffff09ff05ffff02ff16ffff04ff02ffff04ff17ff8080808080ffff01ff02ff0cffff04ff02ffff04ffff02ff0affff04ff02ffff04ff17ffff04ff0bff8080808080ffff04ffff02ff1effff04ff02ffff04ff2fff80808080ffff04ff2fffff04ff5fff80808080808080ffff01ff088080ff0180ffff04ffff01ffff31ff02ffff03ff05ffff01ff04ffff04ff08ffff04ff09ffff04ff0bff80808080ffff02ff0cffff04ff02ffff04ff0dffff04ff0bffff04ff17ffff04ff2fff8080808080808080ffff01ff02ff17ff2f8080ff0180ffff02ffff03ff05ffff01ff02ffff03ff09ffff01ff04ff13ffff02ff0affff04ff02ffff04ff0dffff04ff1bff808080808080ffff01ff02ff0affff04ff02ffff04ff0dffff04ff1bff808080808080ff0180ff8080ff0180ffff02ffff03ff05ffff01ff10ffff02ff16ffff04ff02ffff04ff0dff80808080ffff02ffff03ff09ffff01ff0101ff8080ff018080ff8080ff0180ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080"); - -pub const P2_M_OF_N_DELEGATE_DIRECT_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 0f199d5263ac1a62b077c159404a71abd3f9691cc57520bf1d4c5cb501504457 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(curry)] -pub struct P2MOfNDelegateDirectArgs { - pub m: usize, - pub public_key_list: Vec, -} - -impl P2MOfNDelegateDirectArgs { - pub fn new(m: usize, public_key_list: Vec) -> Self { - Self { m, public_key_list } - } - - pub fn curry_tree_hash(m: usize, public_key_list: Vec) -> TreeHash { - CurriedProgram { - program: P2_M_OF_N_DELEGATE_DIRECT_PUZZLE_HASH, - args: Self::new(m, public_key_list), - } - .tree_hash() - } - - pub fn selectors_for_used_pubkeys( - public_key_list: &[PublicKey], - used_pubkeys: &[PublicKey], - ) -> Vec { - public_key_list - .iter() - .map(|pubkey| used_pubkeys.contains(pubkey)) - .collect() - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct P2MOfNDelegateDirectSolution { - pub selectors: Vec, - pub delegated_puzzle: P, - pub delegated_solution: S, -} diff --git a/src/layers/p2_delegated_by_singleton_layer.rs b/src/layers/p2_delegated_by_singleton_layer.rs deleted file mode 100644 index 007d2fa6..00000000 --- a/src/layers/p2_delegated_by_singleton_layer.rs +++ /dev/null @@ -1,135 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonStruct, -}; -use chia_puzzles::SINGLETON_TOP_LAYER_V1_1_HASH; -use chia_wallet_sdk::driver::{DriverError, Layer, Puzzle, SpendContext}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; -use hex_literal::hex; - -use crate::SpendContextExt; - -#[derive(Debug, Clone)] -#[must_use] -pub struct P2DelegatedBySingletonLayer { - pub singleton_struct_hash: Bytes32, - pub nonce: u64, -} - -impl P2DelegatedBySingletonLayer { - pub fn new(singleton_struct_hash: Bytes32, nonce: u64) -> Self { - Self { - singleton_struct_hash, - nonce, - } - } -} - -impl Layer for P2DelegatedBySingletonLayer { - type Solution = P2DelegatedBySingletonLayerSolution; - - fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result, DriverError> { - let Some(puzzle) = puzzle.as_curried() else { - return Ok(None); - }; - - if puzzle.mod_hash != P2_DELEGATED_BY_SINGLETON_PUZZLE_HASH { - return Ok(None); - } - - let args = P2DelegatedBySingletonLayerArgs::from_clvm(allocator, puzzle.args)?; - - if args.singleton_mod_hash != SINGLETON_TOP_LAYER_V1_1_HASH.into() { - return Ok(None); - } - - Ok(Some(Self { - singleton_struct_hash: args.singleton_struct_hash, - nonce: args.nonce, - })) - } - - fn parse_solution( - allocator: &Allocator, - solution: NodePtr, - ) -> Result { - P2DelegatedBySingletonLayerSolution::from_clvm(allocator, solution) - .map_err(DriverError::FromClvm) - } - - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - Ok(CurriedProgram { - program: ctx.p2_delegated_by_singleton_puzzle()?, - args: P2DelegatedBySingletonLayerArgs::new(self.singleton_struct_hash, self.nonce), - } - .to_clvm(ctx)?) - } - - fn construct_solution( - &self, - ctx: &mut SpendContext, - solution: Self::Solution, - ) -> Result { - solution.to_clvm(ctx).map_err(DriverError::ToClvm) - } -} - -pub const P2_DELEGATED_BY_SINGLETON_PUZZLE: [u8; 382] = hex!("ff02ffff01ff04ffff04ff08ffff04ffff0117ffff04ffff02ff0effff04ff02ffff04ff5fff80808080ffff04ffff0bff2affff0bff0cffff0bff0cff32ff0580ffff0bff0cffff0bff3affff0bff0cffff0bff0cff32ff0b80ffff0bff0cffff0bff3affff0bff0cffff0bff0cff32ff2f80ffff0bff0cff32ff22808080ff22808080ff22808080ff8080808080ffff02ff5fff81bf8080ffff04ffff01ffff4302ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff0effff04ff02ffff04ff09ff80808080ffff02ff0effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080"); - -pub const P2_DELEGATED_BY_SINGLETON_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 25fbd0d4586ff8266eb8b0fc4768b7714394d87f87824b0124fc10806ba87bb5 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct P2DelegatedBySingletonLayerArgs { - pub singleton_mod_hash: Bytes32, - pub singleton_struct_hash: Bytes32, - pub nonce: u64, -} - -impl P2DelegatedBySingletonLayerArgs { - pub fn new(singleton_struct_hash: Bytes32, nonce: u64) -> Self { - Self { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - singleton_struct_hash, - nonce, - } - } - - pub fn from_launcher_id(launcher_id: Bytes32, nonce: u64) -> Self { - Self { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - singleton_struct_hash: SingletonStruct::new(launcher_id).tree_hash().into(), - nonce, - } - } - - pub fn curry_tree_hash(singleton_struct_hash: Bytes32, nonce: u64) -> TreeHash { - CurriedProgram { - program: P2_DELEGATED_BY_SINGLETON_PUZZLE_HASH, - args: Self::new(singleton_struct_hash, nonce), - } - .tree_hash() - } - - pub fn curry_tree_hash_with_launcher_id(launcher_id: Bytes32, nonce: u64) -> TreeHash { - CurriedProgram { - program: P2_DELEGATED_BY_SINGLETON_PUZZLE_HASH, - args: Self::from_launcher_id(launcher_id, nonce), - } - .tree_hash() - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct P2DelegatedBySingletonLayerSolution { - pub singleton_inner_puzzle_hash: Bytes32, - pub delegated_puzzle: P, - pub delegated_solution: S, -} diff --git a/src/layers/precommit_layer.rs b/src/layers/precommit_layer.rs deleted file mode 100644 index 21486c9e..00000000 --- a/src/layers/precommit_layer.rs +++ /dev/null @@ -1,371 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::{Bytes, Bytes32}, -}; -use chia_puzzles::SINGLETON_TOP_LAYER_V1_1_HASH; -use chia_wallet_sdk::{ - driver::{DriverError, Layer, Puzzle, SpendContext}, - types::Conditions, -}; -use clvm_traits::{clvm_quote, clvm_tuple, ClvmEncoder, FromClvm, ToClvm, ToClvmError}; -use clvmr::{Allocator, NodePtr}; -use hex_literal::hex; - -use crate::{CatNftMetadata, DefaultCatMakerArgs, SpendContextExt}; - -#[derive(Debug, Clone)] -#[must_use] -pub struct PrecommitLayer { - pub controller_singleton_struct_hash: Bytes32, - pub relative_block_height: u32, - pub payout_puzzle_hash: Bytes32, - pub refund_puzzle_hash: Bytes32, - pub value: V, -} - -impl PrecommitLayer { - pub fn new( - controller_singleton_struct_hash: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - refund_puzzle_hash: Bytes32, - value: V, - ) -> Self { - Self { - controller_singleton_struct_hash, - relative_block_height, - payout_puzzle_hash, - refund_puzzle_hash, - value, - } - } - - pub fn first_curry_hash( - controller_singleton_struct_hash: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - ) -> TreeHash { - CurriedProgram { - program: PRECOMMIT_LAYER_PUZZLE_HASH, - args: PrecommitLayer1stCurryArgs { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - singleton_struct_hash: controller_singleton_struct_hash, - relative_block_height, - payout_puzzle_hash, - }, - } - .tree_hash() - } - - pub fn puzzle_hash( - controller_singleton_struct_hash: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - refund_puzzle_hash: Bytes32, - value_hash: TreeHash, - ) -> TreeHash { - CurriedProgram { - program: Self::first_curry_hash( - controller_singleton_struct_hash, - relative_block_height, - payout_puzzle_hash, - ), - args: PrecommitLayer2ndCurryArgs { - refund_puzzle_hash, - value: value_hash, - }, - } - .tree_hash() - } - - pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result - where - V: Clone + ToClvm, - { - let prog_1st_curry = CurriedProgram { - program: ctx.precommit_layer_puzzle()?, - args: PrecommitLayer1stCurryArgs { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - singleton_struct_hash: self.controller_singleton_struct_hash, - relative_block_height: self.relative_block_height, - payout_puzzle_hash: self.payout_puzzle_hash, - }, - } - .to_clvm(ctx)?; - - Ok(CurriedProgram { - program: prog_1st_curry, - args: PrecommitLayer2ndCurryArgs { - refund_puzzle_hash: self.refund_puzzle_hash, - value: self.value.clone(), - }, - } - .to_clvm(ctx)?) - } - - pub fn construct_solution( - &self, - ctx: &mut SpendContext, - solution: PrecommitLayerSolution, - ) -> Result { - ctx.alloc(&solution) - } -} - -impl Layer for PrecommitLayer -where - V: ToClvm + FromClvm + Clone, -{ - type Solution = PrecommitLayerSolution; - - fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result, DriverError> { - let Some(puzzle_2nd_curry) = puzzle.as_curried() else { - return Ok(None); - }; - - let Some(curried) = CurriedProgram::::parse_puzzle(allocator, puzzle)? - else { - return Ok(None); - }; - let puzzle_1st_curry = Puzzle::parse(allocator, curried.program); - let Some(puzzle_1st_curry) = puzzle_1st_curry.as_curried() else { - return Ok(None); - }; - - if puzzle_1st_curry.mod_hash != PRECOMMIT_LAYER_PUZZLE_HASH { - return Ok(None); - } - - let args_2nd_curry = - PrecommitLayer2ndCurryArgs::::from_clvm(allocator, puzzle_2nd_curry.args)?; - let args_1st_curry = - PrecommitLayer1stCurryArgs::from_clvm(allocator, puzzle_1st_curry.args)?; - - Ok(Some(Self { - controller_singleton_struct_hash: args_1st_curry.singleton_struct_hash, - relative_block_height: args_1st_curry.relative_block_height, - payout_puzzle_hash: args_1st_curry.payout_puzzle_hash, - refund_puzzle_hash: args_2nd_curry.refund_puzzle_hash, - value: args_2nd_curry.value, - })) - } - - fn parse_solution( - allocator: &Allocator, - solution: NodePtr, - ) -> Result { - PrecommitLayerSolution::from_clvm(allocator, solution).map_err(DriverError::FromClvm) - } - - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - self.construct_puzzle(ctx) - } - - fn construct_solution( - &self, - ctx: &mut SpendContext, - solution: Self::Solution, - ) -> Result { - self.construct_solution(ctx, solution) - } -} - -pub const PRECOMMIT_LAYER_PUZZLE: [u8; 469] = hex!("ff02ffff01ff04ffff04ff10ffff04ff17ff808080ffff04ffff04ff18ffff04ff8202ffff808080ffff04ffff04ff14ffff04ffff03ff82017fff2fff5f80ffff04ff8202ffffff04ffff04ffff03ff82017fff2fff5f80ff8080ff8080808080ffff04ffff04ff1cffff04ffff0113ffff04ff82017fffff04ffff02ff2effff04ff02ffff04ff05ffff04ff0bffff04ff8205ffff808080808080ff8080808080ff8080808080ffff04ffff01ffffff5249ff3343ffff02ff02ffff03ff05ffff01ff0bff76ffff02ff3effff04ff02ffff04ff09ffff04ffff02ff1affff04ff02ffff04ff0dff80808080ff808080808080ffff016680ff0180ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff0bff56ffff02ff3effff04ff02ffff04ff05ffff04ffff02ff1affff04ff02ffff04ff07ff80808080ff808080808080ff0bff12ffff0bff12ff66ff0580ffff0bff12ff0bff468080ff018080"); - -pub const PRECOMMIT_LAYER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 10efe1dab105ef4780345baa2442196a26944040b12c0167375d79aaec89e33f - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct PrecommitLayer1stCurryArgs { - pub singleton_mod_hash: Bytes32, - pub singleton_struct_hash: Bytes32, - pub relative_block_height: u32, - pub payout_puzzle_hash: Bytes32, -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct PrecommitLayer2ndCurryArgs { - pub refund_puzzle_hash: Bytes32, - pub value: V, -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct PrecommitLayerSolution { - pub mode: u8, - pub my_amount: u64, - pub singleton_inner_puzzle_hash: Bytes32, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct CatalogPrecommitValue -where - S: ToTreeHash, -{ - pub tail_reveal: T, - pub initial_inner_puzzle_hash: Bytes32, - pub cat_maker_hash: Bytes32, - pub cat_maker_solution: S, -} - -impl CatalogPrecommitValue { - pub fn with_default_cat_maker( - payment_asset_tail_hash_hash: TreeHash, - initial_inner_puzzle_hash: Bytes32, - tail_reveal: T, - ) -> Self { - Self { - tail_reveal, - initial_inner_puzzle_hash, - cat_maker_hash: DefaultCatMakerArgs::curry_tree_hash( - payment_asset_tail_hash_hash.into(), - ) - .into(), - cat_maker_solution: (), - } - } - - pub fn initial_inner_puzzle( - ctx: &mut SpendContext, - owner_inner_puzzle_hash: Bytes32, - initial_metadata: CatNftMetadata, - ) -> Result { - let mut conds = Conditions::new().create_coin( - owner_inner_puzzle_hash, - 1, - ctx.hint(owner_inner_puzzle_hash)?, - ); - let updater_solution = ctx.alloc(&initial_metadata)?; - conds = conds.update_nft_metadata(ctx.any_metadata_updater()?, updater_solution); - conds = conds.remark(ctx.alloc(&"MEOW".to_string())?); - - ctx.alloc(&clvm_quote!(conds)) - } -} - -// On-chain, the CATalog precommit value is just (TAIL . HASH) -impl, T, S> ToClvm for CatalogPrecommitValue -where - S: ToTreeHash, - T: ToClvm + Clone, -{ - fn to_clvm(&self, encoder: &mut E) -> Result { - let hash: Bytes32 = clvm_tuple!( - self.initial_inner_puzzle_hash, - clvm_tuple!(self.cat_maker_hash, self.cat_maker_solution.tree_hash()) - ) - .tree_hash() - .into(); - - clvm_tuple!(self.tail_reveal.clone(), hash).to_clvm(encoder) - } -} - -// value is: -// (c -// (c (c cat_maker_reveal cat_maker_solution) (c pricing_puzzle_reveal pricing_solution)) -// (c (c secret handle) (c owner_launcher_id resolved_data))) -// ) -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct XchandlesPrecommitValue -where - CS: ToTreeHash, - PS: ToTreeHash, - S: ToTreeHash, -{ - pub cat_maker_hash: Bytes32, - pub cat_maker_solution: CS, - pub pricing_puzzle_hash: Bytes32, - pub pricing_solution: PS, - pub handle: String, - pub secret: S, - pub owner_launcher_id: Bytes32, - pub resolved_data: Bytes, -} - -impl XchandlesPrecommitValue -where - CS: ToTreeHash, - PS: ToTreeHash, - S: ToTreeHash, -{ - #[allow(clippy::too_many_arguments)] - pub fn new( - cat_maker_hash: Bytes32, - cat_maker_solution: CS, - pricing_puzzle_hash: Bytes32, - pricing_solution: PS, - handle: String, - secret: S, - owner_launcher_id: Bytes32, - resolved_data: Bytes, - ) -> Self { - Self { - cat_maker_hash, - cat_maker_solution, - pricing_puzzle_hash, - pricing_solution, - handle, - secret, - owner_launcher_id, - resolved_data, - } - } -} - -impl XchandlesPrecommitValue<(), TreeHash, Bytes32> { - #[allow(clippy::too_many_arguments)] - pub fn for_normal_registration( - payment_tail_hash_hash: TreeHash, - pricing_puzzle_hash: TreeHash, - pricing_puzzle_solution: PS, - handle: String, - secret: Bytes32, - owner_launcher_id: Bytes32, - resolved_data: Bytes, - ) -> Self - where - PS: ToTreeHash, - { - Self::new( - DefaultCatMakerArgs::curry_tree_hash(payment_tail_hash_hash.into()).into(), - (), - pricing_puzzle_hash.into(), - pricing_puzzle_solution.tree_hash(), - handle, - secret, - owner_launcher_id, - resolved_data, - ) - } -} - -// On-chain, the precommit value is just a hash of the data it stores -impl, CS, PS, S> ToClvm for XchandlesPrecommitValue -where - CS: ToTreeHash, - PS: ToTreeHash, - S: ToTreeHash, -{ - fn to_clvm(&self, encoder: &mut E) -> Result { - let data_hash: Bytes32 = clvm_tuple!( - clvm_tuple!( - clvm_tuple!(self.cat_maker_hash, self.cat_maker_solution.tree_hash()), - clvm_tuple!(self.pricing_puzzle_hash, self.pricing_solution.tree_hash()) - ), - clvm_tuple!( - clvm_tuple!(self.handle.tree_hash(), self.secret.tree_hash()), - clvm_tuple!(self.owner_launcher_id, self.resolved_data.tree_hash()) - ) - ) - .tree_hash() - .into(); - - data_hash.to_clvm(encoder) - } -} diff --git a/src/layers/state_scheduler_layer.rs b/src/layers/state_scheduler_layer.rs deleted file mode 100644 index f050f340..00000000 --- a/src/layers/state_scheduler_layer.rs +++ /dev/null @@ -1,171 +0,0 @@ -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}, - types::{Condition, Conditions}, -}; -use clvm_traits::{clvm_quote, FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; -use hex_literal::hex; - -use crate::SpendContextExt; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StateSchedulerLayer { - pub receiver_singleton_struct_hash: Bytes32, - pub new_state_hash: Bytes32, - pub required_block_height: u32, - pub new_puzzle_hash: Bytes32, -} - -impl StateSchedulerLayer { - pub fn new( - receiver_singleton_struct_hash: Bytes32, - new_state_hash: Bytes32, - required_block_height: u32, - new_puzzle_hash: Bytes32, - ) -> Self { - Self { - receiver_singleton_struct_hash, - new_state_hash, - required_block_height, - new_puzzle_hash, - } - } -} - -impl Layer for StateSchedulerLayer { - type Solution = StateSchedulerLayerSolution<()>; - - fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result, DriverError> { - let Some(puzzle) = puzzle.as_curried() else { - return Ok(None); - }; - - if puzzle.mod_hash != STATE_SCHEDULER_PUZZLE_HASH { - return Ok(None); - } - - let args = StateSchedulerLayerArgs::::from_clvm(allocator, puzzle.args)?; - - if args.singleton_mod_hash != SINGLETON_TOP_LAYER_V1_1_HASH.into() { - return Err(DriverError::NonStandardLayer); - } - - let conditions = Conditions::::from_clvm(allocator, args.inner_puzzle)?; - let ( - Some(Condition::AssertHeightAbsolute(assert_height_condition)), - Some(Condition::CreateCoin(create_coin_condition)), - ) = conditions - .into_iter() - .fold( - (None, None), - |(assert_height, create_coin), cond| match cond { - Condition::AssertHeightAbsolute(_) if assert_height.is_none() => { - (Some(cond), create_coin) - } - Condition::CreateCoin(_) if create_coin.is_none() => { - (assert_height, Some(cond)) - } - _ => (assert_height, create_coin), - }, - ) - else { - return Err(DriverError::NonStandardLayer); - }; - - Ok(Some(Self { - receiver_singleton_struct_hash: args.receiver_singleton_struct_hash, - new_state_hash: args.message, - required_block_height: assert_height_condition.height, - new_puzzle_hash: create_coin_condition.puzzle_hash, - })) - } - - fn parse_solution( - allocator: &Allocator, - solution: NodePtr, - ) -> Result { - StateSchedulerLayerSolution::from_clvm(allocator, solution).map_err(DriverError::FromClvm) - } - - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - let base_conditions = Conditions::new() - .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))?; - - CurriedProgram { - program: ctx.state_scheduler_puzzle()?, - args: StateSchedulerLayerArgs:: { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - receiver_singleton_struct_hash: self.receiver_singleton_struct_hash, - message: self.new_state_hash, - inner_puzzle, - }, - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - fn construct_solution( - &self, - ctx: &mut SpendContext, - solution: Self::Solution, - ) -> Result { - ctx.alloc(&solution) - } -} - -pub const STATE_SCHEDULER_PUZZLE: [u8; 285] = hex!("ff02ffff01ff04ffff04ff04ffff04ffff0112ffff04ff17ffff04ffff0bff2effff0bff0affff0bff0aff36ff0580ffff0bff0affff0bff3effff0bff0affff0bff0aff36ff0b80ffff0bff0affff0bff3effff0bff0affff0bff0aff36ff5f80ffff0bff0aff36ff26808080ff26808080ff26808080ff8080808080ffff02ff2fff7f8080ffff04ffff01ff42ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff018080"); - -pub const STATE_SCHEDULER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 13fe7833751a6fe582caa09d48978d8d1b016d224cb0c10e538184ab22df9c13 - " -)); - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(curry)] -pub struct StateSchedulerLayerArgs { - pub singleton_mod_hash: Bytes32, - pub receiver_singleton_struct_hash: Bytes32, - pub message: M, - pub inner_puzzle: I, -} - -impl StateSchedulerLayerArgs -where - M: ToTreeHash, - I: ToTreeHash, -{ - pub fn curry_tree_hash( - receiver_singleton_struct_hash: Bytes32, - message: M, - inner_puzzle: I, - ) -> TreeHash { - CurriedProgram:: { - program: STATE_SCHEDULER_PUZZLE_HASH, - args: StateSchedulerLayerArgs { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - receiver_singleton_struct_hash, - message: message.tree_hash(), - inner_puzzle: inner_puzzle.tree_hash(), - }, - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct StateSchedulerLayerSolution { - pub other_singleton_inner_puzzle_hash: Bytes32, - #[clvm(rest)] - pub inner_solution: I, -} diff --git a/src/layers/verification_layer.rs b/src/layers/verification_layer.rs deleted file mode 100644 index edad44fd..00000000 --- a/src/layers/verification_layer.rs +++ /dev/null @@ -1,242 +0,0 @@ -use std::fmt::Debug; - -use chia::{ - clvm_traits::{FromClvm, ToClvm}, - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonStruct, -}; -use chia_puzzles::{SINGLETON_LAUNCHER_HASH, SINGLETON_TOP_LAYER_V1_1_HASH}; -use chia_wallet_sdk::driver::{DriverError, Layer, Puzzle, SpendContext}; - -use clvm_traits::clvm_list; -use clvmr::{Allocator, NodePtr}; -use hex_literal::hex; - -use crate::{CatNftMetadata, SpendContextExt}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct VerificationLayer { - pub revocation_singleton_launcher_id: Bytes32, - pub verified_data: VerifiedData, -} - -impl VerificationLayer { - pub fn new(revocation_singleton_launcher_id: Bytes32, verified_data: VerifiedData) -> Self { - Self { - revocation_singleton_launcher_id, - verified_data, - } - } -} - -impl Layer for VerificationLayer { - type Solution = VerificationLayerSolution; - - fn parse_puzzle(allocator: &Allocator, puzzle: Puzzle) -> Result, DriverError> { - let Some(puzzle_2nd_curry) = puzzle.as_curried() else { - return Ok(None); - }; - - let puzzle_2nd_curry = - CurriedProgram::::from_clvm(allocator, puzzle_2nd_curry.curried_ptr)?; - let puzzle_1st_curry = Puzzle::parse(allocator, puzzle_2nd_curry.program); - let Some(puzzle_1st_curry) = puzzle_1st_curry.as_curried() else { - return Ok(None); - }; - - if puzzle_1st_curry.mod_hash != VERIFICATION_LAYER_PUZZLE_HASH { - return Ok(None); - } - - let args_2nd_curry = VerificationLayer2ndCurryArgs::::from_clvm( - allocator, - puzzle_2nd_curry.args, - )?; - let args_1st_curry = - VerificationLayer1stCurryArgs::from_clvm(allocator, puzzle_1st_curry.args)?; - - if args_1st_curry - .revocation_singleton_struct - .launcher_puzzle_hash - != SINGLETON_LAUNCHER_HASH.into() - || args_1st_curry.revocation_singleton_struct.mod_hash - != SINGLETON_TOP_LAYER_V1_1_HASH.into() - { - return Err(DriverError::NonStandardLayer); - } - - if args_2nd_curry.self_hash - != VerificationLayer1stCurryArgs::curry_tree_hash( - args_1st_curry.revocation_singleton_struct.launcher_id, - ) - .into() - { - return Err(DriverError::NonStandardLayer); - } - - Ok(Some(Self { - revocation_singleton_launcher_id: args_1st_curry - .revocation_singleton_struct - .launcher_id, - verified_data: args_2nd_curry.verified_data, - })) - } - - fn parse_solution( - allocator: &Allocator, - solution: NodePtr, - ) -> Result { - VerificationLayerSolution::from_clvm(allocator, solution).map_err(DriverError::FromClvm) - } - - fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - let puzzle_1st_curry = CurriedProgram { - program: ctx.verification_puzzle()?, - args: VerificationLayer1stCurryArgs { - revocation_singleton_struct: SingletonStruct::new( - self.revocation_singleton_launcher_id, - ), - }, - } - .to_clvm(ctx)?; - let self_hash: Bytes32 = - VerificationLayer1stCurryArgs::curry_tree_hash(self.revocation_singleton_launcher_id) - .into(); - - CurriedProgram { - program: puzzle_1st_curry, - args: VerificationLayer2ndCurryArgs { - self_hash, - verified_data: self.verified_data.clone(), - }, - } - .to_clvm(ctx) - .map_err(DriverError::ToClvm) - } - - fn construct_solution( - &self, - ctx: &mut SpendContext, - solution: Self::Solution, - ) -> Result { - ctx.alloc(&solution) - } -} - -pub const VERIFICATION_LAYER_PUZZLE: [u8; 576] = hex!("ff02ffff01ff02ffff03ffff09ff2fff8080ffff01ff04ffff04ff14ffff01ff808080ffff04ffff04ff08ffff04ffff0bff56ffff0bff0affff0bff0aff66ff0b80ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ffff0bffff0101ff0b8080ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ffff02ff1effff04ff02ffff04ff17ff8080808080ffff0bff0aff66ff46808080ff46808080ff46808080ffff01ff01808080ff808080ffff01ff04ffff04ff08ffff01ff80ff818f8080ffff04ffff04ff1cffff04ffff0112ffff04ff80ffff04ffff0bff56ffff0bff0affff0bff0aff66ff0980ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ffff02ff1effff04ff02ffff04ff05ff8080808080ffff0bff0affff0bff76ffff0bff0affff0bff0aff66ff2f80ffff0bff0aff66ff46808080ff46808080ff46808080ff8080808080ff80808080ff0180ffff04ffff01ffff33ff3e43ff02ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff1effff04ff02ffff04ff09ff80808080ffff02ff1effff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff018080"); - -pub const VERIFICATION_LAYER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 72600e1408134c0def58ce09d1b9edce15ffcfd5f5a2ebcd421d4a47ec4518c2 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct VerificationLayer1stCurryArgs { - pub revocation_singleton_struct: SingletonStruct, -} - -impl VerificationLayer1stCurryArgs { - pub fn curry_tree_hash(revocation_singleton_launcher_id: Bytes32) -> TreeHash { - CurriedProgram { - program: VERIFICATION_LAYER_PUZZLE_HASH, - args: VerificationLayer1stCurryArgs { - revocation_singleton_struct: SingletonStruct::new(revocation_singleton_launcher_id), - }, - } - .tree_hash() - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct VerificationLayer2ndCurryArgs { - pub self_hash: Bytes32, - pub verified_data: T, -} - -impl VerificationLayer2ndCurryArgs -where - T: ToTreeHash, -{ - pub fn curry_tree_hash( - revocation_singleton_launcher_id: Bytes32, - verified_data: T, - ) -> TreeHash { - let self_hash = - VerificationLayer1stCurryArgs::curry_tree_hash(revocation_singleton_launcher_id); - - CurriedProgram { - program: self_hash, - args: VerificationLayer2ndCurryArgs { - self_hash: self_hash.into(), - verified_data: verified_data.tree_hash(), - }, - } - .tree_hash() - } -} - -#[derive(FromClvm, ToClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct VerificationLayerSolution { - pub revocation_singleton_inner_puzzle_hash: Option, -} - -impl VerificationLayerSolution { - pub fn oracle() -> Self { - Self { - revocation_singleton_inner_puzzle_hash: None, - } - } - - pub fn revocation(revocation_singleton_inner_puzzle_hash: Bytes32) -> Self { - Self { - revocation_singleton_inner_puzzle_hash: Some(revocation_singleton_inner_puzzle_hash), - } - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct VerifiedData { - pub version: u32, - pub asset_id: Bytes32, - pub data_hash: Bytes32, - #[clvm(rest)] - pub comment: String, -} - -impl VerifiedData { - pub fn data_hash_from_cat_nft_metadata(metadata: &CatNftMetadata) -> Bytes32 { - clvm_list!( - metadata.ticker.clone(), - metadata.name.clone(), - metadata.description.clone(), - metadata.image_hash, - metadata.metadata_hash, - metadata.license_hash, - ) - .tree_hash() - .into() - } - - pub fn from_cat_nft_metadata( - asset_id: Bytes32, - metadata: &CatNftMetadata, - comment: String, - ) -> Self { - Self { - version: 1, - asset_id, - data_hash: Self::data_hash_from_cat_nft_metadata(metadata), - comment, - } - } - - pub fn get_hint(&self) -> Bytes32 { - self.data_hash - } -} diff --git a/src/lib.rs b/src/lib.rs index 6668e9d9..7d713231 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,371 +1,3 @@ -use chia_wallet_sdk::driver::{DriverError, SpendContext}; -use clvmr::NodePtr; - -mod benchmarker; -mod cat_nft_metadata; mod cli; -mod debug; -mod drivers; -mod layers; -mod name_nft_metadata; -mod primitives; -pub use cat_nft_metadata::*; pub use cli::*; -pub use debug::*; -pub use drivers::*; -pub use layers::*; -pub use name_nft_metadata::*; -pub use primitives::*; -pub trait SpendContextExt { - fn default_finalizer_puzzle(&mut self) -> Result; - fn action_layer_puzzle(&mut self) -> Result; - fn delegated_state_action_puzzle(&mut self) -> Result; - fn catalog_register_action_puzzle(&mut self) -> Result; - fn catalog_refund_action_puzzle(&mut self) -> Result; - fn uniqueness_prelauncher_puzzle(&mut self) -> Result; - fn precommit_layer_puzzle(&mut self) -> Result; - fn slot_puzzle(&mut self) -> Result; - fn any_metadata_updater(&mut self) -> Result; - fn verification_puzzle(&mut self) -> Result; - fn xchandles_register_puzzle(&mut self) -> Result; - fn xchandles_update_puzzle(&mut self) -> Result; - fn xchandles_extend_puzzle(&mut self) -> Result; - fn xchandles_expire_puzzle(&mut self) -> Result; - fn xchandles_oracle_puzzle(&mut self) -> Result; - fn xchandles_refund_puzzle(&mut self) -> Result; - fn xchandles_factor_pricing_puzzle(&mut self) -> Result; - fn xchandles_exponential_premium_renew_puzzle(&mut self) -> Result; - fn default_cat_maker_puzzle(&mut self) -> Result; - fn reward_distributor_add_incentives_action_puzzle(&mut self) -> Result; - fn reward_distributor_add_entry_action_puzzle(&mut self) -> Result; - fn reward_distributor_commit_incentives_action_puzzle( - &mut self, - ) -> Result; - fn reward_distributor_initiate_payout_action_puzzle(&mut self) -> Result; - fn reward_distributor_new_epoch_action_puzzle(&mut self) -> Result; - fn reward_distributor_remove_entry_action_puzzle(&mut self) -> Result; - fn reward_distributor_sync_action_puzzle(&mut self) -> Result; - fn reward_distributor_withdraw_incentives_action_puzzle( - &mut self, - ) -> Result; - fn reward_distributor_stake_action_puzzle(&mut self) -> Result; - fn reward_distributor_unstake_action_puzzle(&mut self) -> Result; - fn nonce_wrapper_puzzle(&mut self) -> Result; - fn reserve_finalizer_puzzle(&mut self) -> Result; - fn p2_delegated_by_singleton_puzzle(&mut self) -> Result; - fn state_scheduler_puzzle(&mut self) -> Result; - fn p2_m_of_n_delegate_direct_puzzle(&mut self) -> Result; - fn default_reserve_amount_from_state_program(&mut self) -> Result; - fn verification_asserter_puzzle(&mut self) -> Result; - fn catalog_verification_maker_puzzle(&mut self) -> Result; -} - -impl SpendContextExt for SpendContext { - /// Allocate thedefault finalizer puzzle and return its pointer. - fn default_finalizer_puzzle(&mut self) -> Result { - self.puzzle(DEFAULT_FINALIZER_PUZZLE_HASH, &DEFAULT_FINALIZER_PUZZLE) - } - - /// Allocate the action layer puzzle and return its pointer. - fn action_layer_puzzle(&mut self) -> Result { - self.puzzle(ACTION_LAYER_PUZZLE_HASH, &ACTION_LAYER_PUZZLE) - } - - /// Allocate the delegated state action puzzle and return its pointer. - fn delegated_state_action_puzzle(&mut self) -> Result { - self.puzzle( - DELEGATED_STATE_ACTION_PUZZLE_HASH, - &DELEGATED_STATE_ACTION_PUZZLE, - ) - } - - /// Allocate the catalog register action puzzle and return its pointer. - fn catalog_register_action_puzzle(&mut self) -> Result { - self.puzzle(CATALOG_REGISTER_PUZZLE_HASH, &CATALOG_REGISTER_PUZZLE) - } - - /// Allocate the catalog refund action puzzle and return its pointer. - fn catalog_refund_action_puzzle(&mut self) -> Result { - self.puzzle(CATALOG_REFUND_PUZZLE_HASH, &CATALOG_REFUND_PUZZLE) - } - - /// Allocate the uniqueness prelauncher puzzle and return its pointer. - fn uniqueness_prelauncher_puzzle(&mut self) -> Result { - self.puzzle( - UNIQUENESS_PRELAUNCHER_PUZZLE_HASH, - &UNIQUENESS_PRELAUNCHER_PUZZLE, - ) - } - - /// Allocate the precommit coin puzzle and return its pointer. - fn precommit_layer_puzzle(&mut self) -> Result { - self.puzzle(PRECOMMIT_LAYER_PUZZLE_HASH, &PRECOMMIT_LAYER_PUZZLE) - } - - /// Allocate the slot puzzle and return its pointer. - fn slot_puzzle(&mut self) -> Result { - self.puzzle(SLOT_PUZZLE_HASH, &SLOT_PUZZLE) - } - - /// Allocate the any metadata updater puzzle and return its pointer. - fn any_metadata_updater(&mut self) -> Result { - self.puzzle(ANY_METADATA_UPDATER_HASH, &ANY_METADATA_UPDATER) - } - - /// Allocate the verification puzzle and return its pointer. - fn verification_puzzle(&mut self) -> Result { - self.puzzle(VERIFICATION_LAYER_PUZZLE_HASH, &VERIFICATION_LAYER_PUZZLE) - } - - /// Allocate the XCHandles register puzzle and return its pointer. - fn xchandles_register_puzzle(&mut self) -> Result { - self.puzzle(XCHANDLES_REGISTER_PUZZLE_HASH, &XCHANDLES_REGISTER_PUZZLE) - } - - /// Allocate the XCHandles update puzzle and return its pointer. - fn xchandles_update_puzzle(&mut self) -> Result { - self.puzzle(XCHANDLES_UPDATE_PUZZLE_HASH, &XCHANDLES_UPDATE_PUZZLE) - } - - /// Allocate the XCHandles extend puzzle and return its pointer. - fn xchandles_extend_puzzle(&mut self) -> Result { - self.puzzle(XCHANDLES_EXTEND_PUZZLE_HASH, &XCHANDLES_EXTEND_PUZZLE) - } - - /// Allocate the XCHandles expire puzzle and return its pointer. - fn xchandles_expire_puzzle(&mut self) -> Result { - self.puzzle(XCHANDLES_EXPIRE_PUZZLE_HASH, &XCHANDLES_EXPIRE_PUZZLE) - } - - /// Allocate the XCHandles oracle puzzle and return its pointer. - fn xchandles_oracle_puzzle(&mut self) -> Result { - self.puzzle(XCHANDLES_ORACLE_PUZZLE_HASH, &XCHANDLES_ORACLE_PUZZLE) - } - - /// Allocate the XCHandles refund puzzle and return its pointer. - fn xchandles_refund_puzzle(&mut self) -> Result { - self.puzzle(XCHANDLES_REFUND_PUZZLE_HASH, &XCHANDLES_REFUND_PUZZLE) - } - - /// Allocate the XCHandles factor pricing puzzle and return its pointer. - fn xchandles_factor_pricing_puzzle(&mut self) -> Result { - self.puzzle( - XCHANDLES_FACTOR_PRICING_PUZZLE_HASH, - &XCHANDLES_FACTOR_PRICING_PUZZLE, - ) - } - - /// Allocate the XCHandles exponential premium renew puzzle and return its pointer. - fn xchandles_exponential_premium_renew_puzzle(&mut self) -> Result { - self.puzzle( - XCHANDLES_EXPONENTIAL_PREMIUM_RENEW_PUZZLE_HASH, - &XCHANDLES_EXPONENTIAL_PREMIUM_RENEW_PUZZLE, - ) - } - - /// Allocate the default CAT maker puzzle and return its pointer. - fn default_cat_maker_puzzle(&mut self) -> Result { - self.puzzle(DEFAULT_CAT_MAKER_PUZZLE_HASH, &DEFAULT_CAT_MAKER_PUZZLE) - } - - /// Allocate the reward distributor add incentives action puzzle and return its pointer. - fn reward_distributor_add_incentives_action_puzzle(&mut self) -> Result { - self.puzzle( - REWARD_DISTRIBUTOR_ADD_INCENTIVES_PUZZLE_HASH, - &REWARD_DISTRIBUTOR_ADD_INCENTIVES_PUZZLE, - ) - } - - /// Allocate the reward distributor add entry action puzzle and return its pointer. - fn reward_distributor_add_entry_action_puzzle(&mut self) -> Result { - self.puzzle( - REWARD_DISTRIBUTOR_ADD_ENTRY_PUZZLE_HASH, - &REWARD_DISTRIBUTOR_ADD_ENTRY_PUZZLE, - ) - } - - /// Allocate the reward distributor commit incentives action puzzle and return its pointer. - fn reward_distributor_commit_incentives_action_puzzle( - &mut self, - ) -> Result { - self.puzzle( - REWARD_DISTRIBUTOR_COMMIT_INCENTIVES_PUZZLE_HASH, - &REWARD_DISTRIBUTOR_COMMIT_INCENTIVES_PUZZLE, - ) - } - - /// Allocate the reward distributor initiate payout action puzzle and return its pointer. - fn reward_distributor_initiate_payout_action_puzzle(&mut self) -> Result { - self.puzzle( - REWARD_DISTRIBUTOR_INITIATE_PAYOUT_PUZZLE_HASH, - &REWARD_DISTRIBUTOR_INITIATE_PAYOUT_PUZZLE, - ) - } - - /// Allocate the reward distributor new epoch action puzzle and return its pointer. - fn reward_distributor_new_epoch_action_puzzle(&mut self) -> Result { - self.puzzle( - REWARD_DISTRIBUTOR_NEW_EPOCH_PUZZLE_HASH, - &REWARD_DISTRIBUTOR_NEW_EPOCH_PUZZLE, - ) - } - - /// Allocate the reward distributor remove entry action puzzle and return its pointer. - fn reward_distributor_remove_entry_action_puzzle(&mut self) -> Result { - self.puzzle( - REWARD_DISTRIBUTOR_REMOVE_ENTRY_PUZZLE_HASH, - &REWARD_DISTRIBUTOR_REMOVE_ENTRY_PUZZLE, - ) - } - - /// Allocate the reward distributor sync action puzzle and return its pointer. - fn reward_distributor_sync_action_puzzle(&mut self) -> Result { - self.puzzle( - REWARD_DISTRIBUTOR_SYNC_PUZZLE_HASH, - &REWARD_DISTRIBUTOR_SYNC_PUZZLE, - ) - } - - /// Allocate the reward distributor withdraw incentives action puzzle and return its pointer. - fn reward_distributor_withdraw_incentives_action_puzzle( - &mut self, - ) -> Result { - self.puzzle( - REWARD_DISTRIBUTOR_WITHDRAW_INCENTIVES_PUZZLE_HASH, - &REWARD_DISTRIBUTOR_WITHDRAW_INCENTIVES_PUZZLE, - ) - } - - /// Allocate the reward distributor stake action puzzle and return its pointer. - fn reward_distributor_stake_action_puzzle(&mut self) -> Result { - self.puzzle( - REWARD_DISTRIBUTOR_STAKE_PUZZLE_HASH, - &REWARD_DISTRIBUTOR_STAKE_PUZZLE, - ) - } - - /// Allocate the nonce wrapper puzzle and return its pointer. - fn nonce_wrapper_puzzle(&mut self) -> Result { - self.puzzle(NONCE_WRAPPER_PUZZLE_HASH, &NONCE_WRAPPER_PUZZLE) - } - - /// Allocate the reward distributor unstake action puzzle and return its pointer. - fn reward_distributor_unstake_action_puzzle(&mut self) -> Result { - self.puzzle( - REWARD_DISTRIBUTOR_UNSTAKE_PUZZLE_HASH, - &REWARD_DISTRIBUTOR_UNSTAKE_PUZZLE, - ) - } - - /// Allocate the reserve finalizer puzzle and return its pointer. - fn reserve_finalizer_puzzle(&mut self) -> Result { - self.puzzle(RESERVE_FINALIZER_PUZZLE_HASH, &RESERVE_FINALIZER_PUZZLE) - } - - /// Allocate the P2 delegated by singleton puzzle and return its pointer. - fn p2_delegated_by_singleton_puzzle(&mut self) -> Result { - self.puzzle( - P2_DELEGATED_BY_SINGLETON_PUZZLE_HASH, - &P2_DELEGATED_BY_SINGLETON_PUZZLE, - ) - } - - /// Allocate the state scheduler puzzle and return its pointer. - fn state_scheduler_puzzle(&mut self) -> Result { - self.puzzle(STATE_SCHEDULER_PUZZLE_HASH, &STATE_SCHEDULER_PUZZLE) - } - - /// Allocate the P2 M of N delegate direct puzzle and return its pointer. - fn p2_m_of_n_delegate_direct_puzzle(&mut self) -> Result { - self.puzzle( - P2_M_OF_N_DELEGATE_DIRECT_PUZZLE_HASH, - &P2_M_OF_N_DELEGATE_DIRECT_PUZZLE, - ) - } - - /// Allocate the default reserve amount from state program and return its pointer. - fn default_reserve_amount_from_state_program(&mut self) -> Result { - self.puzzle( - RESERVE_FINALIZER_DEFAULT_RESERVE_AMOUNT_FROM_STATE_PROGRAM_HASH, - &RESERVE_FINALIZER_DEFAULT_RESERVE_AMOUNT_FROM_STATE_PROGRAM, - ) - } - - /// Allocate the verification asserter puzzle and return its pointer. - fn verification_asserter_puzzle(&mut self) -> Result { - self.puzzle( - VERIFICATION_ASSERTER_PUZZLE_HASH, - &VERIFICATION_ASSERTER_PUZZLE, - ) - } - - /// Allocate the catalog verification maker puzzle and return its pointer. - fn catalog_verification_maker_puzzle(&mut self) -> Result { - self.puzzle( - CATALOG_VERIFICATION_MAKER_PUZZLE_HASH, - &CATALOG_VERIFICATION_MAKER_PUZZLE, - ) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use chia::clvm_utils::tree_hash; - - // we really have to expose this in chia-sdk-test - macro_rules! assert_puzzle_hash { - ($puzzle:ident => $puzzle_hash:ident) => { - let mut a = clvmr::Allocator::new(); - let ptr = clvmr::serde::node_from_bytes(&mut a, &$puzzle)?; - let hash = tree_hash(&mut a, ptr); - assert_eq!($puzzle_hash, hash); - }; - } - - #[test] - fn test_puzzle_hashes() -> anyhow::Result<()> { - assert_puzzle_hash!(DEFAULT_FINALIZER_PUZZLE => DEFAULT_FINALIZER_PUZZLE_HASH); - assert_puzzle_hash!(ACTION_LAYER_PUZZLE => ACTION_LAYER_PUZZLE_HASH); - assert_puzzle_hash!(DELEGATED_STATE_ACTION_PUZZLE => DELEGATED_STATE_ACTION_PUZZLE_HASH); - assert_puzzle_hash!(CATALOG_REGISTER_PUZZLE => CATALOG_REGISTER_PUZZLE_HASH); - assert_puzzle_hash!(CATALOG_REFUND_PUZZLE => CATALOG_REFUND_PUZZLE_HASH); - assert_puzzle_hash!(UNIQUENESS_PRELAUNCHER_PUZZLE => UNIQUENESS_PRELAUNCHER_PUZZLE_HASH); - assert_puzzle_hash!(PRECOMMIT_LAYER_PUZZLE => PRECOMMIT_LAYER_PUZZLE_HASH); - assert_puzzle_hash!(SLOT_PUZZLE => SLOT_PUZZLE_HASH); - assert_puzzle_hash!(ANY_METADATA_UPDATER => ANY_METADATA_UPDATER_HASH); - assert_puzzle_hash!(VERIFICATION_LAYER_PUZZLE => VERIFICATION_LAYER_PUZZLE_HASH); - assert_puzzle_hash!(XCHANDLES_REGISTER_PUZZLE => XCHANDLES_REGISTER_PUZZLE_HASH); - assert_puzzle_hash!(XCHANDLES_UPDATE_PUZZLE => XCHANDLES_UPDATE_PUZZLE_HASH); - assert_puzzle_hash!(XCHANDLES_EXTEND_PUZZLE => XCHANDLES_EXTEND_PUZZLE_HASH); - assert_puzzle_hash!(XCHANDLES_EXPIRE_PUZZLE => XCHANDLES_EXPIRE_PUZZLE_HASH); - assert_puzzle_hash!(XCHANDLES_ORACLE_PUZZLE => XCHANDLES_ORACLE_PUZZLE_HASH); - assert_puzzle_hash!(XCHANDLES_REFUND_PUZZLE => XCHANDLES_REFUND_PUZZLE_HASH); - assert_puzzle_hash!(XCHANDLES_FACTOR_PRICING_PUZZLE => XCHANDLES_FACTOR_PRICING_PUZZLE_HASH); - assert_puzzle_hash!(XCHANDLES_EXPONENTIAL_PREMIUM_RENEW_PUZZLE => XCHANDLES_EXPONENTIAL_PREMIUM_RENEW_PUZZLE_HASH); - assert_puzzle_hash!(DEFAULT_CAT_MAKER_PUZZLE => DEFAULT_CAT_MAKER_PUZZLE_HASH); - assert_puzzle_hash!(REWARD_DISTRIBUTOR_ADD_INCENTIVES_PUZZLE => REWARD_DISTRIBUTOR_ADD_INCENTIVES_PUZZLE_HASH); - assert_puzzle_hash!(REWARD_DISTRIBUTOR_ADD_ENTRY_PUZZLE => REWARD_DISTRIBUTOR_ADD_ENTRY_PUZZLE_HASH); - assert_puzzle_hash!(REWARD_DISTRIBUTOR_COMMIT_INCENTIVES_PUZZLE => REWARD_DISTRIBUTOR_COMMIT_INCENTIVES_PUZZLE_HASH); - assert_puzzle_hash!(REWARD_DISTRIBUTOR_INITIATE_PAYOUT_PUZZLE => REWARD_DISTRIBUTOR_INITIATE_PAYOUT_PUZZLE_HASH); - assert_puzzle_hash!(REWARD_DISTRIBUTOR_NEW_EPOCH_PUZZLE => REWARD_DISTRIBUTOR_NEW_EPOCH_PUZZLE_HASH); - assert_puzzle_hash!(REWARD_DISTRIBUTOR_REMOVE_ENTRY_PUZZLE => REWARD_DISTRIBUTOR_REMOVE_ENTRY_PUZZLE_HASH); - assert_puzzle_hash!(REWARD_DISTRIBUTOR_SYNC_PUZZLE => REWARD_DISTRIBUTOR_SYNC_PUZZLE_HASH); - assert_puzzle_hash!(REWARD_DISTRIBUTOR_WITHDRAW_INCENTIVES_PUZZLE => REWARD_DISTRIBUTOR_WITHDRAW_INCENTIVES_PUZZLE_HASH); - assert_puzzle_hash!(REWARD_DISTRIBUTOR_STAKE_PUZZLE => REWARD_DISTRIBUTOR_STAKE_PUZZLE_HASH); - assert_puzzle_hash!(REWARD_DISTRIBUTOR_UNSTAKE_PUZZLE => REWARD_DISTRIBUTOR_UNSTAKE_PUZZLE_HASH); - assert_puzzle_hash!(NONCE_WRAPPER_PUZZLE => NONCE_WRAPPER_PUZZLE_HASH); - assert_puzzle_hash!(RESERVE_FINALIZER_PUZZLE => RESERVE_FINALIZER_PUZZLE_HASH); - assert_puzzle_hash!(P2_DELEGATED_BY_SINGLETON_PUZZLE => P2_DELEGATED_BY_SINGLETON_PUZZLE_HASH); - assert_puzzle_hash!(STATE_SCHEDULER_PUZZLE => STATE_SCHEDULER_PUZZLE_HASH); - assert_puzzle_hash!(P2_M_OF_N_DELEGATE_DIRECT_PUZZLE => P2_M_OF_N_DELEGATE_DIRECT_PUZZLE_HASH); - assert_puzzle_hash!( - RESERVE_FINALIZER_DEFAULT_RESERVE_AMOUNT_FROM_STATE_PROGRAM => - RESERVE_FINALIZER_DEFAULT_RESERVE_AMOUNT_FROM_STATE_PROGRAM_HASH - ); - assert_puzzle_hash!(VERIFICATION_ASSERTER_PUZZLE => VERIFICATION_ASSERTER_PUZZLE_HASH); - assert_puzzle_hash!(CATALOG_VERIFICATION_MAKER_PUZZLE => CATALOG_VERIFICATION_MAKER_PUZZLE_HASH); - Ok(()) - } -} diff --git a/src/name_nft_metadata.rs b/src/name_nft_metadata.rs deleted file mode 100644 index ae2d1685..00000000 --- a/src/name_nft_metadata.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::fmt::Debug; - -use chia::protocol::Bytes32; -use clvm_traits::{ClvmDecoder, ClvmEncoder, FromClvm, FromClvmError, Raw, ToClvm, ToClvmError}; - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct NameNftMetadata { - pub display_name: Option, - pub description: Option, - pub did_launcher_id: Option, - pub receive_puzzle_hash: Option, - pub image_uris: Vec, - pub image_hash: Bytes32, - pub metadata_uris: Vec, - pub metadata_hash: Bytes32, - pub license_uris: Vec, - pub license_hash: Bytes32, -} - -impl> FromClvm for NameNftMetadata { - fn from_clvm(decoder: &D, node: N) -> Result { - let items: Vec<(String, Raw)> = FromClvm::from_clvm(decoder, node)?; - let mut metadata = Self::default(); - - for (key, Raw(ptr)) in items { - match key.as_str() { - "dn" => metadata.display_name = FromClvm::from_clvm(decoder, ptr)?, - "d" => metadata.description = FromClvm::from_clvm(decoder, ptr)?, - "did" => metadata.did_launcher_id = FromClvm::from_clvm(decoder, ptr)?, - "ph" => metadata.receive_puzzle_hash = FromClvm::from_clvm(decoder, ptr)?, - "u" => metadata.image_uris = FromClvm::from_clvm(decoder, ptr)?, - "h" => metadata.image_hash = FromClvm::from_clvm(decoder, ptr)?, - "mu" => metadata.metadata_uris = FromClvm::from_clvm(decoder, ptr)?, - "mh" => metadata.metadata_hash = FromClvm::from_clvm(decoder, ptr)?, - "lu" => metadata.license_uris = FromClvm::from_clvm(decoder, ptr)?, - "lh" => metadata.license_hash = FromClvm::from_clvm(decoder, ptr)?, - _ => (), - } - } - - Ok(metadata) - } -} - -impl> ToClvm for NameNftMetadata { - fn to_clvm(&self, encoder: &mut E) -> Result { - let mut items: Vec<(&str, Raw)> = Vec::new(); - - if let Some(display_name) = &self.display_name { - items.push(("dn", Raw(display_name.to_clvm(encoder)?))); - } - if let Some(description) = &self.description { - items.push(("d", Raw(description.to_clvm(encoder)?))); - } - if let Some(did_launcher_id) = &self.did_launcher_id { - items.push(("did", Raw(did_launcher_id.to_clvm(encoder)?))); - } - if let Some(receive_puzzle_hash) = &self.receive_puzzle_hash { - items.push(("ph", Raw(receive_puzzle_hash.to_clvm(encoder)?))); - } - - items.extend(vec![ - ("u", Raw(self.image_uris.to_clvm(encoder)?)), - ("h", Raw(self.image_hash.to_clvm(encoder)?)), - ("mu", Raw(self.metadata_uris.to_clvm(encoder)?)), - ("mh", Raw(self.metadata_hash.to_clvm(encoder)?)), - ("lu", Raw(self.license_uris.to_clvm(encoder)?)), - ("lh", Raw(self.license_hash.to_clvm(encoder)?)), - ]); - - items.to_clvm(encoder) - } -} diff --git a/src/primitives.rs b/src/primitives.rs deleted file mode 100644 index f6e676ae..00000000 --- a/src/primitives.rs +++ /dev/null @@ -1,39 +0,0 @@ -mod catalog_registry; -mod catalog_registry_info; -mod default_cat_maker; -mod medieval_vault; -mod medieval_vault_info; -mod precommit_coin; -mod reserve; -mod reward_distributor; -mod reward_distributor_info; -mod slot; -mod slot_info; -mod state_scheduler; -mod state_scheduler_info; -mod uniqueness_prelauncher; -mod verification; -mod verification_asserter; -mod verification_info; -mod xchandles_registry; -mod xchandles_registry_info; - -pub use catalog_registry::*; -pub use catalog_registry_info::*; -pub use default_cat_maker::*; -pub use medieval_vault::*; -pub use medieval_vault_info::*; -pub use precommit_coin::*; -pub use reserve::*; -pub use reward_distributor::*; -pub use reward_distributor_info::*; -pub use slot::*; -pub use slot_info::*; -pub use state_scheduler::*; -pub use state_scheduler_info::*; -pub use uniqueness_prelauncher::*; -pub use verification::*; -pub use verification_asserter::*; -pub use verification_info::*; -pub use xchandles_registry::*; -pub use xchandles_registry_info::*; diff --git a/src/primitives/catalog_registry.rs b/src/primitives/catalog_registry.rs deleted file mode 100644 index e4e6765a..00000000 --- a/src/primitives/catalog_registry.rs +++ /dev/null @@ -1,370 +0,0 @@ -use chia::{ - bls::Signature, - clvm_utils::ToTreeHash, - protocol::{Bytes32, Coin, CoinSpend}, - puzzles::{singleton::SingletonSolution, LineageProof, Proof}, -}; -use chia_wallet_sdk::driver::{DriverError, Layer, Puzzle, Spend, SpendContext}; -use clvm_traits::{clvm_list, match_tuple}; -use clvmr::NodePtr; - -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 { - pub coin: Coin, - pub proof: Proof, - pub info: CatalogRegistryInfo, - - pub pending_spend: CatalogPendingSpendInfo, -} - -impl CatalogRegistry { - pub fn new(coin: Coin, proof: Proof, info: CatalogRegistryInfo) -> Self { - Self { - coin, - proof, - info, - 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( - ctx: &mut SpendContext, - parent_spend: &CoinSpend, - constants: CatalogRegistryConstants, - ) -> Result, DriverError> - where - Self: Sized, - { - let Some(parent_registry) = CatalogRegistry::from_spend(ctx, parent_spend, constants)? - else { - return Ok(None); - }; - - let proof = Proof::Lineage(parent_registry.child_lineage_proof()); - - 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_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 { - type State = CatalogRegistryState; - type Constants = CatalogRegistryConstants; -} - -impl CatalogRegistry { - 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_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 { - lineage_proof: self.proof, - amount: self.coin.amount, - inner_solution: ActionLayerSolution { - proofs: layers - .inner_puzzle - .get_proofs( - &CatalogRegistryInfo::action_puzzle_hashes(&self.info.constants), - &action_puzzle_hashes, - ) - .ok_or(DriverError::Custom( - "Couldn't build proofs for one or more actions".to_string(), - ))?, - action_spends: self.pending_spend.actions, - finalizer_solution: NodePtr::NIL, - }, - }, - )?; - - let my_spend = Spend::new(puzzle, solution); - ctx.spend(self.coin, my_spend)?; - - Ok((child, self.pending_spend.signature)) - } - - pub fn new_action(&self) -> A - where - A: Action, - { - A::from_constants(&self.info.constants) - } - - pub fn created_slot_value_to_slot( - &self, - 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::new( - proof, - SlotInfo::from_value(self.info.constants.launcher_id, 0, slot_value), - ) - } - - pub fn actual_neigbors( - &self, - new_tail_hash: Bytes32, - on_chain_left_slot: Slot, - on_chain_right_slot: Slot, - ) -> (Slot, Slot) { - let mut left = on_chain_left_slot; - let mut right = on_chain_right_slot; - - 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_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 deleted file mode 100644 index 1be8939e..00000000 --- a/src/primitives/catalog_registry_info.rs +++ /dev/null @@ -1,160 +0,0 @@ -use chia::{ - clvm_utils::{ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonArgs, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Layer, Puzzle, SingletonLayer}, - types::MerkleTree, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::Allocator; -use hex_literal::hex; - -use crate::{ - Action, ActionLayer, ActionLayerArgs, CatalogRefundAction, CatalogRegisterAction, - DefaultFinalizer2ndCurryArgs, DelegatedStateAction, Finalizer, -}; - -use super::CatalogRegistry; - -pub type CatalogRegistryLayers = SingletonLayer>; - -#[must_use] -#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm, Copy)] -#[clvm(list)] -pub struct CatalogRegistryState { - pub cat_maker_puzzle_hash: Bytes32, - #[clvm(rest)] - pub registration_price: u64, -} - -#[must_use] -#[derive(Debug, Clone, PartialEq, Eq, Copy)] -pub struct CatalogRegistryConstants { - pub launcher_id: Bytes32, - pub royalty_address: Bytes32, - pub royalty_basis_points: u16, - pub precommit_payout_puzzle_hash: Bytes32, - pub relative_block_height: u32, - pub price_singleton_launcher_id: Bytes32, -} - -impl CatalogRegistryConstants { - pub fn get(testnet11: bool) -> Self { - if testnet11 { - return CatalogRegistryConstants { - launcher_id: Bytes32::from(hex!( - "0b705afb0d848794311970de0cb98722468fad6c8f687337735ab9e5286d7704" - )), - royalty_address: Bytes32::from(hex!( - "b3aea098428b2b5e6d57cf3bff6ee82e3950dec338b17df6d8ee20944787def5" - )), - royalty_basis_points: 100, - precommit_payout_puzzle_hash: Bytes32::from(hex!( - "b3aea098428b2b5e6d57cf3bff6ee82e3950dec338b17df6d8ee20944787def5" - )), - relative_block_height: 4, - price_singleton_launcher_id: Bytes32::from(hex!( - "45dff01375d9bd681d36a3a186ab3d0c86eb809d7f85fff950f0b37f068ec664" - )), - }; - } - - todo!("oops - catalog constants for mainnet are not yet available"); - } - - pub fn with_price_singleton(mut self, price_singleton_launcher_id: Bytes32) -> Self { - self.price_singleton_launcher_id = price_singleton_launcher_id; - self - } - - pub fn with_launcher_id(mut self, launcher_id: Bytes32) -> Self { - self.launcher_id = launcher_id; - self - } -} - -#[must_use] -#[derive(Debug, Clone, PartialEq, Eq, Copy)] -pub struct CatalogRegistryInfo { - pub state: CatalogRegistryState, - - pub constants: CatalogRegistryConstants, -} - -impl CatalogRegistryInfo { - pub fn new(state: CatalogRegistryState, constants: CatalogRegistryConstants) -> Self { - Self { state, constants } - } - - pub fn with_state(mut self, state: CatalogRegistryState) -> Self { - self.state = state; - self - } - - pub fn action_puzzle_hashes(constants: &CatalogRegistryConstants) -> [Bytes32; 3] { - [ - CatalogRegisterAction::from_constants(constants) - .tree_hash() - .into(), - CatalogRefundAction::from_constants(constants) - .tree_hash() - .into(), - >::from_constants(constants) - .tree_hash() - .into(), - ] - } - - #[must_use] - pub fn into_layers(self) -> CatalogRegistryLayers { - SingletonLayer::new( - self.constants.launcher_id, - ActionLayer::from_action_puzzle_hashes( - &Self::action_puzzle_hashes(&self.constants), - self.state, - Finalizer::Default { - hint: self.constants.launcher_id, - }, - ), - ) - } - - pub fn parse( - allocator: &mut Allocator, - puzzle: Puzzle, - constants: CatalogRegistryConstants, - ) -> Result, DriverError> { - let Some(layers) = CatalogRegistryLayers::parse_puzzle(allocator, puzzle)? else { - return Ok(None); - }; - - let action_puzzle_hashes = Self::action_puzzle_hashes(&constants); - let merkle_root = MerkleTree::new(&action_puzzle_hashes).root(); - if layers.inner_puzzle.merkle_root != merkle_root { - return Ok(None); - } - - Ok(Some(Self::from_layers(layers, constants))) - } - - pub fn from_layers(layers: CatalogRegistryLayers, constants: CatalogRegistryConstants) -> Self { - Self { - state: layers.inner_puzzle.state, - constants, - } - } - - pub fn puzzle_hash(&self) -> TreeHash { - SingletonArgs::curry_tree_hash(self.constants.launcher_id, self.inner_puzzle_hash()) - } - - pub fn inner_puzzle_hash(&self) -> TreeHash { - ActionLayerArgs::curry_tree_hash( - DefaultFinalizer2ndCurryArgs::curry_tree_hash(self.constants.launcher_id), - MerkleTree::new(&Self::action_puzzle_hashes(&self.constants)).root(), - self.state.tree_hash(), - ) - } -} diff --git a/src/primitives/default_cat_maker.rs b/src/primitives/default_cat_maker.rs deleted file mode 100644 index 19a8e614..00000000 --- a/src/primitives/default_cat_maker.rs +++ /dev/null @@ -1,57 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::Bytes32, -}; -use chia_puzzles::CAT_PUZZLE_HASH; -use chia_wallet_sdk::driver::{DriverError, SpendContext}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::SpendContextExt; - -pub const DEFAULT_CAT_MAKER_PUZZLE: [u8; 283] = hex!("ff02ffff01ff0bff16ffff0bff04ffff0bff04ff1aff0580ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bffff0101ff058080ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1aff0b80ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1aff1780ffff0bff04ff1aff12808080ff12808080ff12808080ff12808080ffff04ffff01ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff018080"); - -pub const DEFAULT_CAT_MAKER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 0370e9c0343398cbe3487fb93d4aa24357005cdd67894e1cbae14772e778a75a - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct DefaultCatMakerArgs { - pub cat_mod_hash: Bytes32, - pub tail_hash_hash: Bytes32, -} - -impl DefaultCatMakerArgs { - pub fn new(tail_hash_hash: Bytes32) -> Self { - Self { - cat_mod_hash: CAT_PUZZLE_HASH.into(), - tail_hash_hash, - } - } -} - -impl DefaultCatMakerArgs { - pub fn curry_tree_hash(tail_hash_hash: Bytes32) -> TreeHash { - CurriedProgram { - program: DEFAULT_CAT_MAKER_PUZZLE_HASH, - args: DefaultCatMakerArgs::new(tail_hash_hash), - } - .tree_hash() - } - - pub fn get_puzzle( - ctx: &mut SpendContext, - tail_hash_hash: Bytes32, - ) -> Result { - let cat_maker_puzzle = ctx.default_cat_maker_puzzle()?; - - ctx.alloc(&CurriedProgram { - program: cat_maker_puzzle, - args: DefaultCatMakerArgs::new(tail_hash_hash), - }) - } -} diff --git a/src/primitives/medieval_vault.rs b/src/primitives/medieval_vault.rs deleted file mode 100644 index bfd70e27..00000000 --- a/src/primitives/medieval_vault.rs +++ /dev/null @@ -1,407 +0,0 @@ -use chia::{ - bls::PublicKey, - clvm_utils::{CurriedProgram, ToTreeHash}, - protocol::{Bytes32, Coin, CoinSpend}, - puzzles::{ - singleton::{LauncherSolution, SingletonArgs, SingletonSolution, SingletonStruct}, - EveProof, LineageProof, Proof, - }, -}; -use chia_puzzles::{SINGLETON_LAUNCHER_HASH, SINGLETON_TOP_LAYER_V1_1_HASH}; -use chia_wallet_sdk::{ - driver::{DriverError, Layer, Puzzle, SingletonLayer, Spend, SpendContext}, - prelude::{Condition, Conditions, Memos}, -}; -use clvm_traits::{clvm_quote, FromClvm, ToClvm}; -use clvmr::{serde::node_from_bytes, Allocator, NodePtr}; - -use crate::{ - MOfNLayer, P2MOfNDelegateDirectArgs, P2MOfNDelegateDirectSolution, SpendContextExt, - StateSchedulerLayerArgs, -}; - -use super::{MedievalVaultHint, MedievalVaultInfo}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MedievalVault { - pub coin: Coin, - pub proof: Proof, - - pub info: MedievalVaultInfo, -} - -impl MedievalVault { - pub fn new(coin: Coin, proof: Proof, info: MedievalVaultInfo) -> Self { - Self { coin, proof, info } - } - - pub fn from_launcher_spend( - ctx: &mut SpendContext, - launcher_spend: CoinSpend, - ) -> Result, DriverError> { - if launcher_spend.coin.puzzle_hash != SINGLETON_LAUNCHER_HASH.into() { - return Ok(None); - } - - let solution = node_from_bytes(ctx, &launcher_spend.solution)?; - let solution = ctx.extract::>(solution)?; - - let Ok(hint) = ctx.extract::(solution.key_value_list) else { - return Ok(None); - }; - - let info = MedievalVaultInfo::from_hint(hint); - - let new_coin = Coin::new( - launcher_spend.coin.coin_id(), - SingletonArgs::curry_tree_hash(info.launcher_id, info.inner_puzzle_hash()).into(), - 1, - ); - - if launcher_spend.coin.amount != new_coin.amount - || new_coin.puzzle_hash != solution.singleton_puzzle_hash - { - return Ok(None); - } - - Ok(Some(Self::new( - new_coin, - Proof::Eve(EveProof { - parent_parent_coin_info: launcher_spend.coin.parent_coin_info, - parent_amount: launcher_spend.coin.amount, - }), - info, - ))) - } - - pub fn child(&self, new_m: usize, new_public_key_list: Vec) -> Option { - let child_proof = Proof::Lineage(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, - }); - - let child_info = MedievalVaultInfo::new(self.info.launcher_id, new_m, new_public_key_list); - let child_inner_puzzle_hash = child_info.inner_puzzle_hash(); - - Some(Self { - coin: Coin::new( - self.coin.coin_id(), - SingletonArgs::curry_tree_hash(self.info.launcher_id, child_inner_puzzle_hash) - .into(), - 1, - ), - proof: child_proof, - info: child_info, - }) - } - - pub fn from_parent_spend( - ctx: &mut SpendContext, - parent_spend: CoinSpend, - ) -> Result, DriverError> { - if parent_spend.coin.puzzle_hash == SINGLETON_LAUNCHER_HASH.into() { - return Self::from_launcher_spend(ctx, parent_spend); - } - - let solution = node_from_bytes(ctx, &parent_spend.solution)?; - let puzzle = node_from_bytes(ctx, &parent_spend.puzzle_reveal)?; - - let puzzle_puzzle = Puzzle::from_clvm(ctx, puzzle)?; - let Some(parent_layers) = SingletonLayer::::parse_puzzle(ctx, puzzle_puzzle)? - else { - return Ok(None); - }; - - let output = ctx.run(puzzle, solution)?; - let output = ctx.extract::>(output)?; - let recreate_condition = output - .into_iter() - .find(|c| matches!(c, Condition::CreateCoin(..))); - let Some(Condition::CreateCoin(recreate_condition)) = recreate_condition else { - return Ok(None); - }; - - 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 { - ( - parent_layers.inner_puzzle.m, - 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( - parent_layers.launcher_id, - parent_layers.inner_puzzle.m, - parent_layers.inner_puzzle.public_key_list, - ); - let new_info = MedievalVaultInfo::new(parent_layers.launcher_id, new_m, new_pubkeys); - - let new_coin = Coin::new( - parent_spend.coin.coin_id(), - SingletonArgs::curry_tree_hash(parent_layers.launcher_id, new_info.inner_puzzle_hash()) - .into(), - 1, - ); - - Ok(Some(Self::new( - new_coin, - Proof::Lineage(LineageProof { - parent_parent_coin_info: parent_spend.coin.parent_coin_info, - parent_inner_puzzle_hash: parent_info.inner_puzzle_hash().into(), - parent_amount: parent_spend.coin.amount, - }), - new_info, - ))) - } - - pub fn delegated_conditions( - conditions: Conditions, - coin_id: Bytes32, - genesis_challenge: NodePtr, - ) -> Conditions { - MOfNLayer::ensure_non_replayable(conditions, coin_id, genesis_challenge) - } - - // Mark this as unsafe since the transaction may be replayable - // across coin generations and networks if delegated puzzle is not - // properly secured. - pub fn spend_sunsafe( - self, - ctx: &mut SpendContext, - used_pubkeys: &[PublicKey], - delegated_puzzle: NodePtr, - delegated_solution: NodePtr, - ) -> Result<(), DriverError> { - let lineage_proof = self.proof; - let coin = self.coin; - - let layers = self.info.into_layers(); - - let puzzle = layers.construct_puzzle(ctx)?; - let solution = layers.construct_solution( - ctx, - SingletonSolution { - lineage_proof, - amount: coin.amount, - inner_solution: P2MOfNDelegateDirectSolution { - selectors: P2MOfNDelegateDirectArgs::selectors_for_used_pubkeys( - &self.info.public_key_list, - used_pubkeys, - ), - delegated_puzzle, - delegated_solution, - }, - }, - )?; - - ctx.spend(coin, Spend::new(puzzle, solution))?; - - Ok(()) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - used_pubkeys: &[PublicKey], - conditions: Conditions, - genesis_challenge: Bytes32, - ) -> Result<(), DriverError> { - let genesis_challenge = ctx.alloc(&genesis_challenge)?; - let delegated_puzzle = ctx.alloc(&clvm_quote!(Self::delegated_conditions( - conditions, - self.coin.coin_id(), - genesis_challenge - )))?; - - self.spend_sunsafe(ctx, used_pubkeys, delegated_puzzle, NodePtr::NIL) - } - - pub fn rekey_create_coin_unsafe( - ctx: &mut SpendContext, - launcher_id: Bytes32, - new_m: usize, - new_pubkeys: Vec, - ) -> Result { - let new_info = MedievalVaultInfo::new(launcher_id, new_m, new_pubkeys); - - let memos = ctx.alloc(&new_info.to_hint())?; - Ok(Conditions::new().create_coin( - new_info.inner_puzzle_hash().into(), - 1, - Memos::Some(memos), - )) - } - - pub fn delegated_puzzle_for_rekey( - ctx: &mut SpendContext, - launcher_id: Bytes32, - new_m: usize, - new_pubkeys: Vec, - coin_id: Bytes32, - genesis_challenge: Bytes32, - ) -> Result { - let genesis_challenge = ctx.alloc(&genesis_challenge)?; - let conditions = Self::rekey_create_coin_unsafe(ctx, launcher_id, new_m, new_pubkeys)?; - - ctx.alloc(&clvm_quote!(Self::delegated_conditions( - conditions, - coin_id, - genesis_challenge - ))) - } - - pub fn delegated_puzzle_for_flexible_send_message( - ctx: &mut SpendContext, - message: M, - receiver_launcher_id: Bytes32, - my_coin: Coin, - my_info: &MedievalVaultInfo, - genesis_challenge: Bytes32, - ) -> Result - where - M: ToClvm, - { - let conditions = Conditions::new().create_coin( - my_info.inner_puzzle_hash().into(), - my_coin.amount, - ctx.hint(my_info.launcher_id)?, - ); - let genesis_challenge = ctx.alloc(&genesis_challenge)?; - - let innermost_delegated_puzzle_ptr = ctx.alloc(&clvm_quote!( - Self::delegated_conditions(conditions, my_coin.coin_id(), genesis_challenge) - ))?; - - let program = ctx.state_scheduler_puzzle()?; - ctx.alloc(&CurriedProgram { - program, - args: StateSchedulerLayerArgs:: { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - receiver_singleton_struct_hash: SingletonStruct::new(receiver_launcher_id) - .tree_hash() - .into(), - message, - inner_puzzle: innermost_delegated_puzzle_ptr, - }, - }) - } -} - -#[cfg(test)] -mod tests { - use chia_wallet_sdk::{driver::Launcher, test::Simulator, types::TESTNET11_CONSTANTS}; - - use super::*; - - #[test] - fn test_medieval_vault() -> anyhow::Result<()> { - let ctx = &mut SpendContext::new(); - let mut sim = Simulator::new(); - - let user1 = sim.bls(0); - let user2 = sim.bls(0); - let user3 = sim.bls(0); - - let multisig_configs = [ - (1, vec![user1.pk, user2.pk]), - (2, vec![user1.pk, user2.pk]), - (3, vec![user1.pk, user2.pk, user3.pk]), - (3, vec![user1.pk, user2.pk, user3.pk]), - (1, vec![user1.pk, user2.pk, user3.pk]), - (2, vec![user1.pk, user2.pk, user3.pk]), - ]; - - let launcher_coin = sim.new_coin(SINGLETON_LAUNCHER_HASH.into(), 1); - let launcher = Launcher::new(launcher_coin.parent_coin_info, 1); - let launch_hints = MedievalVaultHint { - my_launcher_id: launcher_coin.coin_id(), - m: multisig_configs[0].0, - public_key_list: multisig_configs[0].1.clone(), - }; - let (_conds, first_vault_coin) = launcher.spend( - ctx, - P2MOfNDelegateDirectArgs::curry_tree_hash( - multisig_configs[0].0, - multisig_configs[0].1.clone(), - ) - .into(), - launch_hints, - )?; - - let spends = ctx.take(); - let launcher_spend = spends.first().unwrap().clone(); - sim.spend_coins(spends, &[])?; - - let mut vault = MedievalVault::from_parent_spend(ctx, launcher_spend)?.unwrap(); - assert_eq!(vault.coin, first_vault_coin); - - let mut current_vault_info = MedievalVaultInfo { - launcher_id: launcher_coin.coin_id(), - m: multisig_configs[0].0, - public_key_list: multisig_configs[0].1.clone(), - }; - assert_eq!(vault.info, current_vault_info); - - for (i, (m, pubkeys)) in multisig_configs.clone().into_iter().enumerate().skip(1) { - let mut recreate_memos: NodePtr = ctx.alloc(&vec![vault.info.launcher_id])?; - - let info_changed = - multisig_configs[i - 1].0 != m || multisig_configs[i - 1].1 != pubkeys; - if info_changed { - recreate_memos = ctx.alloc(&MedievalVaultHint { - my_launcher_id: vault.info.launcher_id, - m, - public_key_list: pubkeys.clone(), - })?; - } - current_vault_info = MedievalVaultInfo { - launcher_id: vault.info.launcher_id, - m, - public_key_list: pubkeys.clone(), - }; - - let recreate_condition = Conditions::::new().create_coin( - current_vault_info.inner_puzzle_hash().into(), - 1, - Memos::Some(recreate_memos), - ); - - let mut used_keys = 0; - let mut used_pubkeys = vec![]; - while used_keys < vault.info.m { - used_pubkeys.push(current_vault_info.public_key_list[used_keys]); - used_keys += 1; - } - vault.clone().spend( - ctx, - &used_pubkeys, - recreate_condition, - TESTNET11_CONSTANTS.genesis_challenge, - )?; - - let spends = ctx.take(); - let vault_spend = spends.first().unwrap().clone(); - sim.spend_coins( - spends, - &[user1.sk.clone(), user2.sk.clone(), user3.sk.clone()], - )?; - - let check_vault = vault.child(m, pubkeys).unwrap(); - - vault = MedievalVault::from_parent_spend(ctx, vault_spend)?.unwrap(); - assert_eq!(vault.info, current_vault_info); - assert_eq!(vault, check_vault); - } - - Ok(()) - } -} diff --git a/src/primitives/medieval_vault_info.rs b/src/primitives/medieval_vault_info.rs deleted file mode 100644 index c19ce357..00000000 --- a/src/primitives/medieval_vault_info.rs +++ /dev/null @@ -1,61 +0,0 @@ -use chia::{bls::PublicKey, clvm_utils::TreeHash, protocol::Bytes32}; -use chia_wallet_sdk::driver::SingletonLayer; -use clvm_traits::{FromClvm, ToClvm}; - -use crate::{MOfNLayer, P2MOfNDelegateDirectArgs}; - -type MedievalVaultLayers = SingletonLayer; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MedievalVaultInfo { - pub launcher_id: Bytes32, - - pub m: usize, - pub public_key_list: Vec, -} - -impl MedievalVaultInfo { - pub fn new(launcher_id: Bytes32, m: usize, public_key_list: Vec) -> Self { - Self { - launcher_id, - m, - public_key_list, - } - } - - pub fn from_hint(hint: MedievalVaultHint) -> Self { - Self { - launcher_id: hint.my_launcher_id, - m: hint.m, - public_key_list: hint.public_key_list, - } - } - - pub fn inner_puzzle_hash(&self) -> TreeHash { - P2MOfNDelegateDirectArgs::curry_tree_hash(self.m, self.public_key_list.clone()) - } - - pub fn into_layers(&self) -> MedievalVaultLayers { - SingletonLayer::new( - self.launcher_id, - MOfNLayer::new(self.m, self.public_key_list.clone()), - ) - } - - pub fn to_hint(&self) -> MedievalVaultHint { - MedievalVaultHint { - my_launcher_id: self.launcher_id, - m: self.m, - public_key_list: self.public_key_list.clone(), - } - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct MedievalVaultHint { - pub my_launcher_id: Bytes32, - pub m: usize, - #[clvm(rest)] - pub public_key_list: Vec, -} diff --git a/src/primitives/precommit_coin.rs b/src/primitives/precommit_coin.rs deleted file mode 100644 index 85d05a9d..00000000 --- a/src/primitives/precommit_coin.rs +++ /dev/null @@ -1,167 +0,0 @@ -use chia::{ - clvm_utils::TreeHash, - protocol::{Bytes32, Coin}, - puzzles::{ - cat::{CatArgs, CatSolution}, - CoinProof, LineageProof, - }, -}; -use chia_wallet_sdk::driver::{CatLayer, DriverError, Layer, Spend, SpendContext}; -use clvm_traits::ToClvm; -use clvmr::{Allocator, NodePtr}; - -use crate::{PrecommitLayer, PrecommitLayerSolution}; - -#[derive(Debug, Clone)] -#[must_use] -pub struct PrecommitCoin { - pub coin: Coin, - pub asset_id: Bytes32, - pub proof: LineageProof, - pub inner_puzzle_hash: Bytes32, - - pub controller_singleton_struct_hash: Bytes32, - pub relative_block_height: u32, - pub payout_puzzle_hash: Bytes32, - pub refund_puzzle_hash: Bytes32, - pub value: V, -} - -impl PrecommitCoin { - #[allow(clippy::too_many_arguments)] - pub fn new( - ctx: &mut SpendContext, - parent_coin_id: Bytes32, - proof: LineageProof, - asset_id: Bytes32, - controller_singleton_struct_hash: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - refund_puzzle_hash: Bytes32, - value: V, - precommit_amount: u64, - ) -> Result - where - V: ToClvm + Clone, - { - let value_ptr = ctx.alloc(&value)?; - let value_hash = ctx.tree_hash(value_ptr); - - let inner_puzzle_hash = PrecommitLayer::::puzzle_hash( - controller_singleton_struct_hash, - relative_block_height, - payout_puzzle_hash, - refund_puzzle_hash, - value_hash, - ); - - Ok(Self { - coin: Coin::new( - parent_coin_id, - CatArgs::curry_tree_hash(asset_id, inner_puzzle_hash).into(), - precommit_amount, - ), - proof, - asset_id, - inner_puzzle_hash: inner_puzzle_hash.into(), - controller_singleton_struct_hash, - relative_block_height, - payout_puzzle_hash, - refund_puzzle_hash, - value, - }) - } - - pub fn puzzle_hash( - asset_id: Bytes32, - controller_singleton_struct_hash: Bytes32, - relative_block_height: u32, - payout_puzzle_hash: Bytes32, - refund_puzzle_hash: Bytes32, - value_hash: TreeHash, - ) -> TreeHash { - CatArgs::curry_tree_hash( - asset_id, - PrecommitLayer::::puzzle_hash( - controller_singleton_struct_hash, - relative_block_height, - payout_puzzle_hash, - refund_puzzle_hash, - value_hash, - ), - ) - } - - pub fn inner_puzzle(&self, ctx: &mut SpendContext) -> Result - where - V: Clone + ToClvm, - { - PrecommitLayer::::new( - self.controller_singleton_struct_hash, - self.relative_block_height, - self.payout_puzzle_hash, - self.refund_puzzle_hash, - self.value.clone(), - ) - .construct_puzzle(ctx) - } - - pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result - where - V: Clone + ToClvm, - { - let inner_puzzle = self.inner_puzzle(ctx)?; - - CatLayer::::new(self.asset_id, inner_puzzle).construct_puzzle(ctx) - } - - pub fn construct_solution( - &self, - ctx: &mut SpendContext, - mode: u8, - singleton_inner_puzzle_hash: Bytes32, - ) -> Result - where - V: ToClvm + Clone, - { - let layers = CatLayer::::new(self.asset_id, self.inner_puzzle(ctx)?); - - let inner_puzzle_solution = ctx.alloc(&PrecommitLayerSolution { - mode, - my_amount: self.coin.amount, - singleton_inner_puzzle_hash, - })?; - - layers.construct_solution( - ctx, - CatSolution { - inner_puzzle_solution, - lineage_proof: Some(self.proof), - prev_coin_id: self.coin.coin_id(), - this_coin_info: self.coin, - next_coin_proof: CoinProof { - parent_coin_info: self.coin.parent_coin_info, - inner_puzzle_hash: self.inner_puzzle_hash, - amount: self.coin.amount, - }, - prev_subtotal: 0, - extra_delta: 0, - }, - ) - } - - pub fn spend( - &self, - ctx: &mut SpendContext, - mode: u8, - spender_inner_puzzle_hash: Bytes32, - ) -> Result<(), DriverError> - where - V: ToClvm + Clone, - { - let puzzle = self.construct_puzzle(ctx)?; - let solution = self.construct_solution(ctx, mode, spender_inner_puzzle_hash)?; - - ctx.spend(self.coin, Spend::new(puzzle, solution)) - } -} diff --git a/src/primitives/reserve.rs b/src/primitives/reserve.rs deleted file mode 100644 index 96b589b7..00000000 --- a/src/primitives/reserve.rs +++ /dev/null @@ -1,197 +0,0 @@ -use chia::{ - clvm_utils::TreeHash, - protocol::{Bytes32, Coin}, - puzzles::{cat::CatArgs, singleton::SingletonSolution, LineageProof}, -}; -use chia_wallet_sdk::{ - driver::{Cat, CatInfo, CatSpend, DriverError, Layer, Spend, SpendContext}, - prelude::CreateCoin, - types::run_puzzle, -}; -use clvm_traits::{clvm_list, clvm_quote, match_tuple, FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; - -use crate::{ - ActionLayer, P2DelegatedBySingletonLayer, P2DelegatedBySingletonLayerArgs, - P2DelegatedBySingletonLayerSolution, -}; - -#[derive(Debug, Clone)] -#[must_use] -pub struct Reserve { - pub coin: Coin, - pub asset_id: Bytes32, - pub proof: LineageProof, - pub inner_puzzle_hash: Bytes32, - - pub controller_singleton_struct_hash: Bytes32, - pub nonce: u64, -} - -pub trait Reserveful { - fn reserve_amount(&self, index: u64) -> u64; -} - -impl Reserve { - pub fn new( - parent_coin_id: Bytes32, - proof: LineageProof, - asset_id: Bytes32, - controller_singleton_struct_hash: Bytes32, - nonce: u64, - amount: u64, - ) -> Self { - let inner_puzzle_hash = P2DelegatedBySingletonLayerArgs::curry_tree_hash( - controller_singleton_struct_hash, - nonce, - ); - - Self { - coin: Coin::new( - parent_coin_id, - CatArgs::curry_tree_hash(asset_id, inner_puzzle_hash).into(), - amount, - ), - proof, - asset_id, - inner_puzzle_hash: inner_puzzle_hash.into(), - controller_singleton_struct_hash, - nonce, - } - } - - pub fn puzzle_hash( - asset_id: Bytes32, - controller_singleton_struct_hash: Bytes32, - nonce: u64, - ) -> TreeHash { - CatArgs::curry_tree_hash( - asset_id, - P2DelegatedBySingletonLayerArgs::curry_tree_hash( - controller_singleton_struct_hash, - nonce, - ), - ) - } - - pub fn construct_inner_puzzle(&self, ctx: &mut SpendContext) -> Result { - let layer = - P2DelegatedBySingletonLayer::new(self.controller_singleton_struct_hash, self.nonce); - - layer.construct_puzzle(ctx) - } - - pub fn to_cat(&self) -> Cat { - Cat::new( - self.coin, - Some(self.proof), - CatInfo::new(self.asset_id, None, self.inner_puzzle_hash), - ) - } - - pub fn inner_spend( - &self, - ctx: &mut SpendContext, - controller_singleton_inner_puzzle_hash: Bytes32, - delegated_puzzle: NodePtr, - delegated_solution: NodePtr, - ) -> Result { - P2DelegatedBySingletonLayer::new(self.controller_singleton_struct_hash, self.nonce) - .construct_spend( - ctx, - P2DelegatedBySingletonLayerSolution { - singleton_inner_puzzle_hash: controller_singleton_inner_puzzle_hash, - delegated_puzzle, - delegated_solution, - }, - ) - } - - pub fn delegated_puzzle_for_finalizer_controller( - &self, - ctx: &mut SpendContext, - controlelr_initial_state: S, - controller_solution: NodePtr, - ) -> Result - where - S: ToClvm + FromClvm + Clone + Reserveful, - { - let controller_solution = ctx.extract::>(controller_solution)?; - let inner_solution = - ActionLayer::::parse_solution(ctx, controller_solution.inner_solution)?; - - let mut state: (NodePtr, S) = (NodePtr::NIL, controlelr_initial_state); - let mut reserve_conditions: Vec = Vec::new(); - for raw_action in inner_solution.action_spends { - let actual_solution = ctx.alloc(&clvm_list!(state, raw_action.solution))?; - - let output = run_puzzle(ctx, raw_action.puzzle, actual_solution)?; - - let (new_state, conditions) = - ctx.extract::)>(output)?; - state = new_state; - - for (opcode, cond) in conditions { - if opcode == -42 { - reserve_conditions.push(cond); - } - } - } - - // prepend CREATE_COIN, just like the reserve finalizer does - // (list CREATE_COIN RESERVE_INNER_PUZZLE_HASH (f New_State) (list RESERVE_INNER_PUZZLE_HASH)) - let new_reserve_amount = state.1.reserve_amount(0); - let cc = CreateCoin::new( - self.inner_puzzle_hash, - new_reserve_amount, - ctx.hint(self.inner_puzzle_hash)?, - ); - reserve_conditions.insert(0, ctx.alloc(&cc)?); - - let delegated_puzzle = ctx.alloc(&clvm_quote!(reserve_conditions))?; - - Ok(delegated_puzzle) - } - - pub fn cat_spend_for_reserve_finalizer_controller( - &self, - ctx: &mut SpendContext, - controlelr_initial_state: S, - controller_singleton_inner_puzzle_hash: Bytes32, - controller_solution: NodePtr, - ) -> Result - where - S: ToClvm + FromClvm + Clone + Reserveful, - { - let delegated_puzzle = self.delegated_puzzle_for_finalizer_controller( - ctx, - controlelr_initial_state, - controller_solution, - )?; - - Ok(CatSpend::new( - self.to_cat(), - self.inner_spend( - ctx, - controller_singleton_inner_puzzle_hash, - delegated_puzzle, - NodePtr::NIL, - )?, - )) - } - - 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 deleted file mode 100644 index ff623502..00000000 --- a/src/primitives/reward_distributor.rs +++ /dev/null @@ -1,684 +0,0 @@ -use chia::{ - bls::Signature, - clvm_utils::{tree_hash, ToTreeHash}, - protocol::{Bytes32, Coin, CoinSpend}, - puzzles::{ - singleton::{SingletonSolution, SingletonStruct}, - LineageProof, Proof, - }, -}; -use chia_puzzle_types::singleton::{LauncherSolution, SingletonArgs}; -use chia_wallet_sdk::{ - driver::{DriverError, Layer, Puzzle, SingletonLayer, Spend, SpendContext}, - prelude::{Cat, CatSpend}, - types::{Condition, Conditions}, -}; -use clvm_traits::{clvm_list, match_tuple, FromClvm}; -use clvmr::NodePtr; - -use crate::{ - Action, ActionLayer, ActionLayerSolution, RawActionLayerSolution, Registry, - ReserveFinalizerSolution, RewardDistributorAddEntryAction, - RewardDistributorAddIncentivesAction, RewardDistributorCommitIncentivesAction, - RewardDistributorInitiatePayoutAction, RewardDistributorNewEpochAction, - RewardDistributorRemoveEntryAction, RewardDistributorStakeAction, RewardDistributorSyncAction, - RewardDistributorUnstakeAction, RewardDistributorWithdrawIncentivesAction, Slot, SlotInfo, - SlotProof, -}; - -use super::{ - Reserve, RewardDistributorCommitmentSlotValue, RewardDistributorConstants, - RewardDistributorEntrySlotValue, RewardDistributorInfo, RewardDistributorRewardSlotValue, - RewardDistributorSlotNonce, RewardDistributorState, -}; - -#[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 fn add_delta(&mut self, delta: RewardDistributorPendingSpendInfo) { - self.actions.extend(delta.actions); - - 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)] -#[must_use] -pub struct RewardDistributor { - pub coin: Coin, - pub proof: Proof, - pub info: RewardDistributorInfo, - pub reserve: Reserve, - - pub pending_spend: RewardDistributorPendingSpendInfo, -} - -impl RewardDistributor { - pub fn new(coin: Coin, proof: Proof, info: RewardDistributorInfo, reserve: Reserve) -> Self { - Self { - coin, - proof, - info, - reserve, - pending_spend: RewardDistributorPendingSpendInfo::new(info.state), - } - } -} - -impl RewardDistributor { - #[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 { - 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 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)?; - - let inner_solution = - RawActionLayerSolution::::from_clvm( - ctx, - solution.inner_solution, - )?; - - let reserve = Reserve::new( - 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(info.constants.launcher_id) - .tree_hash() - .into(), - 0, - info.state.total_reserves, - ); - - Ok(Some(RewardDistributor { - coin, - proof, - info, - reserve, - 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, - launcher_coin: Coin, - launcher_solution: NodePtr, - ) -> Result, DriverError> - where - Self: Sized, - { - let Ok(launcher_solution) = - ctx.extract::>(launcher_solution) - else { - return Ok(None); - }; - - let launcher_id = launcher_coin.coin_id(); - let (first_epoch_start, constants) = launcher_solution.key_value_list; - - if constants != constants.with_launcher_id(launcher_id) { - return Err(DriverError::Custom( - "Distributor constants invalid".to_string(), - )); - } - - let distributor_eve_coin = - Coin::new(launcher_id, launcher_solution.singleton_puzzle_hash, 1); - - let initial_state = RewardDistributorState::initial(first_epoch_start); - - Ok(Some((constants, initial_state, distributor_eve_coin))) - } - - #[allow(clippy::type_complexity)] - pub fn from_eve_coin_spend( - ctx: &mut SpendContext, - constants: RewardDistributorConstants, - initial_state: RewardDistributorState, - eve_coin_spend: CoinSpend, - reserve_parent_id: Bytes32, - reserve_lineage_proof: LineageProof, - ) -> Result)>, DriverError> - where - Self: Sized, - { - 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 { - return Err(DriverError::Custom("Eve coin not a singleton".to_string())); - }; - - let eve_coin_inner_puzzle_hash = tree_hash(ctx, eve_coin_puzzle.inner_puzzle); - - let eve_coin_solution_ptr = ctx.alloc(&eve_coin_spend.solution)?; - let eve_coin_output = ctx.run(eve_coin_puzzle_ptr, eve_coin_solution_ptr)?; - let eve_coin_output = ctx.extract::>(eve_coin_output)?; - - let Some(Condition::CreateCoin(odd_create_coin)) = eve_coin_output.into_iter().find(|c| { - if let Condition::CreateCoin(create_coin) = c { - // singletons with amount != 1 are weird and I don't support them - create_coin.amount % 2 == 1 - } else { - false - } - }) else { - return Err(DriverError::Custom( - "Eve coin did not create a coin".to_string(), - )); - }; - - let new_coin = Coin::new( - eve_coin_spend.coin.coin_id(), - odd_create_coin.puzzle_hash, - odd_create_coin.amount, - ); - let lineage_proof = LineageProof { - parent_parent_coin_info: eve_coin_spend.coin.parent_coin_info, - parent_inner_puzzle_hash: eve_coin_inner_puzzle_hash.into(), - parent_amount: eve_coin_spend.coin.amount, - }; - let reserve = Reserve::new( - reserve_parent_id, - reserve_lineage_proof, - constants.reserve_asset_id, - SingletonStruct::new(constants.launcher_id) - .tree_hash() - .into(), - 0, - 0, - ); - let new_distributor = RewardDistributor::new( - new_coin, - Proof::Lineage(lineage_proof), - RewardDistributorInfo::new(initial_state, constants), - reserve, - ); - - if SingletonArgs::curry_tree_hash( - constants.launcher_id, - new_distributor.info.inner_puzzle_hash(), - ) != new_distributor.coin.puzzle_hash.into() - { - return Err(DriverError::Custom( - "Distributor singleton puzzle hash mismatch".to_string(), - )); - } - - let slot_proof = SlotProof { - parent_parent_info: lineage_proof.parent_parent_coin_info, - parent_inner_puzzle_hash: lineage_proof.parent_inner_puzzle_hash, - }; - let slot_value = RewardDistributorRewardSlotValue { - epoch_start: initial_state.round_time_info.epoch_end, - next_epoch_initialized: false, - rewards: 0, - }; - - let slot = Slot::new( - slot_proof, - SlotInfo::from_value( - constants.launcher_id, - RewardDistributorSlotNonce::REWARD.to_u64(), - slot_value, - ), - ); - - 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 { - type State = RewardDistributorState; - type Constants = RewardDistributorConstants; -} - -impl RewardDistributor { - pub fn finish_spend( - self, - ctx: &mut SpendContext, - other_cat_spends: Vec, - ) -> Result<(Self, Signature), DriverError> { - let layers = self.info.into_layers(ctx)?; - - let puzzle = layers.construct_puzzle(ctx)?; - - let action_puzzle_hashes = self - .pending_spend - .actions - .iter() - .map(|a| ctx.tree_hash(a.puzzle).into()) - .collect::>(); - - let finalizer_solution = ctx.alloc(&ReserveFinalizerSolution { - 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 { - lineage_proof: self.proof, - amount: self.coin.amount, - inner_solution: ActionLayerSolution { - proofs: layers - .inner_puzzle - .get_proofs( - &RewardDistributorInfo::action_puzzle_hashes(&self.info.constants), - &action_puzzle_hashes, - ) - .ok_or(DriverError::Custom( - "Couldn't build proofs for one or more actions".to_string(), - ))?, - action_spends: self.pending_spend.actions, - finalizer_solution, - }, - }, - )?; - - let my_spend = Spend::new(puzzle, solution); - ctx.spend(self.coin, my_spend)?; - - let cat_spend = self.reserve.cat_spend_for_reserve_finalizer_controller( - ctx, - self.info.state, - self.info.inner_puzzle_hash().into(), - solution, - )?; - - 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)?; - - Ok((child, self.pending_spend.signature)) - } - - pub fn new_action(&self) -> A - where - A: Action, - { - A::from_constants(&self.info.constants) - } - - pub fn created_slot_value_to_slot( - &self, - slot_value: SlotValue, - nonce: RewardDistributorSlotNonce, - ) -> Slot - where - SlotValue: Copy + ToTreeHash, - { - let proof = SlotProof { - parent_parent_info: self.coin.parent_coin_info, - parent_inner_puzzle_hash: self.info.inner_puzzle_hash().into(), - }; - - Slot::new( - proof, - SlotInfo::from_value(self.info.constants.launcher_id, nonce.to_u64(), slot_value), - ) - } - - 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, - )?; - - self.pending_spend.add_delta(delta); - - Ok(()) - } - - pub fn actual_reward_slot_value( - &self, - 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); - } - } - - slot - } - - pub fn actual_entry_slot_value( - &self, - 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); - } - } - - slot - } - - 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, - ); - } - } - - slot - } -} diff --git a/src/primitives/reward_distributor_info.rs b/src/primitives/reward_distributor_info.rs deleted file mode 100644 index 0f6370fd..00000000 --- a/src/primitives/reward_distributor_info.rs +++ /dev/null @@ -1,276 +0,0 @@ -use chia::{ - clvm_utils::{ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::{cat::CatArgs, singleton::SingletonArgs}, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Layer, Puzzle, SingletonLayer, SpendContext}, - types::MerkleTree, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; - -use crate::{ - Action, ActionLayer, ActionLayerArgs, Finalizer, P2DelegatedBySingletonLayerArgs, - ReserveFinalizer2ndCurryArgs, RewardDistributorAddEntryAction, - RewardDistributorAddIncentivesAction, RewardDistributorCommitIncentivesAction, - RewardDistributorInitiatePayoutAction, RewardDistributorNewEpochAction, - RewardDistributorRemoveEntryAction, RewardDistributorStakeAction, RewardDistributorSyncAction, - RewardDistributorUnstakeAction, RewardDistributorWithdrawIncentivesAction, SpendContextExt, - RESERVE_FINALIZER_DEFAULT_RESERVE_AMOUNT_FROM_STATE_PROGRAM_HASH, -}; - -use super::Reserveful; - -pub type RewardDistributorLayers = SingletonLayer>; - -#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm, Copy)] -#[clvm(list)] -pub struct RoundRewardInfo { - pub cumulative_payout: u64, - #[clvm(rest)] - pub remaining_rewards: u64, -} - -#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm, Copy)] -#[clvm(list)] -pub struct RoundTimeInfo { - pub last_update: u64, - #[clvm(rest)] - pub epoch_end: u64, -} - -#[must_use] -#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm, Copy)] -#[clvm(list)] -pub struct RewardDistributorState { - pub total_reserves: u64, - pub active_shares: u64, - pub round_reward_info: RoundRewardInfo, - pub round_time_info: RoundTimeInfo, -} - -impl RewardDistributorState { - pub fn initial(first_epoch_start: u64) -> Self { - Self { - total_reserves: 0, - active_shares: 0, - round_reward_info: RoundRewardInfo { - cumulative_payout: 0, - remaining_rewards: 0, - }, - round_time_info: RoundTimeInfo { - last_update: first_epoch_start, - epoch_end: first_epoch_start, - }, - } - } -} - -impl Reserveful for RewardDistributorState { - fn reserve_amount(&self, index: u64) -> u64 { - if index == 0 { - self.total_reserves - } else { - 0 - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, ToClvm, FromClvm)] -#[repr(u8)] -#[clvm(atom)] -pub enum RewardDistributorType { - Manager = 1, - Nft = 2, -} - -#[must_use] -#[derive(Debug, Clone, PartialEq, Eq, Copy, ToClvm, FromClvm)] -#[clvm(list)] -pub struct RewardDistributorConstants { - pub launcher_id: Bytes32, - pub reward_distributor_type: RewardDistributorType, - pub manager_or_collection_did_launcher_id: Bytes32, - pub fee_payout_puzzle_hash: Bytes32, - pub epoch_seconds: u64, - pub max_seconds_offset: u64, - pub payout_threshold: u64, - pub fee_bps: u64, - pub withdrawal_share_bps: u64, - pub reserve_asset_id: Bytes32, - pub reserve_inner_puzzle_hash: Bytes32, - pub reserve_full_puzzle_hash: Bytes32, -} - -impl RewardDistributorConstants { - #[allow(clippy::too_many_arguments)] - pub fn without_launcher_id( - reward_distributor_type: RewardDistributorType, - manager_or_collection_did_launcher_id: Bytes32, - fee_payout_puzzle_hash: Bytes32, - epoch_seconds: u64, - max_seconds_offset: u64, - payout_threshold: u64, - fee_bps: u64, - withdrawal_share_bps: u64, - reserve_asset_id: Bytes32, - ) -> Self { - Self { - launcher_id: Bytes32::default(), - reward_distributor_type, - manager_or_collection_did_launcher_id, - fee_payout_puzzle_hash, - epoch_seconds, - max_seconds_offset, - payout_threshold, - fee_bps, - withdrawal_share_bps, - reserve_asset_id, - reserve_inner_puzzle_hash: Bytes32::default(), - reserve_full_puzzle_hash: Bytes32::default(), - } - } - - pub fn with_launcher_id(mut self, launcher_id: Bytes32) -> Self { - self.launcher_id = launcher_id; - self.reserve_inner_puzzle_hash = - P2DelegatedBySingletonLayerArgs::curry_tree_hash_with_launcher_id(launcher_id, 0) - .into(); - self.reserve_full_puzzle_hash = - CatArgs::curry_tree_hash(self.reserve_asset_id, self.reserve_inner_puzzle_hash.into()) - .into(); - self - } -} - -#[must_use] -#[derive(Debug, Clone, PartialEq, Eq, Copy)] -pub struct RewardDistributorInfo { - pub state: RewardDistributorState, - - pub constants: RewardDistributorConstants, -} - -impl RewardDistributorInfo { - pub fn new(state: RewardDistributorState, constants: RewardDistributorConstants) -> Self { - Self { state, constants } - } - - pub fn with_state(mut self, state: RewardDistributorState) -> Self { - self.state = state; - self - } - - pub fn action_puzzle_hashes(constants: &RewardDistributorConstants) -> [Bytes32; 8] { - [ - RewardDistributorAddIncentivesAction::from_constants(constants) - .tree_hash() - .into(), - RewardDistributorCommitIncentivesAction::from_constants(constants) - .tree_hash() - .into(), - RewardDistributorInitiatePayoutAction::from_constants(constants) - .tree_hash() - .into(), - RewardDistributorNewEpochAction::from_constants(constants) - .tree_hash() - .into(), - RewardDistributorSyncAction::from_constants(constants) - .tree_hash() - .into(), - RewardDistributorWithdrawIncentivesAction::from_constants(constants) - .tree_hash() - .into(), - match constants.reward_distributor_type { - RewardDistributorType::Manager => { - RewardDistributorAddEntryAction::from_constants(constants) - .tree_hash() - .into() - } - RewardDistributorType::Nft => { - RewardDistributorStakeAction::from_constants(constants) - .tree_hash() - .into() - } - }, - match constants.reward_distributor_type { - RewardDistributorType::Manager => { - RewardDistributorRemoveEntryAction::from_constants(constants) - .tree_hash() - .into() - } - RewardDistributorType::Nft => { - RewardDistributorUnstakeAction::from_constants(constants) - .tree_hash() - .into() - } - }, - ] - } - - pub fn into_layers( - self, - ctx: &mut SpendContext, - ) -> Result { - Ok(SingletonLayer::new( - self.constants.launcher_id, - ActionLayer::::from_action_puzzle_hashes( - &Self::action_puzzle_hashes(&self.constants), - self.state, - Finalizer::Reserve { - reserve_full_puzzle_hash: self.constants.reserve_full_puzzle_hash, - reserve_inner_puzzle_hash: self.constants.reserve_inner_puzzle_hash, - reserve_amount_from_state_program: ctx - .default_reserve_amount_from_state_program()?, - hint: self.constants.launcher_id, - }, - ), - )) - } - - pub fn parse( - allocator: &mut Allocator, - puzzle: Puzzle, - constants: RewardDistributorConstants, - ) -> Result, DriverError> { - let Some(layers) = RewardDistributorLayers::parse_puzzle(allocator, puzzle)? else { - return Ok(None); - }; - - let action_puzzle_hashes = Self::action_puzzle_hashes(&constants); - let merkle_root = MerkleTree::new(&action_puzzle_hashes).root(); - if layers.inner_puzzle.merkle_root != merkle_root { - return Ok(None); - } - - Ok(Some(Self::from_layers(layers, constants))) - } - - pub fn from_layers( - layers: RewardDistributorLayers, - constants: RewardDistributorConstants, - ) -> Self { - Self { - state: layers.inner_puzzle.state, - constants, - } - } - - pub fn puzzle_hash(&self) -> TreeHash { - SingletonArgs::curry_tree_hash(self.constants.launcher_id, self.inner_puzzle_hash()) - } - - pub fn inner_puzzle_hash(&self) -> TreeHash { - ActionLayerArgs::curry_tree_hash( - ReserveFinalizer2ndCurryArgs::curry_tree_hash( - self.constants.reserve_full_puzzle_hash, - self.constants.reserve_inner_puzzle_hash, - RESERVE_FINALIZER_DEFAULT_RESERVE_AMOUNT_FROM_STATE_PROGRAM_HASH, - self.constants.launcher_id, - ), - MerkleTree::new(&Self::action_puzzle_hashes(&self.constants)).root(), - self.state.tree_hash(), - ) - } -} diff --git a/src/primitives/slot.rs b/src/primitives/slot.rs deleted file mode 100644 index 602711fa..00000000 --- a/src/primitives/slot.rs +++ /dev/null @@ -1,139 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::{Bytes32, Coin, CoinSpend}, - puzzles::singleton::{SingletonArgs, SingletonStruct}, -}; -use chia_wallet_sdk::driver::{DriverError, SpendContext}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::NodePtr; -use hex_literal::hex; - -use crate::SpendContextExt; - -use super::SlotInfo; - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct SlotProof { - pub parent_parent_info: Bytes32, - pub parent_inner_puzzle_hash: Bytes32, -} - -impl SlotProof { - pub fn slot_parent_id(&self, launcher_id: Bytes32) -> Bytes32 { - Coin::new( - self.parent_parent_info, - SingletonArgs::curry_tree_hash(launcher_id, self.parent_inner_puzzle_hash.into()) - .into(), - 1, - ) - .coin_id() - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -#[must_use] -pub struct Slot { - pub coin: Coin, - pub proof: SlotProof, - - pub info: SlotInfo, -} - -impl Slot { - pub fn new(proof: SlotProof, info: SlotInfo) -> Self { - let parent_coin_id = proof.slot_parent_id(info.launcher_id); - - Self { - coin: Coin::new(parent_coin_id, Slot::::puzzle_hash(&info).into(), 0), - proof, - info, - } - } - - pub fn first_curry_hash(launcher_id: Bytes32, nonce: u64) -> TreeHash { - CurriedProgram { - program: SLOT_PUZZLE_HASH, - args: Slot1stCurryArgs { - singleton_struct: SingletonStruct::new(launcher_id), - nonce, - }, - } - .tree_hash() - } - - pub fn puzzle_hash(info: &SlotInfo) -> TreeHash { - CurriedProgram { - program: Self::first_curry_hash(info.launcher_id, info.nonce), - args: Slot2ndCurryArgs { - value_hash: info.value_hash, - }, - } - .tree_hash() - } - - pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - let program = ctx.slot_puzzle()?; - let self_program = ctx.alloc(&CurriedProgram { - program, - args: Slot1stCurryArgs { - singleton_struct: SingletonStruct::new(self.info.launcher_id), - nonce: self.info.nonce, - }, - })?; - - ctx.alloc(&CurriedProgram { - program: self_program, - args: Slot2ndCurryArgs { - value_hash: self.info.value_hash, - }, - }) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - spender_inner_puzzle_hash: Bytes32, - ) -> Result<(), DriverError> { - let puzzle_reveal = self.construct_puzzle(ctx)?; - let puzzle_reveal = ctx.serialize(&puzzle_reveal)?; - - let solution = ctx.serialize(&SlotSolution { - parent_parent_info: self.proof.parent_parent_info, - parent_inner_puzzle_hash: self.proof.parent_inner_puzzle_hash, - spender_inner_puzzle_hash, - })?; - - ctx.insert(CoinSpend::new(self.coin, puzzle_reveal, solution)); - - Ok(()) - } -} - -pub const SLOT_PUZZLE: [u8; 456] = hex!("ff02ffff01ff04ffff04ff08ffff04ffff30ff2fffff02ff1effff04ff02ffff04ff05ffff04ff5fff8080808080ffff010180ff808080ffff04ffff04ff14ffff04ffff0112ffff04ff80ffff04ffff02ff1effff04ff02ffff04ff05ffff04ff81bfff8080808080ff8080808080ff808080ffff04ffff01ffff47ff4302ffffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ffff02ffff03ffff07ff0580ffff01ff0bffff0102ffff02ff16ffff04ff02ffff04ff09ff80808080ffff02ff16ffff04ff02ffff04ff0dff8080808080ffff01ff0bffff0101ff058080ff0180ff0bff2affff0bff1cffff0bff1cff32ff0980ffff0bff1cffff0bff3affff0bff1cffff0bff1cff32ffff02ff16ffff04ff02ffff04ff05ff8080808080ffff0bff1cffff0bff3affff0bff1cffff0bff1cff32ff0b80ffff0bff1cff32ff22808080ff22808080ff22808080ff018080"); - -pub const SLOT_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 66460af4bd504bc5e26f05698530a46fceb764b354727faf620e3a49065fa513 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct Slot1stCurryArgs { - pub singleton_struct: SingletonStruct, - pub nonce: u64, -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct Slot2ndCurryArgs { - pub value_hash: Bytes32, -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct SlotSolution { - pub parent_parent_info: Bytes32, - pub parent_inner_puzzle_hash: Bytes32, - pub spender_inner_puzzle_hash: Bytes32, -} diff --git a/src/primitives/slot_info.rs b/src/primitives/slot_info.rs deleted file mode 100644 index 5409f1e7..00000000 --- a/src/primitives/slot_info.rs +++ /dev/null @@ -1,310 +0,0 @@ -use std::cmp::Ordering; - -use chia::{ - clvm_utils::ToTreeHash, - protocol::{Bytes, Bytes32}, -}; -use clvm_traits::{ - clvm_tuple, ClvmDecoder, ClvmEncoder, FromClvm, FromClvmError, ToClvm, ToClvmError, -}; -use hex_literal::hex; - -// comparison is >s, not > -// previous min was 0x8000000000000000000000000000000000000000000000000000000000000000 -// and previous max was 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -pub static SLOT32_MIN_VALUE: [u8; 32] = - hex!("0000000000000000000000000000000000000000000000000000000000000000"); -// the maximum possible value of a slot - will be contained by the other end of the list -pub static SLOT32_MAX_VALUE: [u8; 32] = - hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); - -#[derive(Debug, Clone, PartialEq, Eq)] -#[must_use] -pub struct SlotInfo { - pub nonce: u64, - pub launcher_id: Bytes32, - - pub value_hash: Bytes32, - pub value: V, -} - -impl SlotInfo { - pub fn new(launcher_id: Bytes32, nonce: u64, value_hash: Bytes32, value: V) -> Self { - Self { - launcher_id, - nonce, - value_hash, - value, - } - } - - pub fn from_value(launcher_id: Bytes32, nonce: u64, value: V) -> Self - where - V: ToTreeHash, - { - Self { - launcher_id, - nonce, - value_hash: value.tree_hash().into(), - value, - } - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct SlotNeigborsInfo { - pub left_value: Bytes32, - #[clvm(rest)] - pub right_value: Bytes32, -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct CatalogSlotValue { - pub asset_id: Bytes32, - #[clvm(rest)] - pub neighbors: SlotNeigborsInfo, -} - -impl CatalogSlotValue { - pub fn new(asset_id: Bytes32, left_asset_id: Bytes32, right_asset_id: Bytes32) -> Self { - Self { - asset_id, - neighbors: SlotNeigborsInfo { - left_value: left_asset_id, - right_value: right_asset_id, - }, - } - } - - pub fn initial_left_end() -> Self { - Self::new( - SLOT32_MIN_VALUE.into(), - SLOT32_MIN_VALUE.into(), - SLOT32_MAX_VALUE.into(), - ) - } - - pub fn initial_right_end() -> Self { - Self::new( - SLOT32_MAX_VALUE.into(), - SLOT32_MIN_VALUE.into(), - SLOT32_MAX_VALUE.into(), - ) - } -} - -impl Ord for CatalogSlotValue { - fn cmp(&self, other: &Self) -> Ordering { - self.asset_id.cmp(&other.asset_id) - } -} - -impl PartialOrd for CatalogSlotValue { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct XchandlesDataValue { - pub owner_launcher_id: Bytes32, - #[clvm(rest)] - pub resolved_data: Bytes, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct XchandlesSlotValue { - pub handle_hash: Bytes32, - pub neighbors: SlotNeigborsInfo, - pub expiration: u64, - pub owner_launcher_id: Bytes32, - pub resolved_data: Bytes, -} - -impl XchandlesSlotValue { - pub fn new( - handle_hash: Bytes32, - left_handle_hash: Bytes32, - right_handle_hash: Bytes32, - expiration: u64, - owner_launcher_id: Bytes32, - resolved_data: Bytes, - ) -> Self { - Self { - handle_hash, - neighbors: SlotNeigborsInfo { - left_value: left_handle_hash, - right_value: right_handle_hash, - }, - expiration, - owner_launcher_id, - resolved_data, - } - } - - pub fn rest_data(&self) -> XchandlesDataValue { - XchandlesDataValue { - owner_launcher_id: self.owner_launcher_id, - resolved_data: self.resolved_data.clone(), - } - } - - pub fn initial_left_end() -> Self { - XchandlesSlotValue::new( - SLOT32_MIN_VALUE.into(), - SLOT32_MIN_VALUE.into(), - SLOT32_MAX_VALUE.into(), - u64::MAX, - Bytes32::default(), - Bytes::default(), - ) - } - - pub fn initial_right_end() -> Self { - XchandlesSlotValue::new( - SLOT32_MAX_VALUE.into(), - SLOT32_MIN_VALUE.into(), - SLOT32_MAX_VALUE.into(), - u64::MAX, - Bytes32::default(), - Bytes::default(), - ) - } - - pub fn with_neighbors(self, left_handle_hash: Bytes32, right_handle_hash: Bytes32) -> Self { - Self { - handle_hash: self.handle_hash, - neighbors: SlotNeigborsInfo { - left_value: left_handle_hash, - right_value: right_handle_hash, - }, - expiration: self.expiration, - owner_launcher_id: self.owner_launcher_id, - resolved_data: self.resolved_data, - } - } - - pub fn with_expiration(self, expiration: u64) -> Self { - Self { - handle_hash: self.handle_hash, - neighbors: self.neighbors, - expiration, - owner_launcher_id: self.owner_launcher_id, - resolved_data: self.resolved_data.clone(), - } - } - - pub fn with_data(self, owner_launcher_id: Bytes32, resolved_data: Bytes) -> Self { - Self { - handle_hash: self.handle_hash, - neighbors: self.neighbors, - expiration: self.expiration, - owner_launcher_id, - resolved_data, - } - } -} - -impl> FromClvm for XchandlesSlotValue { - fn from_clvm(decoder: &D, node: N) -> Result { - #[allow(clippy::type_complexity)] - let ((handle_hash, (left, right)), (expiration, (owner_launcher_id, resolved_data))): ( - (Bytes32, (Bytes32, Bytes32)), - (u64, (Bytes32, Bytes)), - ) = FromClvm::from_clvm(decoder, node)?; - - Ok(Self::new( - handle_hash, - left, - right, - expiration, - owner_launcher_id, - resolved_data, - )) - } -} - -impl> ToClvm for XchandlesSlotValue { - fn to_clvm(&self, encoder: &mut E) -> Result { - let obj = clvm_tuple!( - clvm_tuple!( - self.handle_hash, - clvm_tuple!(self.neighbors.left_value, self.neighbors.right_value) - ), - clvm_tuple!( - self.expiration, - clvm_tuple!(self.owner_launcher_id, self.resolved_data.clone()) - ), - ); - - obj.to_clvm(encoder) - } -} - -impl Ord for XchandlesSlotValue { - fn cmp(&self, other: &Self) -> Ordering { - self.handle_hash.cmp(&other.handle_hash) - } -} - -impl PartialOrd for XchandlesSlotValue { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum RewardDistributorSlotNonce { - REWARD = 1, - COMMITMENT = 2, - ENTRY = 3, -} - -impl RewardDistributorSlotNonce { - pub fn from_u64(value: u64) -> Option { - match value { - 1 => Some(Self::REWARD), - 2 => Some(Self::COMMITMENT), - 3 => Some(Self::ENTRY), - _ => None, - } - } - - pub fn to_u64(self) -> u64 { - match self { - Self::REWARD => 1, - Self::COMMITMENT => 2, - Self::ENTRY => 3, - } - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorRewardSlotValue { - pub epoch_start: u64, - pub next_epoch_initialized: bool, - #[clvm(rest)] - pub rewards: u64, -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorCommitmentSlotValue { - pub epoch_start: u64, - pub clawback_ph: Bytes32, - #[clvm(rest)] - pub rewards: u64, -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct RewardDistributorEntrySlotValue { - pub payout_puzzle_hash: Bytes32, - pub initial_cumulative_payout: u64, - #[clvm(rest)] - pub shares: u64, -} diff --git a/src/primitives/state_scheduler.rs b/src/primitives/state_scheduler.rs deleted file mode 100644 index 04d50077..00000000 --- a/src/primitives/state_scheduler.rs +++ /dev/null @@ -1,276 +0,0 @@ -use chia::{ - clvm_utils::ToTreeHash, - protocol::{Bytes32, Coin, CoinSpend}, - puzzles::{ - singleton::{LauncherSolution, SingletonArgs, SingletonSolution}, - EveProof, LineageProof, Proof, - }, -}; -use chia_puzzles::SINGLETON_LAUNCHER_HASH; -use chia_wallet_sdk::driver::{DriverError, Layer, Spend, SpendContext}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::{serde::node_from_bytes, Allocator, NodePtr}; - -use crate::{StateSchedulerInfo, StateSchedulerLayerSolution}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StateScheduler -where - S: ToTreeHash + Clone + ToClvm + FromClvm, -{ - pub coin: Coin, - pub proof: Proof, - - pub info: StateSchedulerInfo, -} - -impl StateScheduler -where - S: ToTreeHash + Clone + ToClvm + FromClvm, -{ - pub fn new(coin: Coin, proof: Proof, info: StateSchedulerInfo) -> Self { - Self { coin, proof, info } - } - - pub fn child(&self) -> Option { - // check for both self.info.generation and self.info.generation + 1 to be < self.info.state_schedule.len() - if self.info.generation + 1 >= self.info.state_schedule.len() { - return None; - }; - - let child_proof = Proof::Lineage(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, - }); - - let child_info = self.info.clone().with_generation(self.info.generation + 1); - let child_inner_puzzle_hash = child_info.inner_puzzle_hash(); - - Some(Self { - coin: Coin::new( - self.coin.coin_id(), - SingletonArgs::curry_tree_hash(self.info.launcher_id, child_inner_puzzle_hash) - .into(), - 1, - ), - proof: child_proof, - info: child_info, - }) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - other_singleton_inner_puzzle_hash: Bytes32, - ) -> Result<(), DriverError> { - let lineage_proof = self.proof; - let coin = self.coin; - - let layers = self.info.into_layers(); - - let puzzle = layers.construct_puzzle(ctx)?; - let solution = layers.construct_solution( - ctx, - SingletonSolution { - lineage_proof, - amount: coin.amount, - inner_solution: StateSchedulerLayerSolution { - other_singleton_inner_puzzle_hash, - inner_solution: (), - }, - }, - )?; - - ctx.spend(coin, Spend::new(puzzle, solution))?; - - Ok(()) - } - - pub fn from_launcher_spend( - ctx: &mut SpendContext, - launcher_spend: CoinSpend, - ) -> Result, DriverError> { - if launcher_spend.coin.puzzle_hash != SINGLETON_LAUNCHER_HASH.into() { - return Ok(None); - } - - let solution = node_from_bytes(ctx, &launcher_spend.solution)?; - let solution = ctx.extract::>(solution)?; - - let Some((info, _other_hints)) = - StateSchedulerInfo::from_launcher_solution::(ctx, solution)? - else { - return Ok(None); - }; - - let new_coin = Coin::new( - launcher_spend.coin.coin_id(), - SingletonArgs::curry_tree_hash(info.launcher_id, info.inner_puzzle_hash()).into(), - 1, - ); - - Ok(Some(Self::new( - new_coin, - Proof::Eve(EveProof { - parent_parent_coin_info: launcher_spend.coin.parent_coin_info, - parent_amount: launcher_spend.coin.amount, - }), - info, - ))) - } -} - -#[cfg(test)] -mod tests { - use chia_puzzle_types::Memos; - use chia_wallet_sdk::{ - driver::{Launcher, SingletonLayer}, - test::Simulator, - types::Conditions, - }; - use clvmr::NodePtr; - - use crate::{CatalogRegistryState, StateSchedulerLauncherHints}; - - use super::*; - - fn mock_state(generator: u8) -> CatalogRegistryState { - CatalogRegistryState { - cat_maker_puzzle_hash: Bytes32::new([generator; 32]), - registration_price: generator as u64 * 1000, - } - } - - #[test] - fn test_price_scheduler() -> anyhow::Result<()> { - let ctx = &mut SpendContext::new(); - let mut sim = Simulator::new(); - - let schedule: Vec<(u32, CatalogRegistryState)> = vec![ - (0, mock_state(0)), - (1, mock_state(1)), - (2, mock_state(2)), - (3, mock_state(3)), - (4, mock_state(4)), - (5, mock_state(5)), - (6, mock_state(6)), - (7, mock_state(7)), - ]; - let final_puzzle_hash: Bytes32 = "yakuhito".tree_hash().into(); - - // Launch 'other' singleton, which will consume (reveive) the messages - let other_singleton_inner_puzzle = ctx.alloc(&1)?; - let other_singleton_inner_puzzle_hash = ctx.tree_hash(other_singleton_inner_puzzle); - - let other_singleton_launcher = sim.new_coin(SINGLETON_LAUNCHER_HASH.into(), 1); - let other_launcher = Launcher::new(other_singleton_launcher.parent_coin_info, 1); - let (_conds, mut other_singleton_coin) = - other_launcher.spend(ctx, other_singleton_inner_puzzle_hash.into(), ())?; - - sim.spend_coins(ctx.take(), &[])?; - - // Launch state scheduler singleton - let launcher_coin = sim.new_coin(SINGLETON_LAUNCHER_HASH.into(), 1); - let launcher = Launcher::new(launcher_coin.parent_coin_info, 1); - - let first_coin_info = StateSchedulerInfo::new( - launcher_coin.coin_id(), - other_singleton_launcher.coin_id(), - schedule.clone(), - 0, - final_puzzle_hash, - ); - let (_conds, state_scheduler_coin) = launcher.spend( - ctx, - first_coin_info.inner_puzzle_hash().into(), - StateSchedulerLauncherHints { - my_launcher_id: launcher_coin.coin_id(), - receiver_singleton_launcher_id: other_singleton_launcher.coin_id(), - final_puzzle_hash, - state_schedule: schedule.clone(), - final_puzzle_hash_hints: NodePtr::NIL, - }, - )?; - - let spends = ctx.take(); - assert_eq!(spends.len(), 1); - let state_scheduler_launcher_spend = spends[0].clone(); - ctx.insert(state_scheduler_launcher_spend.clone()); - - sim.spend_coins(ctx.take(), &[])?; - - let mut state_scheduler = - StateScheduler::from_launcher_spend(ctx, state_scheduler_launcher_spend)?.unwrap(); - assert_eq!(state_scheduler.info, first_coin_info); - assert_eq!(state_scheduler.coin, state_scheduler_coin); - - let mut other_singleton_coin_parent = other_singleton_coin; - for (index, (block, new_state)) in schedule.iter().enumerate() { - state_scheduler - .clone() - .spend(ctx, other_singleton_inner_puzzle_hash.into())?; - - let spends = ctx.take(); - assert_eq!(spends.len(), 1); - let state_scheduler_spend = spends[0].clone(); - ctx.insert(state_scheduler_spend.clone()); - - let other_singleton = SingletonLayer::::new( - other_singleton_launcher.coin_id(), - other_singleton_inner_puzzle, - ); - let other_singleton_lp = if index == 0 { - Proof::Eve(EveProof { - parent_parent_coin_info: other_singleton_launcher.parent_coin_info, - parent_amount: other_singleton_launcher.amount, - }) - } else { - Proof::Lineage(LineageProof { - parent_parent_coin_info: other_singleton_coin_parent.parent_coin_info, - parent_inner_puzzle_hash: other_singleton_inner_puzzle_hash.into(), - parent_amount: other_singleton_coin_parent.amount, - }) - }; - let state_scheduler_puzzle_hash_ptr = ctx.alloc(&state_scheduler.coin.puzzle_hash)?; - let other_singleton_inner_solution = ctx.alloc( - &Conditions::new() - .receive_message( - 18, - new_state.tree_hash().to_vec().into(), - vec![state_scheduler_puzzle_hash_ptr], - ) - .create_coin(other_singleton_inner_puzzle_hash.into(), 1, Memos::None), - )?; - let other_singleton_spend = other_singleton.construct_spend( - ctx, - SingletonSolution { - lineage_proof: other_singleton_lp, - amount: 1, - inner_solution: other_singleton_inner_solution, - }, - )?; - - ctx.spend(other_singleton_coin, other_singleton_spend)?; - other_singleton_coin_parent = other_singleton_coin; - other_singleton_coin = Coin::new( - other_singleton_coin.coin_id(), - other_singleton_coin.puzzle_hash, - 1, - ); - - sim.spend_coins(ctx.take(), &[])?; - - if index < schedule.len() - 1 { - state_scheduler = state_scheduler.child().unwrap(); - - assert_eq!(state_scheduler.info.state_schedule, schedule); - assert_eq!(state_scheduler.info.generation, *block as usize + 1); - } else { - break; - } - } - - Ok(()) - } -} diff --git a/src/primitives/state_scheduler_info.rs b/src/primitives/state_scheduler_info.rs deleted file mode 100644 index ece6985f..00000000 --- a/src/primitives/state_scheduler_info.rs +++ /dev/null @@ -1,169 +0,0 @@ -use chia::{ - clvm_utils::{ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::{LauncherSolution, SingletonArgs, SingletonStruct}, -}; -use chia_puzzle_types::Memos; -use chia_wallet_sdk::{ - driver::{DriverError, SingletonLayer}, - types::Condition, -}; -use clvm_traits::{clvm_quote, FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; - -use crate::{StateSchedulerLayer, StateSchedulerLayerArgs}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StateSchedulerInfo { - pub launcher_id: Bytes32, - - pub receiver_singleton_launcher_id: Bytes32, - pub state_schedule: Vec<(u32, S)>, // block height + state - pub generation: usize, - pub final_puzzle_hash: Bytes32, -} - -impl StateSchedulerInfo -where - S: ToTreeHash + Clone, -{ - pub fn new( - launcher_id: Bytes32, - receiver_singleton_launcher_id: Bytes32, - state_schedule: Vec<(u32, S)>, - generation: usize, - final_puzzle_hash: Bytes32, - ) -> Self { - Self { - launcher_id, - receiver_singleton_launcher_id, - state_schedule, - generation, - final_puzzle_hash, - } - } - - pub fn with_generation(&self, generation: usize) -> Self { - Self { - generation, - ..self.clone() - } - } - - pub fn inner_puzzle_hash_for( - &self, - next_puzzle_hash: Bytes32, - required_block_height: u32, - new_state: S, - ) -> TreeHash { - let message: Bytes32 = new_state.tree_hash().into(); - - StateSchedulerLayerArgs::curry_tree_hash( - SingletonStruct::new(self.receiver_singleton_launcher_id) - .tree_hash() - .into(), - message, - clvm_quote!(vec![ - Condition::<()>::create_coin(next_puzzle_hash, 1, Memos::None), - Condition::assert_height_absolute(required_block_height), - ]), - ) - } - - pub fn inner_puzzle_hash_for_generation(&self, generation: usize) -> TreeHash { - if generation >= self.state_schedule.len() { - return self.final_puzzle_hash.into(); - } - - let mut inner_puzzle_hash: TreeHash = self.final_puzzle_hash.into(); - - let mut i = self.state_schedule.len(); - while i > generation { - inner_puzzle_hash = self.inner_puzzle_hash_for( - inner_puzzle_hash.into(), - self.state_schedule[i - 1].0, - self.state_schedule[i - 1].1.clone(), - ); - - i -= 1; - } - - inner_puzzle_hash - } - - pub fn inner_puzzle_hash(&self) -> TreeHash { - self.inner_puzzle_hash_for_generation(self.generation) - } - - pub fn into_layers(self) -> SingletonLayer { - let (required_block_height, new_state) = self.state_schedule[self.generation].clone(); - - SingletonLayer::new( - self.launcher_id, - StateSchedulerLayer::new( - SingletonStruct::new(self.receiver_singleton_launcher_id) - .tree_hash() - .into(), - new_state.tree_hash().into(), - required_block_height, - self.inner_puzzle_hash_for_generation(self.generation + 1) - .into(), - ), - ) - } - - pub fn from_launcher_solution( - allocator: &mut Allocator, - laucher_solution: LauncherSolution, - ) -> Result, DriverError> - where - S: FromClvm, - H: FromClvm, - { - let hints = StateSchedulerLauncherHints::::from_clvm( - allocator, - laucher_solution.key_value_list, - )?; - - let candidate = Self::new( - hints.my_launcher_id, - hints.receiver_singleton_launcher_id, - hints.state_schedule, - 0, - hints.final_puzzle_hash, - ); - - let predicted_inner_puzzle_hash = candidate.inner_puzzle_hash(); - let predicted_puzzle_hash = - SingletonArgs::curry_tree_hash(hints.my_launcher_id, predicted_inner_puzzle_hash); - - if laucher_solution.amount == 1 - && laucher_solution.singleton_puzzle_hash == predicted_puzzle_hash.into() - { - Ok(Some((candidate, hints.final_puzzle_hash_hints))) - } else { - Ok(None) - } - } - - pub fn to_hints(&self, final_puzzle_hash_hints: H) -> StateSchedulerLauncherHints { - StateSchedulerLauncherHints { - my_launcher_id: self.launcher_id, - receiver_singleton_launcher_id: self.receiver_singleton_launcher_id, - final_puzzle_hash: self.final_puzzle_hash, - state_schedule: self.state_schedule.clone(), - final_puzzle_hash_hints, - } - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(curry)] -pub struct StateSchedulerLauncherHints { - pub my_launcher_id: Bytes32, - pub receiver_singleton_launcher_id: Bytes32, - pub final_puzzle_hash: Bytes32, - pub state_schedule: Vec<(u32, S)>, - #[clvm(rest)] - pub final_puzzle_hash_hints: H, -} diff --git a/src/primitives/uniqueness_prelauncher.rs b/src/primitives/uniqueness_prelauncher.rs deleted file mode 100644 index 6e2b00b1..00000000 --- a/src/primitives/uniqueness_prelauncher.rs +++ /dev/null @@ -1,117 +0,0 @@ -use chia::{ - clvm_utils::{tree_hash, CurriedProgram, ToTreeHash, TreeHash}, - protocol::{Bytes32, Coin, CoinSpend}, -}; -use chia_puzzles::SINGLETON_LAUNCHER_HASH; -use chia_wallet_sdk::driver::{DriverError, Launcher, SpendContext}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; -use hex_literal::hex; - -use crate::SpendContextExt; - -#[derive(Debug, Clone)] -#[must_use] -pub struct UniquenessPrelauncher { - pub coin: Coin, - pub value: V, -} - -impl UniquenessPrelauncher { - pub fn from_coin(coin: Coin, value: V) -> Self { - Self { coin, value } - } - - pub fn new( - allocator: &mut Allocator, - parent_coin_id: Bytes32, - value: V, - ) -> Result - where - V: ToClvm + Clone, - { - let value_ptr = value.to_clvm(allocator)?; - let value_hash = tree_hash(allocator, value_ptr); - - Ok(Self::from_coin( - Coin::new( - parent_coin_id, - UniquenessPrelauncher::::puzzle_hash(value_hash).into(), - 0, - ), - value, - )) - } - - pub fn first_curry_hash() -> TreeHash { - CurriedProgram { - program: UNIQUENESS_PRELAUNCHER_PUZZLE_HASH, - args: UniquenessPrelauncher1stCurryArgs { - launcher_puzzle_hash: SINGLETON_LAUNCHER_HASH.into(), - }, - } - .tree_hash() - } - - pub fn puzzle_hash(value_hash: TreeHash) -> TreeHash { - CurriedProgram { - program: Self::first_curry_hash(), - args: UniquenessPrelauncher2ndCurryArgs { value: value_hash }, - } - .tree_hash() - } - - pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result - where - V: ToClvm + Clone, - { - let program = ctx.uniqueness_prelauncher_puzzle()?; - let prog_1st_curry = ctx.alloc(&CurriedProgram { - program, - args: UniquenessPrelauncher1stCurryArgs { - launcher_puzzle_hash: SINGLETON_LAUNCHER_HASH.into(), - }, - })?; - - ctx.alloc(&CurriedProgram { - program: prog_1st_curry, - args: UniquenessPrelauncher2ndCurryArgs { - value: self.value.clone(), - }, - }) - } - - pub fn spend(self, ctx: &mut SpendContext) -> Result - where - V: ToClvm + Clone, - { - let puzzle_reveal = self.construct_puzzle(ctx)?; - let puzzle_reveal = ctx.serialize(&puzzle_reveal)?; - - let solution = ctx.serialize(&NodePtr::NIL)?; - - ctx.insert(CoinSpend::new(self.coin, puzzle_reveal, solution)); - - Ok(Launcher::new(self.coin.coin_id(), 1)) - } -} - -pub const UNIQUENESS_PRELAUNCHER_PUZZLE: [u8; 59] = hex!("ff02ffff01ff04ffff04ff04ffff04ff05ffff01ff01808080ffff04ffff04ff06ffff04ff0bff808080ff808080ffff04ffff01ff333eff018080"); - -pub const UNIQUENESS_PRELAUNCHER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - 851c3d39cef84cfd9449afcaeff5f50d1be9371d8b7d6057ac318bec553a1a9f - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct UniquenessPrelauncher1stCurryArgs { - pub launcher_puzzle_hash: Bytes32, -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct UniquenessPrelauncher2ndCurryArgs { - pub value: V, -} diff --git a/src/primitives/verification.rs b/src/primitives/verification.rs deleted file mode 100644 index 347eeb70..00000000 --- a/src/primitives/verification.rs +++ /dev/null @@ -1,272 +0,0 @@ -use chia::{ - clvm_utils::{ToTreeHash, TreeHash}, - protocol::{Bytes32, Coin, CoinSpend}, - puzzles::{ - singleton::{SingletonArgs, SingletonSolution}, - EveProof, LineageProof, Proof, - }, -}; -use chia_puzzles::SINGLETON_LAUNCHER_HASH; -use chia_wallet_sdk::driver::{DriverError, Layer, Puzzle, SingletonLayer, SpendContext}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::{Allocator, NodePtr}; - -use crate::{ - VerificationLayer, VerificationLayer2ndCurryArgs, VerificationLayerSolution, VerifiedData, -}; - -use super::VerificationInfo; - -type VerificationLayers = SingletonLayer; - -#[derive(Debug, Clone, PartialEq, Eq)] -#[must_use] -pub struct Verification { - pub coin: Coin, - pub proof: Proof, - - pub info: VerificationInfo, -} - -impl Verification { - pub fn new(coin: Coin, proof: Proof, info: VerificationInfo) -> Self { - Self { coin, proof, info } - } - - pub fn after_mint( - launcher_parent: Bytes32, - revocation_singleton_launcher_id: Bytes32, - verified_data: VerifiedData, - ) -> Self { - let launcher_coin = Coin::new(launcher_parent, SINGLETON_LAUNCHER_HASH.into(), 0); - let verification_launcher_id = launcher_coin.coin_id(); - - let info = VerificationInfo { - launcher_id: verification_launcher_id, - revocation_singleton_launcher_id, - verified_data, - }; - - Self { - coin: Coin::new(verification_launcher_id, Self::puzzle_hash(&info).into(), 1), - proof: Proof::Eve(EveProof { - parent_parent_coin_info: launcher_parent, - parent_amount: 0, - }), - info, - } - } - - pub fn inner_puzzle_hash( - revocation_singleton_launcher_id: Bytes32, - verified_data: T, - ) -> TreeHash - where - T: ToTreeHash, - { - VerificationLayer2ndCurryArgs::curry_tree_hash( - revocation_singleton_launcher_id, - verified_data, - ) - } - - pub fn puzzle_hash(info: &VerificationInfo) -> TreeHash { - SingletonArgs::curry_tree_hash( - info.launcher_id, - Self::inner_puzzle_hash( - info.revocation_singleton_launcher_id, - info.verified_data.tree_hash(), - ), - ) - } - - pub fn into_layers(self) -> VerificationLayers { - SingletonLayer::new( - self.info.launcher_id, - VerificationLayer::new( - self.info.revocation_singleton_launcher_id, - self.info.verified_data, - ), - ) - } - - pub fn into_layers_with_clone(&self) -> VerificationLayers { - SingletonLayer::new( - self.info.launcher_id, - VerificationLayer::new( - self.info.revocation_singleton_launcher_id, - self.info.verified_data.clone(), - ), - ) - } - - pub fn construct_puzzle(&self, ctx: &mut SpendContext) -> Result { - let layers = self.into_layers_with_clone(); - - layers.construct_puzzle(ctx) - } - - pub fn spend( - self, - ctx: &mut SpendContext, - revocation_singleton_inner_puzzle_hash: Option, - ) -> Result<(), DriverError> { - let sol = SingletonSolution { - lineage_proof: self.proof, - amount: self.coin.amount, - inner_solution: VerificationLayerSolution { - revocation_singleton_inner_puzzle_hash, - }, - }; - let my_coin = self.coin; - - let layers = self.into_layers(); - - let puzzle_reveal = layers.construct_puzzle(ctx)?; - let solution = layers.construct_solution(ctx, sol)?; - - let puzzle_reveal = ctx.serialize(&puzzle_reveal)?; - let solution = ctx.serialize(&solution)?; - - ctx.insert(CoinSpend::new(my_coin, puzzle_reveal, solution)); - - Ok(()) - } -} - -impl Verification { - pub fn from_parent_spend( - allocator: &mut Allocator, - parent_coin: Coin, - parent_puzzle: Puzzle, - ) -> Result, DriverError> { - let Some(parent_layers) = VerificationLayers::parse_puzzle(allocator, parent_puzzle)? - else { - return Ok(None); - }; - - let parent_inner_puzzle_hash = Verification::inner_puzzle_hash( - parent_layers.inner_puzzle.revocation_singleton_launcher_id, - parent_layers.inner_puzzle.verified_data.tree_hash(), - ) - .into(); - - Ok(Some(Self { - coin: Coin::new(parent_coin.coin_id(), parent_coin.puzzle_hash, 1), - proof: Proof::Lineage(LineageProof { - parent_parent_coin_info: parent_coin.parent_coin_info, - parent_inner_puzzle_hash, - parent_amount: parent_coin.amount, - }), - info: VerificationInfo::new( - parent_layers.launcher_id, - parent_layers.inner_puzzle.revocation_singleton_launcher_id, - parent_layers.inner_puzzle.verified_data, - ), - })) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm)] -#[clvm(list)] -pub struct VerificationLauncherKVList { - pub revocation_singleton_launcher_id: Bytes32, - pub verified_data: VerifiedData, -} - -#[cfg(test)] -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}, - test::Simulator, - types::Conditions, - }; - - use crate::{VerificationAsserter, VerifiedData}; - - use super::*; - - #[test] - fn test_verifications_and_asserter() -> anyhow::Result<()> { - let mut sim = Simulator::new(); - let ctx = &mut SpendContext::new(); - let bls = sim.bls(1); - let p2 = StandardLayer::new(bls.pk); - - let did_launcher = Launcher::new(bls.coin.coin_id(), 1); - let (create_did, did) = did_launcher.create_simple_did(ctx, &p2)?; - p2.spend(ctx, bls.coin, create_did)?; - - let verifier_proof = did.child_lineage_proof(); - let did = did.update( - ctx, - &p2, - 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 - - let verified_data = VerifiedData { - version: 1, - asset_id: Bytes32::new([2; 32]), - data_hash: Bytes32::new([3; 32]), - comment: "Test verification for test testing purposes only.".to_string(), - }; - let verification = Verification::after_mint( - verification_launcher.coin().parent_coin_info, - did.info.launcher_id, - verified_data.clone(), - ); - - let (_conds, new_coin) = verification_launcher.with_singleton_amount(1).spend( - ctx, - Verification::inner_puzzle_hash( - verification.info.revocation_singleton_launcher_id, - verification.info.verified_data.clone(), - ) - .into(), - (), - )?; - - assert_eq!(new_coin, verification.coin); - - // spend the verification coin in oracle mode - verification.clone().spend(ctx, None)?; - - let parent_puzzle = verification.construct_puzzle(ctx)?; - let parent_puzzle = Puzzle::parse(ctx, parent_puzzle); - let verification = - Verification::from_parent_spend(ctx, verification.coin, parent_puzzle)?.unwrap(); - - // create verification payment and spend it - let verification_asserter = VerificationAsserter::from( - did.info.launcher_id, - verified_data.version, - verified_data.asset_id.tree_hash(), - verified_data.data_hash.tree_hash(), - ); - - let payment_coin = sim.new_coin(verification_asserter.tree_hash().into(), 1337); - verification_asserter.spend(ctx, payment_coin, verifier_proof, 0, verified_data.comment)?; - - // melt verification coin - let revocation_singleton_inner_ph = did.info.inner_puzzle_hash().into(); - - let msg_data = ctx.alloc(&verification.coin.puzzle_hash)?; - let _ = did.update( - ctx, - &p2, - Conditions::new().send_message(18, Bytes::default(), vec![msg_data]), - )?; - - verification.spend(ctx, Some(revocation_singleton_inner_ph))?; - - sim.spend_coins(ctx.take(), &[bls.sk])?; - - Ok(()) - } -} diff --git a/src/primitives/verification_asserter.rs b/src/primitives/verification_asserter.rs deleted file mode 100644 index e52bd4a5..00000000 --- a/src/primitives/verification_asserter.rs +++ /dev/null @@ -1,207 +0,0 @@ -use chia::{ - clvm_utils::{CurriedProgram, ToTreeHash, TreeHash}, - protocol::{Bytes32, Coin}, -}; -use chia_puzzle_types::{singleton::SingletonStruct, LineageProof}; -use chia_puzzles::{SINGLETON_LAUNCHER_HASH, SINGLETON_TOP_LAYER_V1_1_HASH}; -use chia_wallet_sdk::driver::{DriverError, Spend, SpendContext}; -use clvm_traits::{FromClvm, ToClvm}; -use hex_literal::hex; - -use crate::{SpendContextExt, VerificationLayer1stCurryArgs}; - -#[derive(Debug, Copy, Clone)] -#[must_use] -pub struct VerificationAsserter { - pub verifier_singleton_struct_hash: Bytes32, - pub verification_inner_puzzle_self_hash: Bytes32, - pub version: u32, - pub tail_hash_hash: Bytes32, - pub data_hash_hash: Bytes32, -} - -impl VerificationAsserter { - pub fn new( - verifier_singleton_struct_hash: Bytes32, - verification_inner_puzzle_self_hash: Bytes32, - version: u32, - tail_hash_hash: TreeHash, - data_hash_hash: TreeHash, - ) -> Self { - Self { - verifier_singleton_struct_hash, - verification_inner_puzzle_self_hash, - version, - tail_hash_hash: tail_hash_hash.into(), - data_hash_hash: data_hash_hash.into(), - } - } - - pub fn from( - verifier_launcher_id: Bytes32, - version: u32, - tail_hash_hash: TreeHash, - data_hash_hash: TreeHash, - ) -> Self { - Self::new( - SingletonStruct::new(verifier_launcher_id) - .tree_hash() - .into(), - VerificationLayer1stCurryArgs::curry_tree_hash(verifier_launcher_id).into(), - version, - tail_hash_hash, - data_hash_hash, - ) - } - - pub fn tree_hash(&self) -> TreeHash { - CurriedProgram { - program: VERIFICATION_ASSERTER_PUZZLE_HASH, - args: VerificationAsserterArgs::new( - self.verifier_singleton_struct_hash, - CurriedProgram { - program: CATALOG_VERIFICATION_MAKER_PUZZLE_HASH, - args: CatalogVerificationInnerPuzzleMakerArgs::new( - self.verification_inner_puzzle_self_hash, - self.version, - self.tail_hash_hash.into(), - self.data_hash_hash.into(), - ), - } - .tree_hash(), - ), - } - .tree_hash() - } - - pub fn inner_spend( - &self, - ctx: &mut SpendContext, - verifier_proof: LineageProof, - launcher_amount: u64, - comment: String, - ) -> Result { - let inner_program = ctx.catalog_verification_maker_puzzle()?; - let verification_inner_puzzle_maker = ctx.alloc(&CurriedProgram { - program: inner_program, - args: CatalogVerificationInnerPuzzleMakerArgs::new( - self.verification_inner_puzzle_self_hash, - self.version, - self.tail_hash_hash.into(), - self.data_hash_hash.into(), - ), - })?; - - let program = ctx.verification_asserter_puzzle()?; - let puzzle = ctx.alloc(&CurriedProgram { - program, - args: VerificationAsserterArgs::new( - self.verifier_singleton_struct_hash, - verification_inner_puzzle_maker, - ), - })?; - - let solution = ctx.alloc(&VerificationAsserterSolution { - verifier_proof, - verification_inner_puzzle_maker_solution: CatalogVerificationInnerPuzzleMakerSolution { - comment, - }, - launcher_amount, - })?; - - Ok(Spend::new(puzzle, solution)) - } - - pub fn spend( - &self, - ctx: &mut SpendContext, - coin: Coin, - verifier_proof: LineageProof, - launcher_amount: u64, - comment: String, - ) -> Result<(), DriverError> { - let spend = self.inner_spend(ctx, verifier_proof, launcher_amount, comment)?; - - ctx.spend(coin, spend)?; - Ok(()) - } -} - -pub const VERIFICATION_ASSERTER_PUZZLE: [u8; 434] = hex!("ff02ffff01ff04ffff04ff04ffff04ffff0bffff0bff2effff0bff0affff0bff0aff36ff0580ffff0bff0affff0bff3effff0bff0affff0bff0aff36ffff0bffff0102ffff0bffff0101ff0580ffff0bffff0102ffff0bffff0101ffff30ffff30ff819fffff0bff2effff0bff0affff0bff0aff36ff0580ffff0bff0affff0bff3effff0bff0affff0bff0aff36ff1780ffff0bff0affff0bff3effff0bff0affff0bff0aff36ff82015f80ffff0bff0aff36ff26808080ff26808080ff26808080ff8202df80ff0bff81ff8080ffff0bffff0101ff0b80808080ffff0bff0affff0bff3effff0bff0affff0bff0aff36ffff02ff2fff81bf8080ffff0bff0aff36ff26808080ff26808080ff26808080ff8080ff808080ff8080ffff04ffff01ff3fff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff018080"); - -pub const VERIFICATION_ASSERTER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - d33c552997cea95b0b66253b34f93c9126bd72839853194a2d03d95d1cc902a4 - " -)); - -pub const CATALOG_VERIFICATION_MAKER_PUZZLE: [u8; 299] = hex!("ff02ffff01ff0bff16ffff0bff04ffff0bff04ff1aff0580ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bffff0101ff058080ffff0bff04ffff0bff1effff0bff04ffff0bff04ff1affff0bffff0102ffff0bffff0101ff0b80ffff0bffff0102ff17ffff0bffff0102ff2fffff0bffff0101ff5f8080808080ffff0bff04ff1aff12808080ff12808080ff12808080ffff04ffff01ff02ffffa04bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459aa09dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2ffa102a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222a102a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5ff018080"); - -pub const CATALOG_VERIFICATION_MAKER_PUZZLE_HASH: TreeHash = TreeHash::new(hex!( - " - cd2caba380e2bb21e209f8b5cad9d832a20bec53b5ffd3e29db51e4041a3d266 - " -)); - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct VerificationAsserterArgs

{ - pub singleton_mod_hash: Bytes32, - pub launcher_puzzle_hash: Bytes32, - pub verifier_singleton_struct_hash: Bytes32, - pub verification_inner_puzzle_maker: P, -} - -impl

VerificationAsserterArgs

{ - pub fn new( - verifier_singleton_struct_hash: Bytes32, - verification_inner_puzzle_maker: P, - ) -> Self { - Self { - singleton_mod_hash: SINGLETON_TOP_LAYER_V1_1_HASH.into(), - launcher_puzzle_hash: SINGLETON_LAUNCHER_HASH.into(), - verifier_singleton_struct_hash, - verification_inner_puzzle_maker, - } - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(list)] -pub struct VerificationAsserterSolution { - pub verifier_proof: LineageProof, - pub verification_inner_puzzle_maker_solution: S, - #[clvm(rest)] - pub launcher_amount: u64, -} - -#[derive(ToClvm, FromClvm, Debug, Clone, Copy, PartialEq, Eq)] -#[clvm(curry)] -pub struct CatalogVerificationInnerPuzzleMakerArgs { - pub verification_inner_puzzle_self_hash: Bytes32, - pub version: u32, - pub tail_hash_hash: Bytes32, - pub data_hash_hash: Bytes32, -} - -impl CatalogVerificationInnerPuzzleMakerArgs { - pub fn new( - verification_inner_puzzle_self_hash: Bytes32, - version: u32, - tail_hash_hash: TreeHash, - data_hash_hash: TreeHash, - ) -> Self { - Self { - verification_inner_puzzle_self_hash, - version, - tail_hash_hash: tail_hash_hash.into(), - data_hash_hash: data_hash_hash.into(), - } - } -} - -#[derive(ToClvm, FromClvm, Debug, Clone, PartialEq, Eq)] -#[clvm(list)] -pub struct CatalogVerificationInnerPuzzleMakerSolution { - pub comment: String, -} diff --git a/src/primitives/verification_info.rs b/src/primitives/verification_info.rs deleted file mode 100644 index fd549b4c..00000000 --- a/src/primitives/verification_info.rs +++ /dev/null @@ -1,26 +0,0 @@ -use chia::protocol::Bytes32; - -use crate::VerifiedData; - -#[derive(Debug, Clone, PartialEq, Eq)] -#[must_use] -pub struct VerificationInfo { - pub launcher_id: Bytes32, - - pub revocation_singleton_launcher_id: Bytes32, - pub verified_data: VerifiedData, -} - -impl VerificationInfo { - pub fn new( - launcher_id: Bytes32, - revocation_singleton_launcher_id: Bytes32, - verified_data: VerifiedData, - ) -> Self { - Self { - launcher_id, - revocation_singleton_launcher_id, - verified_data, - } - } -} diff --git a/src/primitives/xchandles_registry.rs b/src/primitives/xchandles_registry.rs deleted file mode 100644 index 776411bb..00000000 --- a/src/primitives/xchandles_registry.rs +++ /dev/null @@ -1,520 +0,0 @@ -use chia::{ - bls::Signature, - clvm_utils::ToTreeHash, - 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}; -use clvm_traits::{clvm_list, match_tuple}; -use clvmr::NodePtr; - -use crate::{ - eve_singleton_inner_puzzle, Action, ActionLayer, ActionLayerSolution, DelegatedStateAction, - Registry, XchandlesExpireAction, XchandlesExtendAction, XchandlesOracleAction, - XchandlesRefundAction, XchandlesRegisterAction, XchandlesUpdateAction, -}; - -use super::{ - Slot, SlotInfo, SlotProof, XchandlesConstants, XchandlesRegistryInfo, XchandlesRegistryState, - XchandlesSlotValue, -}; - -#[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)] -#[must_use] -pub struct XchandlesRegistry { - pub coin: Coin, - pub proof: Proof, - pub info: XchandlesRegistryInfo, - - pub pending_spend: XchandlesPendingSpendInfo, -} - -impl XchandlesRegistry { - pub fn new(coin: Coin, proof: Proof, info: XchandlesRegistryInfo) -> Self { - Self { - coin, - proof, - info, - pending_spend: XchandlesPendingSpendInfo::new(info.state), - } - } -} - -impl Registry for XchandlesRegistry { - type State = XchandlesRegistryState; - type Constants = XchandlesConstants; -} - -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( - ctx: &mut SpendContext, - parent_spend: &CoinSpend, - constants: XchandlesConstants, - ) -> Result, DriverError> - where - Self: Sized, - { - let Some(parent_registry) = Self::from_spend(ctx, parent_spend, constants)? else { - return Ok(None); - }; - - let proof = Proof::Lineage(parent_registry.child_lineage_proof()); - - 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_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( - ctx: &mut SpendContext, - launcher_coin: Coin, - launcher_solution: NodePtr, - ) -> Result; 2], Bytes32, u64)>, DriverError> - where - Self: Sized, - { - let Ok(launcher_solution) = ctx.extract::>(launcher_solution) else { - return Ok(None); - }; - - let launcher_id = launcher_coin.coin_id(); - let ( - initial_registration_asset_id, - (initial_base_price, (initial_registration_period, (initial_state, (constants, ())))), - ) = launcher_solution.key_value_list; - - let info = XchandlesRegistryInfo::new( - initial_state, - constants.with_launcher_id(launcher_coin.coin_id()), - ); - if info.state - != XchandlesRegistryState::from( - initial_registration_asset_id.tree_hash().into(), - initial_base_price, - initial_registration_period, - ) - { - return Ok(None); - } - - let registry_inner_puzzle_hash: Bytes32 = info.inner_puzzle_hash().into(); - let eve_singleton_inner_puzzle = eve_singleton_inner_puzzle( - ctx, - launcher_id, - XchandlesSlotValue::initial_left_end(), - XchandlesSlotValue::initial_right_end(), - NodePtr::NIL, - registry_inner_puzzle_hash, - )?; - let eve_singleton_inner_puzzle_hash = ctx.tree_hash(eve_singleton_inner_puzzle); - - let eve_coin = Coin::new( - launcher_id, - SingletonArgs::curry_tree_hash(launcher_id, eve_singleton_inner_puzzle_hash).into(), - 1, - ); - let registry_coin = Coin::new( - eve_coin.coin_id(), - SingletonArgs::curry_tree_hash(launcher_id, registry_inner_puzzle_hash.into()).into(), - 1, - ); - - if eve_coin.puzzle_hash != launcher_solution.singleton_puzzle_hash { - return Ok(None); - } - - // proof for registry, which is created by eve singleton - let proof = Proof::Lineage(LineageProof { - parent_parent_coin_info: eve_coin.parent_coin_info, - parent_inner_puzzle_hash: eve_singleton_inner_puzzle_hash.into(), - parent_amount: eve_coin.amount, - }); - - let slot_proof = SlotProof { - parent_parent_info: eve_coin.parent_coin_info, - parent_inner_puzzle_hash: eve_singleton_inner_puzzle_hash.into(), - }; - let slots = [ - Slot::new( - slot_proof, - SlotInfo::from_value(launcher_id, 0, XchandlesSlotValue::initial_left_end()), - ), - Slot::new( - slot_proof, - SlotInfo::from_value(launcher_id, 0, XchandlesSlotValue::initial_right_end()), - ), - ]; - - Ok(Some(( - XchandlesRegistry { - coin: registry_coin, - proof, - info, - pending_spend: XchandlesPendingSpendInfo::new(info.state), - }, - slots, - initial_registration_asset_id, - initial_base_price, - ))) - } -} - -impl XchandlesRegistry { - 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_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 { - lineage_proof: self.proof, - amount: self.coin.amount, - inner_solution: ActionLayerSolution { - proofs: layers - .inner_puzzle - .get_proofs( - &XchandlesRegistryInfo::action_puzzle_hashes(&self.info.constants), - &action_puzzle_hashes, - ) - .ok_or(DriverError::Custom( - "Couldn't build proofs for one or more actions".to_string(), - ))?, - action_spends: self.pending_spend.actions, - finalizer_solution: NodePtr::NIL, - }, - }, - )?; - - let my_spend = Spend::new(puzzle, solution); - ctx.spend(self.coin, my_spend)?; - - Ok((child, self.pending_spend.signature)) - } - - pub fn new_action(&self) -> A - where - A: Action, - { - A::from_constants(&self.info.constants) - } - - pub fn created_slot_value_to_slot( - &self, - 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::new( - proof, - SlotInfo::from_value(self.info.constants.launcher_id, 0, slot_value), - ) - } - - pub fn actual_neigbors( - &self, - new_handle_hash: Bytes32, - on_chain_left_slot: Slot, - on_chain_right_slot: Slot, - ) -> (Slot, Slot) { - let mut left = on_chain_left_slot; - let mut right = on_chain_right_slot; - - 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_value_to_slot(slot_value.clone()); - } - - if slot_value.handle_hash > new_handle_hash - && slot_value.handle_hash <= right.info.value.handle_hash - { - 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(()) - } -} diff --git a/src/primitives/xchandles_registry_info.rs b/src/primitives/xchandles_registry_info.rs deleted file mode 100644 index a05c4516..00000000 --- a/src/primitives/xchandles_registry_info.rs +++ /dev/null @@ -1,189 +0,0 @@ -use chia::{ - clvm_utils::{ToTreeHash, TreeHash}, - protocol::Bytes32, - puzzles::singleton::SingletonArgs, -}; -use chia_wallet_sdk::{ - driver::{DriverError, Layer, Puzzle, SingletonLayer}, - types::MerkleTree, -}; -use clvm_traits::{FromClvm, ToClvm}; -use clvmr::Allocator; - -use crate::{ - Action, ActionLayer, ActionLayerArgs, DefaultFinalizer2ndCurryArgs, DelegatedStateAction, - Finalizer, XchandlesExpireAction, XchandlesExponentialPremiumRenewPuzzleArgs, - XchandlesExtendAction, XchandlesFactorPricingPuzzleArgs, XchandlesOracleAction, - XchandlesRefundAction, XchandlesRegisterAction, XchandlesUpdateAction, -}; - -use super::{DefaultCatMakerArgs, XchandlesRegistry}; - -pub type XchandlesRegistryLayers = SingletonLayer>; - -#[must_use] -#[derive(Debug, Clone, PartialEq, Eq, ToClvm, FromClvm, Copy)] -#[clvm(list)] -pub struct XchandlesRegistryState { - pub cat_maker_puzzle_hash: Bytes32, - pub pricing_puzzle_hash: Bytes32, - #[clvm(rest)] - pub expired_handle_pricing_puzzle_hash: Bytes32, -} - -impl XchandlesRegistryState { - pub fn from( - payment_cat_tail_hash_hash: Bytes32, - base_price: u64, - registration_period: u64, - ) -> Self { - Self { - cat_maker_puzzle_hash: DefaultCatMakerArgs::curry_tree_hash(payment_cat_tail_hash_hash) - .into(), - pricing_puzzle_hash: XchandlesFactorPricingPuzzleArgs::curry_tree_hash( - base_price, - registration_period, - ) - .into(), - expired_handle_pricing_puzzle_hash: - XchandlesExponentialPremiumRenewPuzzleArgs::curry_tree_hash( - base_price, - registration_period, - 1000, - ) - .into(), - } - } -} - -#[must_use] -#[derive(Debug, Clone, PartialEq, Eq, Copy, ToClvm, FromClvm)] -#[clvm(list)] -pub struct XchandlesConstants { - pub launcher_id: Bytes32, - pub precommit_payout_puzzle_hash: Bytes32, - pub relative_block_height: u32, - pub price_singleton_launcher_id: Bytes32, -} - -impl XchandlesConstants { - pub fn new( - launcher_id: Bytes32, - precommit_payout_puzzle_hash: Bytes32, - relative_block_height: u32, - price_singleton_launcher_id: Bytes32, - ) -> Self { - Self { - launcher_id, - precommit_payout_puzzle_hash, - relative_block_height, - price_singleton_launcher_id, - } - } - - pub fn with_price_singleton(mut self, price_singleton_launcher_id: Bytes32) -> Self { - self.price_singleton_launcher_id = price_singleton_launcher_id; - self - } - - pub fn with_launcher_id(mut self, launcher_id: Bytes32) -> Self { - self.launcher_id = launcher_id; - self - } -} - -#[must_use] -#[derive(Debug, Clone, PartialEq, Eq, Copy)] -pub struct XchandlesRegistryInfo { - pub state: XchandlesRegistryState, - - pub constants: XchandlesConstants, -} - -impl XchandlesRegistryInfo { - pub fn new(state: XchandlesRegistryState, constants: XchandlesConstants) -> Self { - Self { state, constants } - } - - pub fn with_state(mut self, state: XchandlesRegistryState) -> Self { - self.state = state; - self - } - - pub fn action_puzzle_hashes(constants: &XchandlesConstants) -> [Bytes32; 7] { - [ - XchandlesExpireAction::from_constants(constants) - .tree_hash() - .into(), - XchandlesExtendAction::from_constants(constants) - .tree_hash() - .into(), - XchandlesOracleAction::from_constants(constants) - .tree_hash() - .into(), - XchandlesRegisterAction::from_constants(constants) - .tree_hash() - .into(), - XchandlesUpdateAction::from_constants(constants) - .tree_hash() - .into(), - XchandlesRefundAction::from_constants(constants) - .tree_hash() - .into(), - >::from_constants(constants) - .tree_hash() - .into(), - ] - } - - #[must_use] - pub fn into_layers(self) -> XchandlesRegistryLayers { - SingletonLayer::new( - self.constants.launcher_id, - ActionLayer::from_action_puzzle_hashes( - &Self::action_puzzle_hashes(&self.constants), - self.state, - Finalizer::Default { - hint: self.constants.launcher_id, - }, - ), - ) - } - - pub fn parse( - allocator: &mut Allocator, - puzzle: Puzzle, - constants: XchandlesConstants, - ) -> Result, DriverError> { - let Some(layers) = XchandlesRegistryLayers::parse_puzzle(allocator, puzzle)? else { - return Ok(None); - }; - - let action_puzzle_hashes = Self::action_puzzle_hashes(&constants); - let merkle_root = MerkleTree::new(&action_puzzle_hashes).root(); - if layers.inner_puzzle.merkle_root != merkle_root { - return Ok(None); - } - - Ok(Some(Self::from_layers(layers, constants))) - } - - pub fn from_layers(layers: XchandlesRegistryLayers, constants: XchandlesConstants) -> Self { - Self { - state: layers.inner_puzzle.state, - constants, - } - } - - pub fn puzzle_hash(&self) -> TreeHash { - SingletonArgs::curry_tree_hash(self.constants.launcher_id, self.inner_puzzle_hash()) - } - - pub fn inner_puzzle_hash(&self) -> TreeHash { - ActionLayerArgs::curry_tree_hash( - DefaultFinalizer2ndCurryArgs::curry_tree_hash(self.constants.launcher_id), - MerkleTree::new(&Self::action_puzzle_hashes(&self.constants)).root(), - self.state.tree_hash(), - ) - } -}