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

Getters, Config to be upgradeable, Ownable2Step #55

Merged
merged 7 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 27 additions & 0 deletions src/config/pwn_config.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub mod PwnConfig {
use core::clone::Clone;
use openzeppelin::access::ownable::ownable::OwnableComponent;
use openzeppelin::security::initializable::InitializableComponent;
use openzeppelin::upgrades::{interface::IUpgradeable, upgradeable::UpgradeableComponent};
use pwn::config::interface::IPwnConfig;
use pwn::interfaces::{
pool_adapter::IPoolAdapterDispatcher,
Expand All @@ -50,6 +51,7 @@ pub mod PwnConfig {

component!(path: OwnableComponent, storage: ownable, event: OwnableEvent);
component!(path: InitializableComponent, storage: initializable, event: InitializableEvent);
component!(path: UpgradeableComponent, storage: upgradeable, event: UpgradeableEvent);

#[abi(embed_v0)]
impl OwnableTwoStepImpl = OwnableComponent::OwnableTwoStepImpl<ContractState>;
Expand All @@ -60,6 +62,8 @@ pub mod PwnConfig {
InitializableComponent::InitializableImpl<ContractState>;
impl InitializableInternalImpl = InitializableComponent::InternalImpl<ContractState>;

impl UpgreadeableInternalImpl = UpgradeableComponent::InternalImpl<ContractState>;

const VERSION: felt252 = '1.2';
pub const MAX_FEE: u16 = 1000; // 10%

Expand All @@ -74,6 +78,8 @@ pub mod PwnConfig {
ownable: OwnableComponent::Storage,
#[substorage(v0)]
initializable: InitializableComponent::Storage,
#[substorage(v0)]
upgradeable: UpgradeableComponent::Storage,
}

#[event]
Expand All @@ -87,6 +93,8 @@ pub mod PwnConfig {
OwnableEvent: OwnableComponent::Event,
#[flat]
InitializableEvent: InitializableComponent::Event,
#[flat]
UpgradeableEvent: UpgradeableComponent::Event,
}

#[derive(Drop, starknet::Event)]
Expand Down Expand Up @@ -352,6 +360,25 @@ pub mod PwnConfig {
}
}


#[abi(embed_v0)]
impl UpgradeableImpl of IUpgradeable<ContractState> {
/// Replaces the contract's class hash with `new_class_hash`.
///
/// # Arguments
///
/// - `new_class_hash`: class_hash of the new implementation.
///
/// # Requirements
///
/// - `new_class_hash` is not zero.
/// - Only the contract owner can call this function.
fn upgrade(ref self: ContractState, new_class_hash: starknet::ClassHash) {
self.ownable.assert_only_owner();
self.upgradeable.upgrade(new_class_hash);
}
}

#[generate_trait]
impl Private of PrivateTrait {
fn _set_fee(ref self: ContractState, fee: u16) {
Expand Down
2 changes: 1 addition & 1 deletion src/loan/terms/simple/loan/error.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub mod Err {
pub fn INVALID_EXTENSION_CALLER() {
panic!("Invalid extension caller");
}
pub fn INVALID_EXTENSION_SINGNER(allowed: ContractAddress, current: ContractAddress) {
pub fn INVALID_EXTENSION_SIGNER(allowed: ContractAddress, current: ContractAddress) {
panic!("Invalid extension signer. Allowed: {:?}, Current: {:?}", allowed, current);
}
pub fn INVALID_EXTENSION_DURATION(duration: u64, limit: u64) {
Expand Down
3 changes: 2 additions & 1 deletion src/loan/terms/simple/loan/interface.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,15 @@ pub trait IPwnSimpleLoan<TState> {
fn EXTENSION_PROPOSAL_TYPEHASH(self: @TState) -> felt252;
fn MAX_ACCRUING_INTEREST_APR(self: @TState) -> u32;
fn MAX_EXTENSION_DURATION(self: @TState) -> u64;
fn MINUTE_IN_YEAR(self: @TState) -> u64;
fn MINUTES_IN_YEAR(self: @TState) -> u64;
fn MIN_EXTENSION_DURATION(self: @TState) -> u64;
fn MIN_LOAN_DURATION(self: @TState) -> u64;
fn VERSION(self: @TState) -> felt252;
fn get_lender_spec_hash(self: @TState, calladata: types::LenderSpec) -> felt252;
fn get_loan_repayment_amount(self: @TState, loan_id: felt252) -> u256;
fn get_extension_hash(self: @TState, extension: types::ExtensionProposal) -> felt252;
fn get_loan(self: @TState, loan_id: felt252) -> types::GetLoanReturnValue;
fn get_extension_proposal_made(self: @TState, extension_hash: felt252) -> bool;
fn get_is_valid_asset(self: @TState, asset: Asset) -> bool;
fn get_loan_metadata_uri(self: @TState) -> ByteArray;
fn get_state_fingerprint(self: @TState, token_id: felt252) -> felt252;
Expand Down
28 changes: 20 additions & 8 deletions src/loan/terms/simple/loan/pwn_simple_loan.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub mod PwnSimpleLoan {
pub const MIN_LOAN_DURATION: u64 = 600;
pub const MAX_ACCRUING_INTEREST_APR: u32 = 160000;
pub const MINUTE: u64 = 60;
pub const MINUTE_IN_YEAR: u64 = 525_600;
pub const MINUTES_IN_YEAR: u64 = 525_600;
pub const ACCRUING_INTEREST_APR_DENOMINATOR: u64 = 5256000000;
pub const VERSION: felt252 = '1.2';
// @note: duration in seconds
Expand Down Expand Up @@ -415,7 +415,7 @@ pub mod PwnSimpleLoan {
let caller = starknet::get_caller_address();

if (caller != extension.proposer) {
Err::INVALID_EXTENSION_SINGNER(allowed: extension.proposer, current: caller);
Err::INVALID_EXTENSION_SIGNER(allowed: extension.proposer, current: caller);
}

let extension_hash = self.get_extension_hash(extension);
Expand Down Expand Up @@ -502,15 +502,13 @@ pub mod PwnSimpleLoan {

if (caller == loan_owner) {
if (extension.proposer != loan.borrower) {
Err::INVALID_EXTENSION_SINGNER(
Err::INVALID_EXTENSION_SIGNER(
allowed: loan.borrower, current: extension.proposer
);
}
} else if (caller == loan.borrower) {
if (extension.proposer != loan_owner) {
Err::INVALID_EXTENSION_SINGNER(
allowed: loan_owner, current: extension.proposer
);
Err::INVALID_EXTENSION_SIGNER(allowed: loan_owner, current: extension.proposer);
}
} else {
Err::INVALID_EXTENSION_CALLER();
Expand Down Expand Up @@ -667,6 +665,20 @@ pub mod PwnSimpleLoan {
loan_return_value
}

/// Retrieves whether the extension proposal has been made or not.
///
/// # Arguments
///
/// - `extension_hash`: The unique identifier of the extension_proposal .
///
/// # Returns
///
/// - `true` if extension proposal corresponding to `extension_hash` has been made, `false`
/// otherwise.
fn get_extension_proposal_made(self: @ContractState, extension_hash: felt252) -> bool {
self.extension_proposal_made.read(extension_hash)
}

/// Checks if a given asset is valid.
///
/// # Arguments
Expand Down Expand Up @@ -739,8 +751,8 @@ pub mod PwnSimpleLoan {
MAX_ACCRUING_INTEREST_APR
}

fn MINUTE_IN_YEAR(self: @ContractState) -> u64 {
MINUTE_IN_YEAR
fn MINUTES_IN_YEAR(self: @ContractState) -> u64 {
MINUTES_IN_YEAR
}

fn MAX_EXTENSION_DURATION(self: @ContractState) -> u64 {
Expand Down
31 changes: 31 additions & 0 deletions src/loan/terms/simple/proposal/simple_loan_proposal.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub trait ISimpleLoanProposal<TState> {
fn get_multiproposal_hash(
self: @TState, multiproposal: SimpleLoanProposalComponent::Multiproposal
) -> u256;
fn get_proposal_made(self: @TState, proposal_hash: felt252) -> bool;
fn get_credit_used(self: @TState, proposal_hash: felt252) -> u256;
fn DOMAIN_SEPARATOR(self: @TState) -> felt252;
fn MULTIPROPOSAL_DOMAIN_SEPARATOR(self: @TState) -> u256;
fn MULTIPROPOSAL_TYPEHASH(self: @TState) -> u256;
Expand Down Expand Up @@ -208,6 +210,35 @@ pub mod SimpleLoanProposalComponent {
keccak256(abi_encoded_packed(hash_elements).span())
}

/// Retrieves whether the proposal has been made or not.
///
/// # Arguments
///
/// - `proposal_hash`: The unique identifier of the proposal .
///
/// # Returns
///
/// - `true` if proposal corresponding to `proposal_hash` has been made, `false`
/// otherwise.
fn get_proposal_made(
self: @ComponentState<TContractState>, proposal_hash: felt252
) -> bool {
self.proposal_made.read(proposal_hash)
}

/// Retrieves the `credit_used` for the given proposal.
///
/// # Arguments
///
/// - `proposal_hash`: The unique identifier of the proposal .
///
/// # Returns
///
/// - The `credit_used` as `u256
fn get_credit_used(self: @ComponentState<TContractState>, proposal_hash: felt252) -> u256 {
self.credit_used.read(proposal_hash)
}

fn DOMAIN_SEPARATOR(self: @ComponentState<TContractState>) -> felt252 {
self.DOMAIN_SEPARATOR.read()
}
Expand Down
8 changes: 4 additions & 4 deletions src/multitoken/category_registry.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@ pub mod MultiTokenCategoryRegistry {
component!(path: SRC5Component, storage: src5, event: SRC5Event);

#[abi(embed_v0)]
impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl<ContractState>;
impl OwnableTwoStepImpl = OwnableComponent::OwnableTwoStepImpl<ContractState>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be Mixin?, in pwn_config it was not, so I kept this way. Let me know if it needs to be mixin

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2steps is good

impl OwnableInternalImpl = OwnableComponent::InternalImpl<ContractState>;

#[abi(embed_v0)]
impl SRC5MixinImpl = SRC5Component::SRC5Impl<ContractState>;
impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>;
impl SRC5InternalImpl = SRC5Component::InternalImpl<ContractState>;

pub const CATEGORY_NOT_REGISTERED: u8 = 255;

#[storage]
struct Storage {
registered_category: LegacyMap::<ContractAddress, u8>,
Expand Down Expand Up @@ -101,8 +103,6 @@ pub mod MultiTokenCategoryRegistry {
self.ownable.initializer(starknet::get_caller_address());
}

pub const CATEGORY_NOT_REGISTERED: u8 = 255;

#[abi(embed_v0)]
impl IMultiTokenCategoryRegistry of super::IMultiTokenCategoryRegistry<ContractState> {
/// Registers a category value for a given asset address. Only the contract owner
Expand Down
Loading