11use std:: collections:: HashSet ;
22
3- use chia_protocol:: { Bytes32 , Coin , CoinSpend } ;
3+ use chia_consensus:: opcodes:: {
4+ CREATE_COIN_ANNOUNCEMENT , CREATE_PUZZLE_ANNOUNCEMENT , RECEIVE_MESSAGE , SEND_MESSAGE ,
5+ } ;
6+ use chia_protocol:: { Bytes , Bytes32 , Coin , CoinSpend } ;
47use chia_puzzle_types:: {
58 Memos ,
69 nft:: NftMetadata ,
710 offer:: { NotarizedPayment , SettlementPaymentsSolution } ,
8- singleton:: SingletonArgs ,
911} ;
1012use chia_puzzles:: SETTLEMENT_PAYMENT_HASH ;
1113use chia_sdk_types:: {
12- Condition , MessageFlags , MessageSide , Mod , announcement_id, conditions:: CreateCoin ,
13- puzzles:: SingletonMember , run_puzzle, tree_hash_notarized_payment,
14+ Condition , MessageFlags , MessageSide , Mod , announcement_id,
15+ conditions:: CreateCoin ,
16+ puzzles:: {
17+ AddDelegatedPuzzleWrapper , Force1of2RestrictedVariable , PreventConditionOpcode ,
18+ PreventMultipleCreateCoinsMod , SingletonMember , Timelock ,
19+ } ,
20+ run_puzzle, tree_hash_notarized_payment,
1421} ;
15- use chia_sha2:: Sha256 ;
1622use clvm_traits:: { FromClvm , ToClvm } ;
17- use clvm_utils:: { TreeHash , tree_hash} ;
23+ use clvm_utils:: { ToTreeHash , TreeHash , tree_hash} ;
1824use clvmr:: { Allocator , NodePtr } ;
1925
2026use crate :: { BURN_PUZZLE_HASH , Cat , ClawbackV2 , DriverError , Nft , Puzzle , Spend , mips_puzzle_hash} ;
@@ -31,8 +37,6 @@ pub struct VaultSpendReveal {
3137 /// The delegated puzzle we're signing and its solution.
3238 /// Its output is the non-custody related conditions that the vault spend will output.
3339 pub delegated_spend : Spend ,
34- /// The coin id of the vault coin that is being spent (used for calculating the non-fast forwardable message hash).
35- pub coin_id : Option < Bytes32 > ,
3640}
3741
3842/// The purpose of this is to provide sufficient information to verify what is happening to a vault and its assets
@@ -63,11 +67,8 @@ pub struct VaultTransaction {
6367 pub reserved_fee : u64 ,
6468 /// The p2 puzzle hash that the vault owns (analogous to a decoded XCH or TXCH address).
6569 pub p2_puzzle_hash : Bytes32 ,
66- /// The hash of the delegated puzzle hash and the vault coin id, used for non-fast forwardable spend signing.
67- /// This is only calculated if the vault coin id is provided.
68- pub coin_message_hash : Option < Bytes32 > ,
69- /// The hash of the delegated puzzle hash and the vault puzzle hash, used for fast forwardable spend signing.
70- pub puzzle_message_hash : Bytes32 ,
70+ /// The original delegated puzzle hash that is being signed for.
71+ pub delegated_puzzle_hash : Bytes32 ,
7172}
7273
7374#[ derive( Debug , Clone , PartialEq , Eq ) ]
@@ -444,24 +445,7 @@ impl VaultTransaction {
444445 }
445446 }
446447
447- let delegated_puzzle_hash = tree_hash ( allocator, vault. delegated_spend . puzzle ) ;
448-
449- let coin_message_hash = if let Some ( vault_coin_id) = vault. coin_id {
450- let mut coin_message_hasher = Sha256 :: new ( ) ;
451- coin_message_hasher. update ( delegated_puzzle_hash) ;
452- coin_message_hasher. update ( vault_coin_id) ;
453- Some ( coin_message_hasher. finalize ( ) . into ( ) )
454- } else {
455- None
456- } ;
457-
458- let vault_puzzle_hash =
459- SingletonArgs :: curry_tree_hash ( vault. launcher_id , vault. custody_hash ) ;
460-
461- let mut puzzle_message_hasher = Sha256 :: new ( ) ;
462- puzzle_message_hasher. update ( delegated_puzzle_hash) ;
463- puzzle_message_hasher. update ( vault_puzzle_hash) ;
464- let puzzle_message_hash = puzzle_message_hasher. finalize ( ) . into ( ) ;
448+ let delegated_puzzle_hash = tree_hash ( allocator, vault. delegated_spend . puzzle ) . into ( ) ;
465449
466450 Ok ( Self {
467451 new_custody_hash,
@@ -472,8 +456,7 @@ impl VaultTransaction {
472456 total_fee : total_input. saturating_sub ( total_output) ,
473457 reserved_fee,
474458 p2_puzzle_hash : our_p2_puzzle_hash,
475- coin_message_hash,
476- puzzle_message_hash,
459+ delegated_puzzle_hash,
477460 } )
478461 }
479462}
@@ -767,14 +750,81 @@ fn calculate_transfer_type(
767750 }
768751}
769752
753+ pub fn calculate_vault_puzzle_message (
754+ delegated_puzzle_hash : Bytes32 ,
755+ vault_puzzle_hash : Bytes32 ,
756+ ) -> Bytes {
757+ [
758+ delegated_puzzle_hash. to_bytes ( ) ,
759+ vault_puzzle_hash. to_bytes ( ) ,
760+ ]
761+ . concat ( )
762+ . into ( )
763+ }
764+
765+ pub fn calculate_vault_coin_message (
766+ delegated_puzzle_hash : Bytes32 ,
767+ vault_coin_id : Bytes32 ,
768+ genesis_challenge : Bytes32 ,
769+ ) -> Bytes {
770+ [
771+ delegated_puzzle_hash. to_bytes ( ) ,
772+ vault_coin_id. to_bytes ( ) ,
773+ genesis_challenge. to_bytes ( ) ,
774+ ]
775+ . concat ( )
776+ . into ( )
777+ }
778+
779+ pub fn calculate_vault_start_recovery_message (
780+ delegated_puzzle_hash : Bytes32 ,
781+ left_side_subtree_hash : Bytes32 ,
782+ recovery_timelock : u64 ,
783+ vault_coin_id : Bytes32 ,
784+ genesis_challenge : Bytes32 ,
785+ ) -> Bytes {
786+ let mut delegated_puzzle_hash: TreeHash = delegated_puzzle_hash. into ( ) ;
787+
788+ let restrictions = vec ! [
789+ Force1of2RestrictedVariable :: new(
790+ left_side_subtree_hash,
791+ 0 ,
792+ vec![ Timelock :: new( recovery_timelock) . curry_tree_hash( ) ]
793+ . tree_hash( )
794+ . into( ) ,
795+ ( ) . tree_hash( ) . into( ) ,
796+ )
797+ . curry_tree_hash( ) ,
798+ PreventConditionOpcode :: new( CREATE_COIN_ANNOUNCEMENT ) . curry_tree_hash( ) ,
799+ PreventConditionOpcode :: new( CREATE_PUZZLE_ANNOUNCEMENT ) . curry_tree_hash( ) ,
800+ PreventConditionOpcode :: new( SEND_MESSAGE ) . curry_tree_hash( ) ,
801+ PreventConditionOpcode :: new( RECEIVE_MESSAGE ) . curry_tree_hash( ) ,
802+ PreventMultipleCreateCoinsMod :: mod_hash( ) ,
803+ ] ;
804+
805+ for restriction in restrictions. into_iter ( ) . rev ( ) {
806+ delegated_puzzle_hash =
807+ AddDelegatedPuzzleWrapper :: new ( restriction, delegated_puzzle_hash) . curry_tree_hash ( ) ;
808+ }
809+
810+ [
811+ delegated_puzzle_hash. to_bytes ( ) ,
812+ vault_coin_id. to_bytes ( ) ,
813+ genesis_challenge. to_bytes ( ) ,
814+ ]
815+ . concat ( )
816+ . into ( )
817+ }
818+
770819#[ cfg( test) ]
771820mod tests {
772821 use super :: * ;
773822
774823 use anyhow:: Result ;
824+ use chia_bls:: verify;
775825 use chia_puzzles:: SINGLETON_LAUNCHER_HASH ;
776826 use chia_sdk_test:: Simulator ;
777- use chia_sdk_types:: Conditions ;
827+ use chia_sdk_types:: { Conditions , TESTNET11_CONSTANTS } ;
778828 use rstest:: rstest;
779829
780830 use crate :: { Action , FeeAction , Id , SpendContext , Spends , TestVault } ;
@@ -831,7 +881,6 @@ mod tests {
831881 launcher_id : alice. launcher_id ( ) ,
832882 custody_hash : alice. custody_hash ( ) ,
833883 delegated_spend : result. delegated_spend ,
834- coin_id : None ,
835884 } ;
836885
837886 let tx = VaultTransaction :: parse ( & mut ctx, & reveal, result. coin_spends ) ?;
@@ -897,7 +946,6 @@ mod tests {
897946 launcher_id : bob. launcher_id ( ) ,
898947 custody_hash : bob. custody_hash ( ) ,
899948 delegated_spend : result. delegated_spend ,
900- coin_id : None ,
901949 } ;
902950
903951 let tx = VaultTransaction :: parse ( & mut ctx, & reveal, result. coin_spends ) ?;
@@ -933,7 +981,6 @@ mod tests {
933981 launcher_id : bob. launcher_id ( ) ,
934982 custody_hash : bob. custody_hash ( ) ,
935983 delegated_spend : result. delegated_spend ,
936- coin_id : None ,
937984 } ;
938985
939986 let tx = VaultTransaction :: parse ( & mut ctx, & reveal, result. coin_spends ) ?;
@@ -973,7 +1020,6 @@ mod tests {
9731020 launcher_id : alice. launcher_id ( ) ,
9741021 custody_hash : alice. custody_hash ( ) ,
9751022 delegated_spend : result. delegated_spend ,
976- coin_id : None ,
9771023 } ;
9781024
9791025 let tx = VaultTransaction :: parse ( & mut ctx, & reveal, result. coin_spends ) ?;
@@ -1024,7 +1070,6 @@ mod tests {
10241070 launcher_id : alice. launcher_id ( ) ,
10251071 custody_hash : alice. custody_hash ( ) ,
10261072 delegated_spend : result. delegated_spend ,
1027- coin_id : None ,
10281073 } ;
10291074
10301075 let tx = VaultTransaction :: parse ( & mut ctx, & reveal, result. coin_spends ) ?;
@@ -1090,7 +1135,6 @@ mod tests {
10901135 launcher_id : alice. launcher_id ( ) ,
10911136 custody_hash : alice. custody_hash ( ) ,
10921137 delegated_spend : result. delegated_spend ,
1093- coin_id : None ,
10941138 } ;
10951139
10961140 let tx = VaultTransaction :: parse ( & mut ctx, & reveal, result. coin_spends ) ?;
@@ -1117,7 +1161,6 @@ mod tests {
11171161 launcher_id : alice. launcher_id ( ) ,
11181162 custody_hash : alice. custody_hash ( ) ,
11191163 delegated_spend : result. delegated_spend ,
1120- coin_id : None ,
11211164 } ;
11221165
11231166 let tx = VaultTransaction :: parse ( & mut ctx, & reveal, result. coin_spends ) ?;
@@ -1160,7 +1203,6 @@ mod tests {
11601203 launcher_id : alice. launcher_id ( ) ,
11611204 custody_hash : alice. custody_hash ( ) ,
11621205 delegated_spend : result. delegated_spend ,
1163- coin_id : None ,
11641206 } ;
11651207
11661208 let tx = VaultTransaction :: parse ( & mut ctx, & reveal, result. coin_spends ) ?;
@@ -1178,4 +1220,41 @@ mod tests {
11781220
11791221 Ok ( ( ) )
11801222 }
1223+
1224+ #[ rstest]
1225+ fn test_clear_signing_coin_message ( ) -> Result < ( ) > {
1226+ let mut sim = Simulator :: new ( ) ;
1227+ let mut ctx = SpendContext :: new ( ) ;
1228+
1229+ let alice = TestVault :: mint ( & mut sim, & mut ctx, 1000 ) ?;
1230+ let bob = TestVault :: mint ( & mut sim, & mut ctx, 0 ) ?;
1231+
1232+ let vault = alice. fetch_vault ( & sim) ?;
1233+
1234+ let result = alice. spend (
1235+ & mut sim,
1236+ & mut ctx,
1237+ & [ Action :: send ( Id :: Xch , bob. puzzle_hash ( ) , 1000 , Memos :: None ) ] ,
1238+ ) ?;
1239+
1240+ let reveal = VaultSpendReveal {
1241+ launcher_id : alice. launcher_id ( ) ,
1242+ custody_hash : alice. custody_hash ( ) ,
1243+ delegated_spend : result. delegated_spend ,
1244+ } ;
1245+
1246+ let tx = VaultTransaction :: parse ( & mut ctx, & reveal, result. coin_spends ) ?;
1247+ assert_eq ! ( tx. new_custody_hash, Some ( alice. custody_hash( ) ) ) ;
1248+ assert_eq ! ( tx. payments. len( ) , 1 ) ;
1249+
1250+ let coin_message = calculate_vault_coin_message (
1251+ tx. delegated_puzzle_hash ,
1252+ vault. coin . coin_id ( ) ,
1253+ TESTNET11_CONSTANTS . genesis_challenge ,
1254+ ) ;
1255+
1256+ assert ! ( verify( & result. signature, & alice. public_key, coin_message) ) ;
1257+
1258+ Ok ( ( ) )
1259+ }
11811260}
0 commit comments