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

lock and is_lock function of lockable component #45

Merged
merged 12 commits into from
Aug 20, 2024
119 changes: 119 additions & 0 deletions src/components/lockable/lockable.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,122 @@
// lockable component
// *************************************************************************
// LOCKABLE COMPONENT
// *************************************************************************
#[starknet::component]
pub mod LockableComponent {
// *************************************************************************
// IMPORTS
// *************************************************************************
use starknet::storage::StoragePointerWriteAccess;
use starknet::storage::StoragePointerReadAccess;
use starknet::{ContractAddress, get_caller_address, get_block_timestamp};
use token_bound_accounts::components::account::account::AccountComponent;
use token_bound_accounts::interfaces::IAccount::{IAccount, IAccountDispatcherTrait};
use token_bound_accounts::components::account::account::AccountComponent::InternalImpl;
use token_bound_accounts::interfaces::ILockable::{
ILockable, ILockableDispatcher, ILockableDispatcherTrait
};

#[storage]
pub struct Storage {
lock_until: u64
}

#[event]
#[derive(Drop, starknet::Event)]
pub enum Event {
AccountLocked: AccountLocked
}

/// @notice Emitted when the account is locked
/// @param account tokenbound account who's lock function was triggered
/// @param locked_at timestamp at which the lock function was triggered
/// @param lock_until time duration for which the account remains locked in second
#[derive(Drop, starknet::Event)]
pub struct AccountLocked {
#[key]
pub account: ContractAddress,
pub locked_at: u64,
pub lock_until: u64,
}


// *************************************************************************
// ERRORS
// *************************************************************************
pub mod Errors {
pub const UNAUTHORIZED: felt252 = 'Account: unauthorized';
pub const NOT_OWNER: felt252 = 'Account: Not Account Owner';
pub const EXCEEDS_MAX_LOCK_TIME: felt252 = 'Account: Lock time exceeded';
pub const LOCKED_ACCOUNT: felt252 = 'Account: Locked';
}

pub const YEAR_DAYS_SECONDS: u64 = 31536000;


// storage that store the token_id and the lock_util perioed

// *************************************************************************
// EXTERNAL FUNCTIONS
// *************************************************************************
#[embeddable_as(LockableImpl)]
pub impl Lockable<
TContractState,
+HasComponent<TContractState>,
+Drop<TContractState>,
impl Account: AccountComponent::HasComponent<TContractState>
> of ILockable<ComponentState<TContractState>> {
fn lock(ref self: ComponentState<TContractState>, lock_until: u64) {
let current_timestamp = get_block_timestamp();
let account_comp = get_dep_component!(@self, Account);

let is_valid = account_comp._is_valid_signer(get_caller_address());
assert(is_valid, Errors::UNAUTHORIZED);

assert(
lock_until <= current_timestamp + YEAR_DAYS_SECONDS, Errors::EXCEEDS_MAX_LOCK_TIME
);

let (lock_status, _) = self.is_locked();

assert(lock_status != true, Errors::LOCKED_ACCOUNT);

// update account state
let mut account_comp_mut = get_dep_component_mut!(ref self, Account);
account_comp_mut._update_state();

// set the lock_util which set the period the account is lock
self.lock_until.write(lock_until);
mubarak23 marked this conversation as resolved.
Show resolved Hide resolved
// emit event
self
.emit(
AccountLocked {
account: get_caller_address(),
locked_at: get_block_timestamp(),
lock_until: lock_until
}
);
}

fn is_locked(self: @ComponentState<TContractState>) -> (bool, u64) {
let unlock_timestamp = self.lock_until.read();
let current_time = get_block_timestamp();
if (current_time < unlock_timestamp) {
let time_until_unlocks = unlock_timestamp - current_time;
return (true, time_until_unlocks);
} else {
return (false, 0_u64);
}
}
}
}
// let unlock_timestamp = self.account_unlock_timestamp.read();
// let current_time = get_block_timestamp();
// if (current_time < unlock_timestamp) {
// let time_until_unlocks = unlock_timestamp - current_time;
// return (true, time_until_unlocks);
// } else {
// return (false, 0_u64);
// }


