diff --git a/Makefile b/Makefile index 039ad748..ab45b6f4 100644 --- a/Makefile +++ b/Makefile @@ -173,10 +173,10 @@ compile-mining-rewards-contract: @cd $(MINING_REWARDS_CONTRACT_PATH) && $(DARGO) compile --contract-name=PsyPOWMiningRewardsClaimContractRef --method-names start_session end_session claim_guta_rewards_1 claim_guta_rewards_2 claim_guta_rewards_5 compile-usdt-token-contract: - @cd $(USDT_TOKEN_CONTRACT_PATH) && $(DARGO) compile --contract-name=USDTTokenContractRef --method-names withdraw claim_deposit simple_mint simple_transfer simple_claim batch_simple_transfer_2 batch_simple_transfer_5 simple_burn simple_claim_pow_rewards private_transfer private_claim + @cd $(USDT_TOKEN_CONTRACT_PATH) && $(DARGO) compile --contract-name=USDTTokenContractRef --method-names withdraw claim_deposit simple_mint simple_transfer simple_claim batch_simple_transfer_2 batch_simple_transfer_5 simple_burn private_transfer private_claim compile-usdt-token-abi: - @cd $(USDT_TOKEN_CONTRACT_PATH) && $(DARGO) generate-abi -c USDTTokenContractRef --abi-name usdt_token --method-names withdraw claim_deposit simple_mint simple_transfer simple_claim batch_simple_transfer_2 batch_simple_transfer_5 simple_burn simple_claim_pow_rewards private_transfer private_claim + @cd $(USDT_TOKEN_CONTRACT_PATH) && $(DARGO) generate-abi -c USDTTokenContractRef --abi-name usdt_token --method-names withdraw claim_deposit simple_mint simple_transfer simple_claim batch_simple_transfer_2 batch_simple_transfer_5 simple_burn private_transfer private_claim compile-token-abi: @cd $(TOKEN_CONTRACT_PATH) && $(DARGO) generate-abi -c PsyTokenContractRef --abi-name token --method-names withdraw claim_deposit simple_mint simple_transfer simple_claim batch_simple_transfer_2 batch_simple_transfer_5 simple_burn simple_claim_pow_rewards private_transfer private_claim @@ -237,7 +237,7 @@ gen-deploy-json: build \ @# Regenerate ABI files to a separate dir (avoids overwriting compiled .json) @mkdir -p $(ABI_OUTPUT_DIR) @cd $(TOKEN_CONTRACT_PATH) && $(DARGO) generate-abi -c PsyTokenContractRef --abi-name token --output-dir $(ABI_OUTPUT_DIR) --method-names withdraw claim_deposit simple_mint simple_transfer simple_claim batch_simple_transfer_2 batch_simple_transfer_5 simple_burn simple_claim_pow_rewards private_transfer private_claim - @cd $(USDT_TOKEN_CONTRACT_PATH) && $(DARGO) generate-abi -c USDTTokenContractRef --abi-name usdt_token --output-dir $(ABI_OUTPUT_DIR) --method-names withdraw claim_deposit simple_mint simple_transfer simple_claim batch_simple_transfer_2 batch_simple_transfer_5 simple_burn simple_claim_pow_rewards private_transfer private_claim + @cd $(USDT_TOKEN_CONTRACT_PATH) && $(DARGO) generate-abi -c USDTTokenContractRef --abi-name usdt_token --output-dir $(ABI_OUTPUT_DIR) --method-names withdraw claim_deposit simple_mint simple_transfer simple_claim batch_simple_transfer_2 batch_simple_transfer_5 simple_burn private_transfer private_claim @cd $(MINING_REWARDS_CONTRACT_PATH) && $(DARGO) generate-abi -c PsyPOWMiningRewardsClaimContractRef --abi-name mining_rewards --output-dir $(ABI_OUTPUT_DIR) --method-names start_session end_session claim_guta_rewards_1 claim_guta_rewards_2 claim_guta_rewards_5 @cd $(DEPOSIT_TREE_CONTRACT_PATH) && $(DARGO) generate-abi -c PsyDepositTreeContractRef --abi-name deposit_tree --output-dir $(ABI_OUTPUT_DIR) --method-names get_root get_chain_root is_known_root_hash is_known_root set_chain_root append_leaf append_deposit batch_append_deposits_2 batch_append_deposits_5 @cd $(WITHDRAWAL_TREE_CONTRACT_PATH) && $(DARGO) generate-abi -c PsyWithdrawalTreeContractRef --abi-name withdrawal_tree --output-dir $(ABI_OUTPUT_DIR) --method-names get_root get_chain_root append_leaf append_withdrawal batch_append_withdrawals_2 batch_append_withdrawals_5 diff --git a/psy-precompiles/deposit_tree/src/main.psy b/psy-precompiles/deposit_tree/src/main.psy index 5c9cb9b9..d28322d2 100644 --- a/psy-precompiles/deposit_tree/src/main.psy +++ b/psy-precompiles/deposit_tree/src/main.psy @@ -116,27 +116,13 @@ impl PsyDepositTreeContractRef { fn get_chain_count_value(chain_index: Felt) -> Felt { assert(chain_index < 256, "chain index out of range"); let c = PsyDepositTreeContractRef::new(ContractMetadata::current()); - let mut out: Felt = 0; - for i in 0u32..256u32 { - let idx = i as Felt; - if idx == chain_index { - out = c.chain_counts[idx].get(); - }; - } - out + c.chain_counts[chain_index].get() } fn get_chain_root_value(chain_index: Felt) -> [u32; 8] { assert(chain_index < 256, "chain index out of range"); let c = PsyDepositTreeContractRef::new(ContractMetadata::current()); - let mut out: [u32; 8] = [0u32, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32]; - for i in 0u32..256u32 { - let idx = i as Felt; - if idx == chain_index { - out = c.chain_roots[idx].get(); - }; - } - out + c.chain_roots[chain_index].get() } fn get_global_count_value() -> Felt { diff --git a/psy-precompiles/mining_rewards/src/main.psy b/psy-precompiles/mining_rewards/src/main.psy index 4aecd433..dc5f33bf 100644 --- a/psy-precompiles/mining_rewards/src/main.psy +++ b/psy-precompiles/mining_rewards/src/main.psy @@ -40,9 +40,9 @@ impl MiningRewardMerkleProof { let mut nullifier_level_start_index_multiplier = 1; let index = self.index; - let max_index = 4294967296; + let max_index = 1 << proof_height; - assert(index < max_index, "index out of range"); + assert(index < max_index, "index exceeds proof height"); // Step 1: Compute leaf hash from three components // hash(hash(leaf_left, leaf_right), leaf_tag) diff --git a/psy-precompiles/precompiles.json b/psy-precompiles/precompiles.json index e541312e..0610fcdf 100644 --- a/psy-precompiles/precompiles.json +++ b/psy-precompiles/precompiles.json @@ -73,7 +73,6 @@ "batch_simple_transfer_2", "batch_simple_transfer_5", "simple_claim", - "simple_claim_pow_rewards", "private_transfer", "private_claim" ] diff --git a/psy-precompiles/token/src/main.psy b/psy-precompiles/token/src/main.psy index 74e8bf94..14d7be40 100644 --- a/psy-precompiles/token/src/main.psy +++ b/psy-precompiles/token/src/main.psy @@ -27,6 +27,18 @@ pub struct PrivateClaimEvent { pub amount: Felt, } +#[derive(Event)] +pub struct PrivateTransferEvent { + // Do not emit receiver, value, or note_commitment: they contain private or + // linkable transfer data. + // pub receiver: Hash, + // pub value: Felt, + // pub note_commitment: Hash, + pub index: Felt, + pub commitment: Hash, + pub new_root: Hash, +} + #[derive(Event)] pub struct DepositClaimEvent { pub shield_address: Hash, @@ -183,6 +195,10 @@ impl PsyTokenContractRef { x[4] == 0u32 && x[5] == 0u32, "amount exceeds uint64 range" ); + assert( + x[6] < 4294967295u32 || x[7] == 0u32, + "amount exceeds Felt range" + ); (x[6] as Felt) * Self::u32_shift_factor() + (x[7] as Felt) } @@ -488,8 +504,14 @@ impl PsyTokenContractRef { c.last_claimed_pow_rewards_checkpoint_id.get() < checkpoint_id, "must haven't already claimed during this ups"); + let cumulative_rewards = pow_rewards_persistent_state.claimed_rewards; + let previously_settled_rewards = c.claimed_rewards.get(); + assert(cumulative_rewards >= previously_settled_rewards, "pow rewards total cannot decrease"); + let newly_settled_rewards = cumulative_rewards - previously_settled_rewards; + c.last_claimed_pow_rewards_checkpoint_id = checkpoint_id; - c.balance += pow_rewards_persistent_state.claimed_rewards; + c.claimed_rewards = cumulative_rewards; + c.balance += newly_settled_rewards; } #[contract_method] @@ -510,6 +532,9 @@ impl PsyTokenContractRef { let amount = amounts[i as Felt]; if amount > 0 { + let transfer_event = TransferEvent { to: recipient, amount }; + transfer_event.emit(); + let mut recipient_info = c.other_user_info[recipient].get(); assert(recipient_info.amount_sent + amount > recipient_info.amount_sent, "amount sent overflow"); @@ -541,6 +566,9 @@ impl PsyTokenContractRef { let amount = amounts[i as Felt]; if amount > 0 { + let transfer_event = TransferEvent { to: recipient, amount }; + transfer_event.emit(); + let mut recipient_info = c.other_user_info[recipient].get(); assert(recipient_info.amount_sent + amount > recipient_info.amount_sent, "amount sent overflow"); @@ -587,6 +615,13 @@ impl PsyTokenContractRef { c.note_root = current; c.note_count = idx + 1; + + let transfer_event = PrivateTransferEvent { + index: idx, + commitment, + new_root: current, + }; + transfer_event.emit(); } #[contract_method] diff --git a/psy-precompiles/usdt_token/Dargo.toml b/psy-precompiles/usdt_token/Dargo.toml index 6db8a4f3..cad8c7ab 100644 --- a/psy-precompiles/usdt_token/Dargo.toml +++ b/psy-precompiles/usdt_token/Dargo.toml @@ -4,5 +4,4 @@ type = "bin" authors = [""] [dependencies] -mining_rewards = { path = "../mining_rewards" } deposit_tree = { path = "../deposit_tree" } diff --git a/psy-precompiles/usdt_token/src/main.psy b/psy-precompiles/usdt_token/src/main.psy index 4e2e3636..d976a824 100644 --- a/psy-precompiles/usdt_token/src/main.psy +++ b/psy-precompiles/usdt_token/src/main.psy @@ -1,5 +1,4 @@ use std::prelude::*; -use mining_rewards::PsyPOWMiningRewardsClaimContractRef; use deposit_tree::PsyDepositTreeContractRef; #[derive(Storage)] @@ -27,6 +26,18 @@ pub struct PrivateClaimEvent { pub amount: Felt, } +#[derive(Event)] +pub struct PrivateTransferEvent { + // Do not emit receiver, value, or note_commitment: they contain private or + // linkable transfer data. + // pub receiver: Hash, + // pub value: Felt, + // pub note_commitment: Hash, + pub index: Felt, + pub commitment: Hash, + pub new_root: Hash, +} + #[derive(Event)] pub struct DepositClaimEvent { pub shield_address: Hash, @@ -89,8 +100,9 @@ struct ShieldClaimPublicInputsPreimage { #[derive(Storage)] pub struct USDTTokenContract { pub balance: Felt, - pub last_claimed_pow_rewards_checkpoint_id: Felt, - pub claimed_rewards: Felt, + // Reserved to preserve the deployed storage layout. + pub reserved_1: Felt, + pub reserved_2: Felt, pub other_user_info: [OtherUserInfo; 4294967296], pub note_count: Felt, @@ -183,6 +195,10 @@ impl USDTTokenContractRef { x[4] == 0u32 && x[5] == 0u32, "amount exceeds uint64 range" ); + assert( + x[6] < 4294967295u32 || x[7] == 0u32, + "amount exceeds Felt range" + ); (x[6] as Felt) * Self::u32_shift_factor() + (x[7] as Felt) } @@ -395,6 +411,9 @@ impl USDTTokenContractRef { #[contract_method] pub fn simple_mint(amount: Felt) { + let deployer: Hash = get_contract_deployer(get_contract_id()); + assert(Self::eq_hash(deployer, get_user_public_key_hash()), "only deployer can mint"); + let c = USDTTokenContractRef::new(ContractMetadata::current()); c.balance += amount; } @@ -469,26 +488,6 @@ impl USDTTokenContractRef { claim_event.emit(); } - #[contract_method] - pub fn simple_claim_pow_rewards(checkpoint_id: Felt) { - let c = USDTTokenContractRef::new(ContractMetadata::current()); - let psy_pow_mining_rewards_claim_contract = PsyPOWMiningRewardsClaimContractRef::new(ContractMetadata::new(1, get_user_id())); - let pow_rewards_persistent_state = psy_pow_mining_rewards_claim_contract.persistent_state.get(); - - assert( - pow_rewards_persistent_state.last_claimed_checkpoint_id == checkpoint_id, - "the claims must be from the latest ups"); - assert( - pow_rewards_persistent_state.last_sealed_checkpoint_id == checkpoint_id, - "the checkpoint must be sealed"); - assert( - c.last_claimed_pow_rewards_checkpoint_id.get() < checkpoint_id, - "must haven't already claimed during this ups"); - - c.last_claimed_pow_rewards_checkpoint_id = checkpoint_id; - c.balance += pow_rewards_persistent_state.claimed_rewards; - } - #[contract_method] pub fn batch_simple_transfer_2(recipients: [Felt; 2], amounts: [Felt; 2]) { let c = USDTTokenContractRef::new(ContractMetadata::current()); @@ -507,6 +506,9 @@ impl USDTTokenContractRef { let amount = amounts[i as Felt]; if amount > 0 { + let transfer_event = TransferEvent { to: recipient, amount }; + transfer_event.emit(); + let mut recipient_info = c.other_user_info[recipient].get(); assert(recipient_info.amount_sent + amount > recipient_info.amount_sent, "amount sent overflow"); @@ -538,6 +540,9 @@ impl USDTTokenContractRef { let amount = amounts[i as Felt]; if amount > 0 { + let transfer_event = TransferEvent { to: recipient, amount }; + transfer_event.emit(); + let mut recipient_info = c.other_user_info[recipient].get(); assert(recipient_info.amount_sent + amount > recipient_info.amount_sent, "amount sent overflow"); @@ -584,6 +589,13 @@ impl USDTTokenContractRef { c.note_root = current; c.note_count = idx + 1; + + let transfer_event = PrivateTransferEvent { + index: idx, + commitment, + new_root: current, + }; + transfer_event.emit(); } #[contract_method] diff --git a/psy-precompiles/withdrawal_tree/src/main.psy b/psy-precompiles/withdrawal_tree/src/main.psy index 992e4b9f..742daaa4 100644 --- a/psy-precompiles/withdrawal_tree/src/main.psy +++ b/psy-precompiles/withdrawal_tree/src/main.psy @@ -145,27 +145,13 @@ impl PsyWithdrawalTreeContractRef { fn get_chain_count_value(chain_index: Felt) -> Felt { assert(chain_index < 256, "chain index out of range"); let c = PsyWithdrawalTreeContractRef::new(ContractMetadata::current()); - let mut out: Felt = 0; - for i in 0u32..256u32 { - let idx = i as Felt; - if idx == chain_index { - out = c.chain_counts[idx].get(); - }; - } - out + c.chain_counts[chain_index].get() } fn get_chain_root_value(chain_index: Felt) -> [u32; 8] { assert(chain_index < 256, "chain index out of range"); let c = PsyWithdrawalTreeContractRef::new(ContractMetadata::current()); - let mut out: [u32; 8] = [0u32, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32, 0u32]; - for i in 0u32..256u32 { - let idx = i as Felt; - if idx == chain_index { - out = c.chain_roots[idx].get(); - }; - } - out + c.chain_roots[chain_index].get() } fn get_global_count_value() -> Felt {