From 530672d762f041533152de1d2200040f54aae0af Mon Sep 17 00:00:00 2001 From: Turan Ege Caner Date: Tue, 13 Aug 2024 16:04:12 +0300 Subject: [PATCH 1/7] get_extension_proposal_made & typo fixes --- src/loan/terms/simple/loan/error.cairo | 2 +- src/loan/terms/simple/loan/interface.cairo | 1 + .../terms/simple/loan/pwn_simple_loan.cairo | 25 ++++++++++++++----- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/loan/terms/simple/loan/error.cairo b/src/loan/terms/simple/loan/error.cairo index 7d6a92f..ab9505d 100644 --- a/src/loan/terms/simple/loan/error.cairo +++ b/src/loan/terms/simple/loan/error.cairo @@ -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) { diff --git a/src/loan/terms/simple/loan/interface.cairo b/src/loan/terms/simple/loan/interface.cairo index 0ee42d5..d80f1b2 100644 --- a/src/loan/terms/simple/loan/interface.cairo +++ b/src/loan/terms/simple/loan/interface.cairo @@ -36,6 +36,7 @@ pub trait IPwnSimpleLoan { 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; diff --git a/src/loan/terms/simple/loan/pwn_simple_loan.cairo b/src/loan/terms/simple/loan/pwn_simple_loan.cairo index 74f98bc..ef12090 100644 --- a/src/loan/terms/simple/loan/pwn_simple_loan.cairo +++ b/src/loan/terms/simple/loan/pwn_simple_loan.cairo @@ -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 @@ -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); @@ -502,13 +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( + Err::INVALID_EXTENSION_SIGNER( allowed: loan_owner, current: extension.proposer ); } @@ -667,6 +667,19 @@ 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: @TState, extension_hash: felt252) -> bool { + self.extension_proposal_made.read(extension_hash) + } + /// Checks if a given asset is valid. /// /// # Arguments @@ -739,8 +752,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 { From 88a29c3b027efa5ae8571ba460209c4b8dcc0e83 Mon Sep 17 00:00:00 2001 From: Turan Ege Caner Date: Tue, 13 Aug 2024 16:11:18 +0300 Subject: [PATCH 2/7] 'Ownable' to 'OwnableTwoStep' on category registry --- src/loan/terms/simple/loan/pwn_simple_loan.cairo | 3 ++- src/multitoken/category_registry.cairo | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/loan/terms/simple/loan/pwn_simple_loan.cairo b/src/loan/terms/simple/loan/pwn_simple_loan.cairo index ef12090..954bf00 100644 --- a/src/loan/terms/simple/loan/pwn_simple_loan.cairo +++ b/src/loan/terms/simple/loan/pwn_simple_loan.cairo @@ -675,7 +675,8 @@ pub mod PwnSimpleLoan { /// /// # Returns /// - /// - `true` if extension proposal corresponding to `extension_hash` has been made, `false` otherwise. + /// - `true` if extension proposal corresponding to `extension_hash` has been made, `false` + /// otherwise. fn get_extension_proposal_made(self: @TState, extension_hash: felt252) -> bool { self.extension_proposal_made.read(extension_hash) } diff --git a/src/multitoken/category_registry.cairo b/src/multitoken/category_registry.cairo index 1d7b3ca..a31376f 100644 --- a/src/multitoken/category_registry.cairo +++ b/src/multitoken/category_registry.cairo @@ -49,13 +49,16 @@ pub mod MultiTokenCategoryRegistry { component!(path: SRC5Component, storage: src5, event: SRC5Event); #[abi(embed_v0)] - impl OwnableMixinImpl = OwnableComponent::OwnableMixinImpl; + impl OwnableTwoStepMixinImpl = + OwnableComponent::OwnableTwoStepMixinImpl; impl OwnableInternalImpl = OwnableComponent::InternalImpl; #[abi(embed_v0)] impl SRC5MixinImpl = SRC5Component::SRC5Impl; impl SRC5InternalImpl = SRC5Component::InternalImpl; + pub const CATEGORY_NOT_REGISTERED: u8 = 255; + #[storage] struct Storage { registered_category: LegacyMap::, @@ -101,8 +104,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 { /// Registers a category value for a given asset address. Only the contract owner From b9a53b762ff4e759a45b9cad2bfaaeeb10fc4881 Mon Sep 17 00:00:00 2001 From: Turan Ege Caner Date: Tue, 13 Aug 2024 19:16:36 +0300 Subject: [PATCH 3/7] make the config upgradeable --- src/config/pwn_config.cairo | 27 +++++++++++++++++++ src/loan/terms/simple/loan/interface.cairo | 2 +- .../terms/simple/loan/pwn_simple_loan.cairo | 2 +- 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/config/pwn_config.cairo b/src/config/pwn_config.cairo index 7fb5f64..9527967 100644 --- a/src/config/pwn_config.cairo +++ b/src/config/pwn_config.cairo @@ -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, @@ -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; @@ -60,6 +62,8 @@ pub mod PwnConfig { InitializableComponent::InitializableImpl; impl InitializableInternalImpl = InitializableComponent::InternalImpl; + impl UpgreadeableInternalImpl = UpgradeableComponent::InternalImpl; + const VERSION: felt252 = '1.2'; pub const MAX_FEE: u16 = 1000; // 10% @@ -74,6 +78,8 @@ pub mod PwnConfig { ownable: OwnableComponent::Storage, #[substorage(v0)] initializable: InitializableComponent::Storage, + #[substorage(v0)] + upgradeable: UpgradeableComponent::Storage, } #[event] @@ -87,6 +93,8 @@ pub mod PwnConfig { OwnableEvent: OwnableComponent::Event, #[flat] InitializableEvent: InitializableComponent::Event, + #[flat] + UpgradeableEvent: UpgradeableComponent::Event, } #[derive(Drop, starknet::Event)] @@ -352,6 +360,25 @@ pub mod PwnConfig { } } + + #[abi(embed_v0)] + impl UpgradeableImpl of IUpgradeable{ + /// 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) { diff --git a/src/loan/terms/simple/loan/interface.cairo b/src/loan/terms/simple/loan/interface.cairo index d80f1b2..db66e6b 100644 --- a/src/loan/terms/simple/loan/interface.cairo +++ b/src/loan/terms/simple/loan/interface.cairo @@ -28,7 +28,7 @@ pub trait IPwnSimpleLoan { 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; diff --git a/src/loan/terms/simple/loan/pwn_simple_loan.cairo b/src/loan/terms/simple/loan/pwn_simple_loan.cairo index 954bf00..a991176 100644 --- a/src/loan/terms/simple/loan/pwn_simple_loan.cairo +++ b/src/loan/terms/simple/loan/pwn_simple_loan.cairo @@ -677,7 +677,7 @@ pub mod PwnSimpleLoan { /// /// - `true` if extension proposal corresponding to `extension_hash` has been made, `false` /// otherwise. - fn get_extension_proposal_made(self: @TState, extension_hash: felt252) -> bool { + fn get_extension_proposal_made(self: @ContractState, extension_hash: felt252) -> bool { self.extension_proposal_made.read(extension_hash) } From 655a19c6a6a2e31878fb1952aea7bb7ca0f80894 Mon Sep 17 00:00:00 2001 From: Turan Ege Caner Date: Tue, 13 Aug 2024 19:25:06 +0300 Subject: [PATCH 4/7] getters for simple_loan_proposal 'proposal_made' and 'credit_used' --- .../terms/simple/proposal/simple_loan_proposal.cairo | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/loan/terms/simple/proposal/simple_loan_proposal.cairo b/src/loan/terms/simple/proposal/simple_loan_proposal.cairo index b1beda6..d629f8c 100644 --- a/src/loan/terms/simple/proposal/simple_loan_proposal.cairo +++ b/src/loan/terms/simple/proposal/simple_loan_proposal.cairo @@ -8,6 +8,8 @@ pub trait ISimpleLoanProposal { 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; @@ -208,6 +210,14 @@ pub mod SimpleLoanProposalComponent { keccak256(abi_encoded_packed(hash_elements).span()) } + fn get_proposal_made(self: @TState, proposal_hash: felt252) -> bool { + self.proposal_made.read(proposal_hash) + } + + fn get_credit_used(self: @TState, proposal_hash: felt252) -> u256{ + self.credit_used.read(proposal_hash) + } + fn DOMAIN_SEPARATOR(self: @ComponentState) -> felt252 { self.DOMAIN_SEPARATOR.read() } From ca2657a2a13345e12c6c75066c98235ccc5d3eae Mon Sep 17 00:00:00 2001 From: Turan Ege Caner Date: Tue, 13 Aug 2024 22:27:16 +0300 Subject: [PATCH 5/7] compilation fix --- src/loan/terms/simple/proposal/simple_loan_proposal.cairo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/loan/terms/simple/proposal/simple_loan_proposal.cairo b/src/loan/terms/simple/proposal/simple_loan_proposal.cairo index d629f8c..bf1f3c0 100644 --- a/src/loan/terms/simple/proposal/simple_loan_proposal.cairo +++ b/src/loan/terms/simple/proposal/simple_loan_proposal.cairo @@ -210,11 +210,11 @@ pub mod SimpleLoanProposalComponent { keccak256(abi_encoded_packed(hash_elements).span()) } - fn get_proposal_made(self: @TState, proposal_hash: felt252) -> bool { + fn get_proposal_made(self: @ComponentState, proposal_hash: felt252) -> bool { self.proposal_made.read(proposal_hash) } - fn get_credit_used(self: @TState, proposal_hash: felt252) -> u256{ + fn get_credit_used(self: @ComponentState, proposal_hash: felt252) -> u256 { self.credit_used.read(proposal_hash) } From 7494f42e90a24e4d5326aba05073b7d5c35aa790 Mon Sep 17 00:00:00 2001 From: Turan Ege Caner Date: Wed, 14 Aug 2024 12:41:28 +0300 Subject: [PATCH 6/7] comments & fmt --- src/config/pwn_config.cairo | 4 ++-- .../terms/simple/loan/pwn_simple_loan.cairo | 4 +--- .../proposal/simple_loan_proposal.cairo | 23 ++++++++++++++++++- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/config/pwn_config.cairo b/src/config/pwn_config.cairo index 9527967..bb0d9ef 100644 --- a/src/config/pwn_config.cairo +++ b/src/config/pwn_config.cairo @@ -63,7 +63,7 @@ pub mod PwnConfig { impl InitializableInternalImpl = InitializableComponent::InternalImpl; impl UpgreadeableInternalImpl = UpgradeableComponent::InternalImpl; - + const VERSION: felt252 = '1.2'; pub const MAX_FEE: u16 = 1000; // 10% @@ -362,7 +362,7 @@ pub mod PwnConfig { #[abi(embed_v0)] - impl UpgradeableImpl of IUpgradeable{ + impl UpgradeableImpl of IUpgradeable { /// Replaces the contract's class hash with `new_class_hash`. /// /// # Arguments diff --git a/src/loan/terms/simple/loan/pwn_simple_loan.cairo b/src/loan/terms/simple/loan/pwn_simple_loan.cairo index a991176..cf64964 100644 --- a/src/loan/terms/simple/loan/pwn_simple_loan.cairo +++ b/src/loan/terms/simple/loan/pwn_simple_loan.cairo @@ -508,9 +508,7 @@ pub mod PwnSimpleLoan { } } else if (caller == loan.borrower) { if (extension.proposer != loan_owner) { - Err::INVALID_EXTENSION_SIGNER( - allowed: loan_owner, current: extension.proposer - ); + Err::INVALID_EXTENSION_SIGNER(allowed: loan_owner, current: extension.proposer); } } else { Err::INVALID_EXTENSION_CALLER(); diff --git a/src/loan/terms/simple/proposal/simple_loan_proposal.cairo b/src/loan/terms/simple/proposal/simple_loan_proposal.cairo index bf1f3c0..9bba9cf 100644 --- a/src/loan/terms/simple/proposal/simple_loan_proposal.cairo +++ b/src/loan/terms/simple/proposal/simple_loan_proposal.cairo @@ -210,10 +210,31 @@ pub mod SimpleLoanProposalComponent { keccak256(abi_encoded_packed(hash_elements).span()) } - fn get_proposal_made(self: @ComponentState, proposal_hash: felt252) -> bool { + /// 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, 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, proposal_hash: felt252) -> u256 { self.credit_used.read(proposal_hash) } From 97ceb9f327f8aaf32777628fa14d2ae725c3c566 Mon Sep 17 00:00:00 2001 From: Turan Ege Caner Date: Wed, 14 Aug 2024 12:52:55 +0300 Subject: [PATCH 7/7] renamed vars --- src/multitoken/category_registry.cairo | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/multitoken/category_registry.cairo b/src/multitoken/category_registry.cairo index a31376f..56159d3 100644 --- a/src/multitoken/category_registry.cairo +++ b/src/multitoken/category_registry.cairo @@ -49,12 +49,11 @@ pub mod MultiTokenCategoryRegistry { component!(path: SRC5Component, storage: src5, event: SRC5Event); #[abi(embed_v0)] - impl OwnableTwoStepMixinImpl = - OwnableComponent::OwnableTwoStepMixinImpl; + impl OwnableTwoStepImpl = OwnableComponent::OwnableTwoStepImpl; impl OwnableInternalImpl = OwnableComponent::InternalImpl; #[abi(embed_v0)] - impl SRC5MixinImpl = SRC5Component::SRC5Impl; + impl SRC5Impl = SRC5Component::SRC5Impl; impl SRC5InternalImpl = SRC5Component::InternalImpl; pub const CATEGORY_NOT_REGISTERED: u8 = 255;