Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Upgrade and add upgrade tests #36

Merged
merged 29 commits into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f32091d
upgrade and gift_status
Leonard-Pat Jun 20, 2024
739617f
remove upgrade fn
Leonard-Pat Jun 20, 2024
7d66afa
Merge branch 'develop' into test/missing-tests
Leonard-Pat Jun 21, 2024
33eec92
fix time
Leonard-Pat Jun 20, 2024
934c810
new upgrade changes
Leonard-Pat Jun 21, 2024
cf2b021
more upgrade tests - remove status
Leonard-Pat Jun 21, 2024
d6d2900
upgrade tessts
Leonard-Pat Jun 21, 2024
99b7352
update fixtures
Leonard-Pat Jun 21, 2024
2717336
update comment
Leonard-Pat Jun 21, 2024
9bba7f4
batman
gaetbout Jun 22, 2024
960cbed
revert expecteation file
gaetbout Jun 22, 2024
8b8ee60
format
gaetbout Jun 22, 2024
a1e399c
Merge pull request #38 from argentlabs/small-fixes
Leonard-Pat Jun 23, 2024
eaaec76
fix all tests
Leonard-Pat Jun 23, 2024
3d1623e
remove ds store
Leonard-Pat Jun 24, 2024
b5a1ce8
gitignore
Leonard-Pat Jun 24, 2024
72e9acd
Update src/contracts/timelock_upgrade.cairo
Leonard-Pat Jun 24, 2024
a27dbc4
pr comments
Leonard-Pat Jun 24, 2024
8ab92bc
update tests
Leonard-Pat Jun 24, 2024
8de4399
Merge branch 'develop' into test/missing-tests
sgc-code Jun 25, 2024
8ce144e
fix upgrade tests
Leonard-Pat Jun 25, 2024
72005f5
remove only
Leonard-Pat Jun 25, 2024
93712f0
Merge branch 'develop' into test/missing-tests
Leonard-Pat Jun 25, 2024
3acaa3a
emtpy line
Leonard-Pat Jun 25, 2024
56fb502
Update tests-integration/upgrade.test.ts
Leonard-Pat Jun 25, 2024
ea5ae6c
calc days
Leonard-Pat Jun 25, 2024
fcd8750
ignore
Leonard-Pat Jun 25, 2024
14b457a
Update src/contracts/timelock_upgrade.cairo
Leonard-Pat Jun 25, 2024
ca1b08d
describe blocks
Leonard-Pat Jun 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,5 @@ target
.snfoundry_cache/