34 changes: 31 additions & 3 deletions src/components/presets/account_preset.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@ pub mod AccountPreset {
use starknet::{ContractAddress, get_caller_address, ClassHash, account::Call};
use token_bound_accounts::components::account::account::AccountComponent;
use token_bound_accounts::components::upgradeable::upgradeable::UpgradeableComponent;
use token_bound_accounts::interfaces::{IUpgradeable::IUpgradeable, IExecutable::IExecutable,};
use token_bound_accounts::components::lockable::lockable::LockableComponent;
use token_bound_accounts::interfaces::{
IUpgradeable::IUpgradeable, IExecutable::IExecutable, ILockable::ILockable
};

component!(path: AccountComponent, storage: account, event: AccountEvent);
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);
component!(path: LockableComponent, storage: lockable, event: LockableEvent);

// Account
#[abi(embed_v0)]
impl AccountImpl = AccountComponent::AccountImpl<ContractState>;

impl AccountInternalImpl = AccountComponent::InternalImpl<ContractState>;
impl UpgradeableInternalImpl = UpgradeableComponent::Private<ContractState>;
impl LockableImpl = LockableComponent::LockableImpl<ContractState>;

// *************************************************************************
// STORAGE
Expand All @@ -26,7 +31,9 @@ pub mod AccountPreset {
#[substorage(v0)]
account: AccountComponent::Storage,
#[substorage(v0)]
upgradeable: UpgradeableComponent::Storage
upgradeable: UpgradeableComponent::Storage,
#[substorage(v0)]
lockable: LockableComponent::Storage,
}

// *************************************************************************
Expand All @@ -38,7 +45,9 @@ pub mod AccountPreset {
#[flat]
AccountEvent: AccountComponent::Event,
#[flat]
UpgradeableEvent: UpgradeableComponent::Event
UpgradeableEvent: UpgradeableComponent::Event,
#[flat]
LockableEvent: LockableComponent::Event
}

// *************************************************************************
Expand All @@ -55,6 +64,9 @@ pub mod AccountPreset {
#[abi(embed_v0)]
impl Executable of IExecutable<ContractState> {
fn execute(ref self: ContractState, mut calls: Array<Call>) -> Array<Span<felt252>> {
// cannot make this call when the account is lock
let (is_locked, _) = self.lockable.is_locked();
assert(is_locked != true, 'Account: locked');
self.account._execute(calls)
}
}
Expand All @@ -65,7 +77,23 @@ pub mod AccountPreset {
#[abi(embed_v0)]
impl Upgradeable of IUpgradeable<ContractState> {
fn upgrade(ref self: ContractState, new_class_hash: ClassHash) {
// cannot make this call when the account is lock
let (is_locked, _) = self.lockable.is_locked();
assert(is_locked != true, 'Account: locked');
self.upgradeable._upgrade(new_class_hash);
}
}

// *************************************************************************
// LOCKABLE IMPL
// *************************************************************************
#[abi(embed_v0)]
impl Lockable of ILockable<ContractState> {
fn lock(ref self: ContractState, lock_until: u64) {
self.lockable.lock(lock_until);
}
fn is_locked(self: @ContractState) -> (bool, u64) {
self.lockable.is_locked()
}
}
}
1 change: 1 addition & 0 deletions src/interfaces.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ pub mod IERC721;
pub mod IRegistry;
pub mod IUpgradeable;
pub mod IExecutable;
pub mod ILockable;
7 changes: 7 additions & 0 deletions src/interfaces/ILockable.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use starknet::ContractAddress;

#[starknet::interface]
pub trait ILockable<TContractState> {
fn lock(ref self: TContractState, lock_until: u64);
fn is_locked(self: @TContractState) -> (bool, u64);
}
Loading
Loading