From 09ecb76d244048a6f7f3c7e0619177363cf441e4 Mon Sep 17 00:00:00 2001 From: Moody Salem Date: Tue, 24 Oct 2023 09:10:57 -0400 Subject: [PATCH] Use hash implementations for identifiers --- src/airdrop.cairo | 19 ++++++------------- src/call_trait.cairo | 21 ++++++++++++--------- src/governor.cairo | 7 ++++--- src/tests/airdrop_test.cairo | 20 ++++++++++---------- src/tests/call_trait_test.cairo | 28 ++++++++++++++++++++++------ src/timelock.cairo | 10 +++++----- 6 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/airdrop.cairo b/src/airdrop.cairo index a8131a5..e06edf2 100644 --- a/src/airdrop.cairo +++ b/src/airdrop.cairo @@ -1,7 +1,7 @@ use starknet::ContractAddress; use array::{Array}; -#[derive(Copy, Drop, Serde)] +#[derive(Copy, Drop, Serde, Hash)] struct Claim { claimee: ContractAddress, amount: u128, @@ -24,12 +24,12 @@ mod Airdrop { IAirdrop, ContractAddress, Claim, ITransferrableERC20Dispatcher, ITransferrableERC20DispatcherTrait }; + use hash::{LegacyHash}; use array::{ArrayTrait, SpanTrait}; use traits::{Into, TryInto}; - use starknet::ContractAddressIntoFelt252; + use starknet::{ContractAddressIntoFelt252}; - - fn felt252_lt(lhs: @felt252, rhs: @felt252) -> bool { + fn lt, +Into>(lhs: @X, rhs: @X) -> bool { let a: u256 = (*lhs).into(); let b: u256 = (*rhs).into(); return a < b; @@ -40,7 +40,7 @@ mod Airdrop { match proof.pop_front() { Option::Some(proof_element) => { compute_pedersen_root( - if felt252_lt(@current, proof_element) { + if lt(@current, proof_element) { pedersen::pedersen(current, *proof_element) } else { pedersen::pedersen(*proof_element, current) @@ -52,13 +52,6 @@ mod Airdrop { } } - #[generate_trait] - impl ClaimToLeaf of ClaimToLeafTrait { - fn to_leaf(self: @Claim) -> felt252 { - pedersen::pedersen((*self.claimee).into(), (*self.amount).into()) - } - } - #[storage] struct Storage { root: felt252, @@ -86,7 +79,7 @@ mod Airdrop { #[external(v0)] impl AirdropImpl of IAirdrop { fn claim(ref self: ContractState, claim: Claim, proof: Array::) { - let leaf = claim.to_leaf(); + let leaf = LegacyHash::hash(0, claim); assert(!self.claimed.read(leaf), 'ALREADY_CLAIMED'); assert(self.root.read() == compute_pedersen_root(leaf, proof.span()), 'INVALID_PROOF'); diff --git a/src/call_trait.cairo b/src/call_trait.cairo index eebb187..308ae32 100644 --- a/src/call_trait.cairo +++ b/src/call_trait.cairo @@ -3,24 +3,27 @@ use array::{ArrayTrait, SpanTrait}; use traits::{Into}; use hash::{LegacyHash}; use starknet::{SyscallResult, syscalls::call_contract_syscall}; -use starknet::account::Call; +use starknet::account::{Call}; use result::{ResultTrait}; -#[generate_trait] -impl CallTraitImpl of CallTrait { - fn hash(self: @Call) -> felt252 { - let mut data_hash = 0; - let mut data_span = self.calldata.span(); +impl HashCall, +Drop, +Copy> of hash::Hash<@Call, S> { + fn update_state(state: S, value: @Call) -> S { + let mut s = state.update((*value.to).into()).update(*value.selector); + + let mut data_span = value.calldata.span(); loop { match data_span.pop_front() { - Option::Some(word) => { data_hash = pedersen::pedersen(data_hash, *word); }, - Option::None(_) => { break; } + Option::Some(word) => { s = s.update(*word); }, + Option::None => { break; } }; }; - pedersen::pedersen(pedersen::pedersen((*self.to).into(), *self.selector), data_hash) + s } +} +#[generate_trait] +impl CallTraitImpl of CallTrait { fn execute(self: @Call) -> Span { let result = call_contract_syscall(*self.to, *self.selector, self.calldata.span()); diff --git a/src/governor.cairo b/src/governor.cairo index 5d3bdca..065429f 100644 --- a/src/governor.cairo +++ b/src/governor.cairo @@ -86,9 +86,10 @@ mod Governor { ProposalTimestamps }; use starknet::{get_block_timestamp, get_caller_address, contract_address_const}; - use governance::call_trait::{CallTrait}; + use governance::call_trait::{HashCall, CallTrait}; use governance::governance_token::{IGovernanceTokenDispatcherTrait}; use zeroable::{Zeroable}; + use hash::{LegacyHash}; #[storage] struct Storage { @@ -105,7 +106,7 @@ mod Governor { #[external(v0)] impl GovernorImpl of IGovernor { fn propose(ref self: ContractState, call: Call) -> felt252 { - let id = call.hash(); + let id = LegacyHash::hash(0, @call); assert(self.proposals.read(id).proposer.is_zero(), 'ALREADY_PROPOSED'); @@ -213,7 +214,7 @@ mod Governor { } fn execute(ref self: ContractState, call: Call) -> Span { - let id = call.hash(); + let id = LegacyHash::hash(0, @call); let config = self.config.read(); let mut proposal = self.proposals.read(id); diff --git a/src/tests/airdrop_test.cairo b/src/tests/airdrop_test.cairo index e972334..ca5c8b1 100644 --- a/src/tests/airdrop_test.cairo +++ b/src/tests/airdrop_test.cairo @@ -1,11 +1,11 @@ -use governance::airdrop::Airdrop::ClaimToLeafTrait; -use governance::governance_token::IGovernanceTokenDispatcherTrait; +use governance::governance_token::{IGovernanceTokenDispatcherTrait}; use array::{ArrayTrait}; use debug::PrintTrait; use governance::airdrop::{ IAirdropDispatcher, IAirdropDispatcherTrait, Airdrop, Airdrop::compute_pedersen_root, Claim, - Airdrop::ClaimToLeaf, Airdrop::felt252_lt + Airdrop::lt }; +use hash::{LegacyHash}; use governance::governance_token::{IERC20Dispatcher, IERC20DispatcherTrait}; use starknet::{ get_contract_address, deploy_syscall, ClassHash, contract_address_const, ContractAddress @@ -97,7 +97,7 @@ fn test_claim_single_recipient() { let claim = Claim { claimee: contract_address_const::<2345>(), amount: 6789, }; - let leaf = claim.to_leaf(); + let leaf = LegacyHash::hash(0, claim); let airdrop = deploy(token.contract_address, leaf); @@ -116,7 +116,7 @@ fn test_double_claim() { let claim = Claim { claimee: contract_address_const::<2345>(), amount: 6789, }; - let leaf = claim.to_leaf(); + let leaf = LegacyHash::hash(0, claim); let airdrop = deploy(token.contract_address, leaf); @@ -136,7 +136,7 @@ fn test_invalid_proof_single_entry() { let claim = Claim { claimee: contract_address_const::<2345>(), amount: 6789, }; - let leaf = claim.to_leaf(); + let leaf = LegacyHash::hash(0, claim); let airdrop = deploy(token.contract_address, leaf); @@ -155,7 +155,7 @@ fn test_invalid_proof_fake_entry() { let claim = Claim { claimee: contract_address_const::<2345>(), amount: 6789, }; - let leaf = claim.to_leaf(); + let leaf = LegacyHash::hash(0, claim); let airdrop = deploy(token.contract_address, leaf); @@ -174,10 +174,10 @@ fn test_claim_two_claims() { let claim_a = Claim { claimee: contract_address_const::<2345>(), amount: 6789, }; let claim_b = Claim { claimee: contract_address_const::<3456>(), amount: 789, }; - let leaf_a = claim_a.to_leaf(); - let leaf_b = claim_b.to_leaf(); + let leaf_a = LegacyHash::hash(0, claim_a); + let leaf_b = LegacyHash::hash(0, claim_b); - let root = if felt252_lt(@leaf_a, @leaf_b) { + let root = if lt(@leaf_a, @leaf_b) { pedersen::pedersen(leaf_a, leaf_b) } else { pedersen::pedersen(leaf_b, leaf_a) diff --git a/src/tests/call_trait_test.cairo b/src/tests/call_trait_test.cairo index 2a7c177..b39f644 100644 --- a/src/tests/call_trait_test.cairo +++ b/src/tests/call_trait_test.cairo @@ -1,16 +1,20 @@ use debug::PrintTrait; -use governance::call_trait::{CallTrait}; +use governance::call_trait::{CallTrait, HashCall}; use starknet::{contract_address_const, account::{Call}}; use array::{Array, ArrayTrait}; use governance::tests::governance_token_test::{deploy as deploy_token}; use serde::{Serde}; +use hash::{LegacyHash}; #[test] #[available_gas(300000000)] fn test_hash_empty() { let call = Call { to: contract_address_const::<0>(), selector: 0, calldata: ArrayTrait::new() }; assert( - call.hash() == 0x6bf1b215edde951b1b50c19e77f7b362d23c6cb4232ae8b95bc112ff94d3956, 'hash' + LegacyHash::hash( + 0, @call + ) == 0x6bf1b215edde951b1b50c19e77f7b362d23c6cb4232ae8b95bc112ff94d3956, + 'hash' ); } @@ -19,7 +23,10 @@ fn test_hash_empty() { fn test_hash_address_one() { let call = Call { to: contract_address_const::<1>(), selector: 0, calldata: ArrayTrait::new() }; assert( - call.hash() == 0x40d1577057b0ad691b66e6d129844046c0f329d8368fbf85a7ef4ff4beffc4c, 'hash' + LegacyHash::hash( + 0, @call + ) == 0x5f6208726bc717f95f23a8e3632dd5a30f4b61d11db5ea4f4fab24bf931a053, + 'hash' ); } @@ -28,7 +35,10 @@ fn test_hash_address_one() { fn test_hash_address_entry_point_one() { let call = Call { to: contract_address_const::<0>(), selector: 1, calldata: ArrayTrait::new() }; assert( - call.hash() == 0x5f6208726bc717f95f23a8e3632dd5a30f4b61d11db5ea4f4fab24bf931a053, 'hash' + LegacyHash::hash( + 0, @call + ) == 0x137c95c76862129847d0f5e3618c7a4c3822ee344f4aa80bcb897cb97d3e16, + 'hash' ); } @@ -40,7 +50,10 @@ fn test_hash_address_data_one() { let call = Call { to: contract_address_const::<0>(), selector: 0, calldata: calldata }; assert( - call.hash() == 0x5ad843e478f13c80cd84180f621a6abacca4d9410e6dc5c8b3c1dbf709ff293, 'hash' + LegacyHash::hash( + 0, @call + ) == 0x200a54d7737c13f1013835f88c566515921c2b9c7c7a50cc44ff6f176cf06b2, + 'hash' ); } @@ -53,7 +66,10 @@ fn test_hash_address_data_one_two() { let call = Call { to: contract_address_const::<0>(), selector: 0, calldata: calldata }; assert( - call.hash() == 0x34552b59a4ecaac8c01b63dfb0ee31f2e49fb784dc90f58c7475fbcdaf3330b, 'hash' + LegacyHash::hash( + 0, @call + ) == 0x6f615c05fa309e4041f96f83d47a23acec3d725b47f8c1005f388aa3d26c187, + 'hash' ); } diff --git a/src/timelock.cairo b/src/timelock.cairo index 1c25ad9..25bef0a 100644 --- a/src/timelock.cairo +++ b/src/timelock.cairo @@ -31,8 +31,8 @@ trait ITimelock { #[starknet::contract] mod Timelock { use super::{ITimelock, ContractAddress, Call}; - use governance::call_trait::{CallTrait}; - use hash::LegacyHash; + use governance::call_trait::{CallTrait, HashCall}; + use hash::{LegacyHash}; use array::{ArrayTrait, SpanTrait}; use starknet::{ get_caller_address, get_contract_address, SyscallResult, syscalls::call_contract_syscall, @@ -67,8 +67,8 @@ mod Timelock { let mut state = 0; loop { match calls.pop_front() { - Option::Some(call) => { state = pedersen::pedersen(state, call.hash()); }, - Option::None(_) => { break state; } + Option::Some(call) => { state = LegacyHash::hash(state, call) }, + Option::None => { break state; } }; } } @@ -123,7 +123,7 @@ mod Timelock { loop { match calls.pop_front() { Option::Some(call) => { results.append(call.execute()); }, - Option::None(_) => { break; } + Option::None => { break; } }; };