.env
dist
dist
.DS_STORE
2 changes: 1 addition & 1 deletion lib/claim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ export async function signExternalClaim(signParams: {
export async function claimExternal(args: {
claim: Claim;
receiver: string;
dustReceiver?: string;
claimPrivateKey: string;
dustReceiver?: string;
sgc-code marked this conversation as resolved.
Show resolved Hide resolved
overrides?: { claimAccountAddress?: string; factoryAddress?: string; account?: Account };
details?: UniversalDetails;
}): Promise<TransactionReceipt> {
Expand Down
12 changes: 6 additions & 6 deletions lib/protocol.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Contract, byteArray, uint256 } from "starknet";
import { deployer, manager } from ".";

const cache: Record<string, Contract> = {};
export const protocolCache: Record<string, Contract> = {};

export async function deployMockERC20(): Promise<Contract> {
if (cache["MockERC20"]) {
return cache["MockERC20"];
if (protocolCache["MockERC20"]) {
return protocolCache["MockERC20"];
}
const mockERC20 = await manager.deployContract("MockERC20", {
unique: true,
Expand All @@ -17,7 +17,7 @@ export async function deployMockERC20(): Promise<Contract> {
deployer.address,
],
});
cache["MockERC20"] = mockERC20;
protocolCache["MockERC20"] = mockERC20;
return mockERC20;
}

Expand All @@ -26,14 +26,14 @@ export async function setupGiftProtocol(): Promise<{
claimAccountClassHash: string;
}> {
const claimAccountClassHash = await manager.declareLocalContract("ClaimAccount");
const cachedFactory = cache["GiftFactory"];
const cachedFactory = protocolCache["GiftFactory"];
if (cachedFactory) {
return { factory: cachedFactory, claimAccountClassHash };
}
const factory = await manager.deployContract("GiftFactory", {
unique: true,
constructorCalldata: [claimAccountClassHash, deployer.address],
});
cache["GiftFactory"] = factory;
protocolCache["GiftFactory"] = factory;
return { factory, claimAccountClassHash };
}
26 changes: 2 additions & 24 deletions src/contracts/gift_factory.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ mod GiftFactory {
use starknet_gifting::contracts::claim_hash::{ClaimExternal, IOffChainMessageHashRev1};
use starknet_gifting::contracts::interface::{
IGiftAccountDispatcherTrait, IGiftFactory, ClaimData, AccountConstructorArguments, IGiftAccountDispatcher,
OutsideExecution, GiftStatus, StarknetSignature
OutsideExecution, StarknetSignature
};
use starknet_gifting::contracts::timelock_upgrade::{ITimelockUpgradeCallback, TimelockUpgradeComponent};
use starknet_gifting::contracts::utils::{
Expand Down Expand Up @@ -248,28 +248,6 @@ mod GiftFactory {
self.claim_class_hash.read()
}

fn get_gift_status(self: @ContractState, claim: ClaimData) -> GiftStatus {
let claim_address = self.check_claim_and_get_account_address(claim);
let gift_balance = IERC20Dispatcher { contract_address: claim.gift_token }.balance_of(claim_address);
if gift_balance < claim.gift_amount {
return GiftStatus::ClaimedOrCancelled;
}
if (claim.gift_token == claim.fee_token) {
if gift_balance < claim.gift_amount + claim.fee_amount.into() {
return GiftStatus::ReadyExternalOnly;
} else {
return GiftStatus::Ready;
}
} else {
let fee_balance = IERC20Dispatcher { contract_address: claim.fee_token }.balance_of(claim_address);
if fee_balance < claim.fee_amount.into() {
return GiftStatus::ReadyExternalOnly;
} else {
return GiftStatus::Ready;
}
}
}

fn get_claim_address(
self: @ContractState,
class_hash: ClassHash,
Expand All @@ -295,7 +273,7 @@ mod GiftFactory {
}
}


#[abi(embed_v0)]
impl TimelockUpgradeCallbackImpl of ITimelockUpgradeCallback<ContractState> {
fn perform_upgrade(ref self: ContractState, new_implementation: ClassHash, data: Span<felt252>) {
// This should do some sanity checks
Expand Down
13 changes: 0 additions & 13 deletions src/contracts/interface.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,6 @@ pub trait IGiftFactory<TContractState> {
fee_amount: u128,
claim_pubkey: felt252
) -> ContractAddress;

/// @notice Get the status of a claim
/// @param claim The claim data
fn get_gift_status(self: @TContractState, claim: ClaimData) -> GiftStatus;
}


Expand Down Expand Up @@ -184,12 +180,3 @@ pub struct AccountConstructorArguments {
pub fee_amount: u128,
pub claim_pubkey: felt252
}

/// @notice Enum representing the status of a gift
/// @dev ReadyExternalOnly should only happen if there is no fee_amount or if the account reverted during claim_internal
#[derive(Serde, Drop, Copy)]
pub enum GiftStatus {
ClaimedOrCancelled,
Ready,
ReadyExternalOnly
}
38 changes: 28 additions & 10 deletions src/contracts/timelock_upgrade.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ pub trait ITimelockUpgrade<TContractState> {
/// @dev After the 7-day waiting period, the upgrade can be performed within a 7-day window
/// @dev If there is an ongoing upgrade, the previous proposition will be overwritten
/// @param new_implementation The class hash of the new implementation
fn propose_upgrade(ref self: TContractState, new_implementation: ClassHash);
/// @param calldata The calldata to be used for the upgrade
fn propose_upgrade(ref self: TContractState, new_implementation: ClassHash, calldata: Array<felt252>);

/// @notice Cancel the upgrade proposition
/// @dev Will fail if there is no ongoing upgrade
Expand All @@ -23,6 +24,9 @@ pub trait ITimelockUpgrade<TContractState> {

/// @notice Gets the timestamp when the upgrade is ready to be performed, 0 if no upgrade ongoing
fn get_upgrade_ready_at(self: @TContractState) -> u64;

/// @notice Gets the hash of the calldata used for the upgrade, 0 if no upgrade ongoing
fn get_calldata_hash(self: @TContractState) -> felt252;
}

#[starknet::interface]
Expand All @@ -37,6 +41,7 @@ pub trait ITimelockUpgradeCallback<TContractState> {
#[starknet::component]
pub mod TimelockUpgradeComponent {
use core::num::traits::Zero;
use core::poseidon::poseidon_hash_span;
use openzeppelin::access::ownable::{OwnableComponent, OwnableComponent::InternalTrait};
use starknet::{get_block_timestamp, ClassHash};
use super::{
Expand All @@ -53,6 +58,7 @@ pub mod TimelockUpgradeComponent {
pub struct Storage {
pending_implementation: ClassHash,
ready_at: u64,
calldata_hash: felt252,
}

#[event]
Expand All @@ -66,12 +72,13 @@ pub mod TimelockUpgradeComponent {
#[derive(Drop, starknet::Event)]
struct UpgradeProposed {
new_implementation: ClassHash,
ready_at: u64
ready_at: u64,
calldata: Array<felt252>
}

#[derive(Drop, starknet::Event)]
struct UpgradeCancelled {
new_implementation: ClassHash
cancelled_implementation: ClassHash
}

#[derive(Drop, starknet::Event)]
Expand All @@ -83,30 +90,34 @@ pub mod TimelockUpgradeComponent {
impl TimelockUpgrade<
TContractState,
+HasComponent<TContractState>,
impl Ownable: OwnableComponent::HasComponent<TContractState>,
+OwnableComponent::HasComponent<TContractState>,
+ITimelockUpgradeCallback<TContractState>,
> of ITimelockUpgrade<ComponentState<TContractState>> {
fn propose_upgrade(ref self: ComponentState<TContractState>, new_implementation: ClassHash) {
fn propose_upgrade(
ref self: ComponentState<TContractState>, new_implementation: ClassHash, calldata: Array<felt252>
) {
self.assert_only_owner();
assert(new_implementation.is_non_zero(), 'upgrade/new-implementation-null');

let pending_implementation = self.pending_implementation.read();
if pending_implementation.is_non_zero() {
self.emit(UpgradeCancelled { new_implementation: pending_implementation })
self.emit(UpgradeCancelled { cancelled_implementation: pending_implementation })
}

self.pending_implementation.write(new_implementation);
let ready_at = get_block_timestamp() + MIN_SECURITY_PERIOD;
self.ready_at.write(ready_at);
self.emit(UpgradeProposed { new_implementation, ready_at });
let calldata_hash = poseidon_hash_span(calldata.span());
self.calldata_hash.write(calldata_hash);
self.emit(UpgradeProposed { new_implementation, ready_at, calldata });
}

fn cancel_upgrade(ref self: ComponentState<TContractState>) {
self.assert_only_owner();
let new_implementation = self.pending_implementation.read();
assert(new_implementation.is_non_zero(), 'upgrade/no-new-implementation');
let proposed_implementation = self.pending_implementation.read();
assert(proposed_implementation.is_non_zero(), 'upgrade/no-new-implementation');
assert(self.ready_at.read() != 0, 'upgrade/not-ready');
self.emit(UpgradeCancelled { new_implementation });
self.emit(UpgradeCancelled { cancelled_implementation: proposed_implementation });
self.reset_storage();
}

Expand All @@ -115,6 +126,8 @@ pub mod TimelockUpgradeComponent {
let new_implementation = self.pending_implementation.read();
let ready_at = self.ready_at.read();
let block_timestamp = get_block_timestamp();
let calldata_hash = poseidon_hash_span(calldata.span());
assert(calldata_hash == self.calldata_hash.read(), 'upgrade/invalid-calldata');
assert(new_implementation.is_non_zero(), 'upgrade/no-pending-upgrade');
assert(block_timestamp >= ready_at, 'upgrade/too-early');
assert(block_timestamp < ready_at + VALID_WINDOW_PERIOD, 'upgrade/upgrade-too-late');
Expand All @@ -130,6 +143,10 @@ pub mod TimelockUpgradeComponent {
fn get_upgrade_ready_at(self: @ComponentState<TContractState>) -> u64 {
self.ready_at.read()
}

fn get_calldata_hash(self: @ComponentState<TContractState>) -> felt252 {
self.calldata_hash.read()
}
}
#[generate_trait]
impl PrivateImpl<
Expand All @@ -142,6 +159,7 @@ pub mod TimelockUpgradeComponent {
fn reset_storage(ref self: ComponentState<TContractState>) {
self.pending_implementation.write(Zero::zero());
self.ready_at.write(0);
self.calldata_hash.write(0);
}
}
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading
Loading