From 0a552d956265b79531a8cb4da9ae81c3f2f09d75 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Fri, 25 Oct 2024 17:24:31 +0100 Subject: [PATCH 01/32] Add pool name to extensions --- src/extension/default_extension_cl.cairo | 19 +++++++++++++++++++ src/extension/default_extension_po.cairo | 19 +++++++++++++++++++ src/test/setup.cairo | 6 ++++++ src/test/test_default_extension_cl.cairo | 4 ++++ src/test/test_default_extension_po.cairo | 4 ++++ src/test/test_forking.cairo | 2 ++ src/test/test_pragma_oracle.cairo | 1 + 7 files changed, 55 insertions(+) diff --git a/src/extension/default_extension_cl.cairo b/src/extension/default_extension_cl.cairo index 4ee2b47..a7fb4d0 100644 --- a/src/extension/default_extension_cl.cairo +++ b/src/extension/default_extension_cl.cairo @@ -20,6 +20,7 @@ struct ChainlinkOracleParams { #[starknet::interface] trait IDefaultExtensionCL { + fn pool_name(self: @TContractState, pool_id: felt252) -> felt252; fn pool_owner(self: @TContractState, pool_id: felt252) -> ContractAddress; fn chainlink_oracle_config( self: @TContractState, pool_id: felt252, asset: ContractAddress @@ -54,6 +55,7 @@ trait IDefaultExtensionCL { ) -> ContractAddress; fn create_pool( ref self: TContractState, + name: felt252, asset_params: Span, v_token_params: Span, ltv_params: Span, @@ -161,6 +163,8 @@ mod DefaultExtensionCL { singleton: ContractAddress, // tracks the owner for each pool owner: LegacyMap::, + // tracks the name for each pool + pool_names: LegacyMap::, // storage for the position hooks component #[substorage(v0)] position_hooks: position_hooks_component::Storage, @@ -277,6 +281,15 @@ mod DefaultExtensionCL { #[abi(embed_v0)] impl DefaultExtensionCLImpl of IDefaultExtensionCL { + /// Returns the name of a pool + /// # Arguments + /// * `pool_id` - id of the pool + /// # Returns + /// * `name` - name of the pool + fn pool_name(self: @ContractState, pool_id: felt252) -> felt252 { + self.pool_names.read(pool_id) + } + /// Returns the owner of a pool /// # Arguments /// * `pool_id` - id of the pool @@ -446,6 +459,7 @@ mod DefaultExtensionCL { /// Creates a new pool /// # Arguments + /// * `name` - name of the pool /// * `asset_params` - asset parameters /// * `v_token_params` - vToken parameters /// * `ltv_params` - loan-to-value parameters @@ -458,6 +472,7 @@ mod DefaultExtensionCL { /// * `pool_id` - id of the pool fn create_pool( ref self: ContractState, + name: felt252, mut asset_params: Span, mut v_token_params: Span, mut ltv_params: Span, @@ -477,6 +492,10 @@ mod DefaultExtensionCL { // create the pool in the singleton let pool_id = ISingletonDispatcher { contract_address: self.singleton.read() } .create_pool(asset_params, ltv_params, get_contract_address()); + + // set the pool name + self.pool_names.write(pool_id, name); + // set the pool owner self.owner.write(pool_id, owner); diff --git a/src/extension/default_extension_po.cairo b/src/extension/default_extension_po.cairo index a695b6c..4cc713b 100644 --- a/src/extension/default_extension_po.cairo +++ b/src/extension/default_extension_po.cairo @@ -73,6 +73,7 @@ trait ITokenizationCallback { #[starknet::interface] trait IDefaultExtension { + fn pool_name(self: @TContractState, pool_id: felt252) -> felt252; fn pool_owner(self: @TContractState, pool_id: felt252) -> ContractAddress; fn pragma_oracle(self: @TContractState) -> ContractAddress; fn oracle_config(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> OracleConfig; @@ -106,6 +107,7 @@ trait IDefaultExtension { ) -> ContractAddress; fn create_pool( ref self: TContractState, + name: felt252, asset_params: Span, v_token_params: Span, ltv_params: Span, @@ -211,6 +213,8 @@ mod DefaultExtensionPO { singleton: ContractAddress, // tracks the owner for each pool owner: LegacyMap::, + // tracks the name for each pool + pool_names: LegacyMap::, // storage for the position hooks component #[substorage(v0)] position_hooks: position_hooks_component::Storage, @@ -333,6 +337,15 @@ mod DefaultExtensionPO { #[abi(embed_v0)] impl DefaultExtensionImpl of IDefaultExtension { + /// Returns the name of a pool + /// # Arguments + /// * `pool_id` - id of the pool + /// # Returns + /// * `name` - name of the pool + fn pool_name(self: @ContractState, pool_id: felt252) -> felt252 { + self.pool_names.read(pool_id) + } + /// Returns the owner of a pool /// # Arguments /// * `pool_id` - id of the pool @@ -507,6 +520,7 @@ mod DefaultExtensionPO { /// Creates a new pool /// # Arguments + /// * `name` - name of the pool /// * `asset_params` - asset parameters /// * `v_token_params` - vToken parameters /// * `ltv_params` - loan-to-value parameters @@ -519,6 +533,7 @@ mod DefaultExtensionPO { /// * `pool_id` - id of the pool fn create_pool( ref self: ContractState, + name: felt252, mut asset_params: Span, mut v_token_params: Span, mut ltv_params: Span, @@ -538,6 +553,10 @@ mod DefaultExtensionPO { // create the pool in the singleton let pool_id = ISingletonDispatcher { contract_address: self.singleton.read() } .create_pool(asset_params, ltv_params, get_contract_address()); + + // set the pool name + self.pool_names.write(pool_id, name); + // set the pool owner self.owner.write(pool_id, owner); diff --git a/src/test/setup.cairo b/src/test/setup.cairo index dd00169..8fd713f 100644 --- a/src/test/setup.cairo +++ b/src/test/setup.cairo @@ -323,6 +323,7 @@ fn create_pool( start_prank(CheatTarget::One(extension.contract_address), creator); extension .create_pool( + 'DefaultExtensionPO', asset_params, v_token_params, max_position_ltv_params, @@ -348,6 +349,8 @@ fn create_pool( assert!( extension.collateral_asset_for_v_token(config.pool_id, third_v_token) != Zeroable::zero(), "vToken not set" ); + + assert!(extension.pool_name(config.pool_id) == 'DefaultExtensionPO', "pool name not set"); } fn create_pool_v2( @@ -473,6 +476,7 @@ fn create_pool_v2( start_prank(CheatTarget::One(extension.contract_address), creator); extension .create_pool( + 'DefaultExtensionCL', asset_params, v_token_params, max_position_ltv_params, @@ -503,6 +507,8 @@ fn create_pool_v2( assert!( extension.collateral_asset_for_v_token(config.pool_id_v2, third_v_token) != Zeroable::zero(), "vToken not set" ); + + assert!(extension.pool_name(config.pool_id_v2) == 'DefaultExtensionCL', "pool name not set"); } fn setup_pool( diff --git a/src/test/test_default_extension_cl.cairo b/src/test/test_default_extension_cl.cairo index 02d606d..35956ec 100644 --- a/src/test/test_default_extension_cl.cairo +++ b/src/test/test_default_extension_cl.cairo @@ -75,6 +75,7 @@ mod TestDefaultExtensionCL { start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); extension_v2 .create_pool( + 'DefaultExtensionCL', asset_params, v_token_params, max_position_ltv_params, @@ -121,6 +122,7 @@ mod TestDefaultExtensionCL { start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); extension_v2 .create_pool( + 'DefaultExtensionCL', asset_params, v_token_params, max_position_ltv_params, @@ -167,6 +169,7 @@ mod TestDefaultExtensionCL { start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); extension_v2 .create_pool( + 'DefaultExtensionCL', asset_params, v_token_params, max_position_ltv_params, @@ -213,6 +216,7 @@ mod TestDefaultExtensionCL { start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); extension_v2 .create_pool( + 'DefaultExtensionCL', asset_params, v_token_params, max_position_ltv_params, diff --git a/src/test/test_default_extension_po.cairo b/src/test/test_default_extension_po.cairo index 0b31fb1..03322b9 100644 --- a/src/test/test_default_extension_po.cairo +++ b/src/test/test_default_extension_po.cairo @@ -65,6 +65,7 @@ mod TestDefaultExtensionPO { start_prank(CheatTarget::One(extension.contract_address), users.creator); extension .create_pool( + 'DefaultExtensionPO', asset_params, v_token_params, max_position_ltv_params, @@ -111,6 +112,7 @@ mod TestDefaultExtensionPO { start_prank(CheatTarget::One(extension.contract_address), users.creator); extension .create_pool( + 'DefaultExtensionPO', asset_params, v_token_params, max_position_ltv_params, @@ -157,6 +159,7 @@ mod TestDefaultExtensionPO { start_prank(CheatTarget::One(extension.contract_address), users.creator); extension .create_pool( + 'DefaultExtensionPO', asset_params, v_token_params, max_position_ltv_params, @@ -205,6 +208,7 @@ mod TestDefaultExtensionPO { start_prank(CheatTarget::One(extension.contract_address), users.creator); extension .create_pool( + 'DefaultExtensionPO', asset_params, v_token_params, max_position_ltv_params, diff --git a/src/test/test_forking.cairo b/src/test/test_forking.cairo index 94aff35..5f001b8 100644 --- a/src/test/test_forking.cairo +++ b/src/test/test_forking.cairo @@ -443,6 +443,7 @@ mod TestForking { extension .create_pool( + 'DefaultExtensionPO', asset_params, v_token_params, max_ltv_params, @@ -719,6 +720,7 @@ mod TestForking { extension .create_pool( + 'DefaultExtensionCL', asset_params, v_token_params, max_ltv_params, diff --git a/src/test/test_pragma_oracle.cairo b/src/test/test_pragma_oracle.cairo index 562e5e9..f0ef36e 100644 --- a/src/test/test_pragma_oracle.cairo +++ b/src/test/test_pragma_oracle.cairo @@ -109,6 +109,7 @@ mod TestPragmaOracle { start_prank(CheatTarget::One(extension.contract_address), creator); extension .create_pool( + 'DefaultExtensionPO', asset_params, v_token_params, max_position_ltv_params, From 9e7c0aa284826e34cb40981942c97051b210988a Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:09:39 +0000 Subject: [PATCH 02/32] Add pool name to scripts --- gas-report.txt | 4 ++-- lib/config.devnet.ts | 1 + lib/config.mainnet.ts | 1 + lib/config.sepolia.ts | 1 + lib/model.ts | 1 + lib/protocol.ts | 1 + 6 files changed, 7 insertions(+), 2 deletions(-) diff --git a/gas-report.txt b/gas-report.txt index ab353db..ed30f13 100644 --- a/gas-report.txt +++ b/gas-report.txt @@ -2,7 +2,7 @@ Summary: ┌─────────────┬─────────────────────────┬─────────┬────────────────┬────────────────┬─────────────────┬───────────┬──────────────┬──────────────────────────────┬───────────────┬──────────────────┬─────────┐ │ (index) │ Actual fee │ Fee usd │ Fee without DA │ Gas without DA │ Computation gas │ Event gas │ Calldata gas │ Max computation per Category │ Storage diffs │ DA fee │ DA mode │ ├─────────────┼─────────────────────────┼─────────┼────────────────┼────────────────┼─────────────────┼───────────┼──────────────┼──────────────────────────────┼───────────────┼──────────────────┼─────────┤ -│ Create pool │ '1.452.040.000.000.000' │ 5.8081 │ 24840000000000 │ 690 │ 628 │ 144 │ 62 │ 'steps' │ 206 │ 1427200000000000 │ 'BLOB' │ +│ Create pool │ '1.458.476.000.000.000' │ 5.8339 │ 24876000000000 │ 691 │ 629 │ 144 │ 62 │ 'steps' │ 207 │ 1433600000000000 │ 'BLOB' │ │ Lend │ '111.768.000.000.000' │ 0.447 │ 15768000000000 │ 438 │ 436 │ 12 │ 2 │ 'range_check' │ 12 │ 96000000000000 │ 'BLOB' │ │ Transfer │ '102.684.000.000.000' │ 0.4107 │ 25884000000000 │ 719 │ 717 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ │ Borrow │ '146.900.000.000.000' │ 0.5876 │ 18900000000000 │ 525 │ 523 │ 13 │ 2 │ 'range_check' │ 16 │ 128000000000000 │ 'BLOB' │ @@ -12,7 +12,7 @@ Resources: ┌─────────────┬─────────┬───────┬───────┬────────┬──────────┬──────────┬─────────────┬────────┐ │ (index) │ bitwise │ ec_op │ ecdsa │ keccak │ pedersen │ poseidon │ range_check │ steps │ ├─────────────┼─────────┼───────┼───────┼────────┼──────────┼──────────┼─────────────┼────────┤ -│ Create pool │ 57 │ 3 │ 0 │ 0 │ 1019 │ 1 │ 14528 │ 251057 │ +│ Create pool │ 57 │ 3 │ 0 │ 0 │ 1021 │ 1 │ 14534 │ 251284 │ │ Lend │ 26 │ 3 │ 0 │ 0 │ 134 │ 0 │ 10892 │ 93965 │ │ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17924 │ 142928 │ │ Borrow │ 33 │ 3 │ 0 │ 0 │ 146 │ 0 │ 13058 │ 107000 │ diff --git a/lib/config.devnet.ts b/lib/config.devnet.ts index 98cb459..45729bb 100644 --- a/lib/config.devnet.ts +++ b/lib/config.devnet.ts @@ -51,6 +51,7 @@ export const config: Config = { description: "", type: "", params: { + pool_name: "Genesis Pool", asset_params: CONFIG.asset_parameters.map((asset: any) => ({ asset: "0x0", floor: toScale(asset.floor), diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index da9a4ee..f6d5379 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -38,6 +38,7 @@ export const config: Config = { description: "", type: "", params: { + pool_name: "Genesis Pool", asset_params: CONFIG.asset_parameters.map((asset: any) => ({ asset: asset.token.address, floor: toScale(asset.floor), diff --git a/lib/config.sepolia.ts b/lib/config.sepolia.ts index 996056c..fcfd6e9 100644 --- a/lib/config.sepolia.ts +++ b/lib/config.sepolia.ts @@ -57,6 +57,7 @@ export const config: Config = { description: "", type: "", params: { + pool_name: "Genesis Pool", asset_params: CONFIG.asset_parameters.map((asset: any) => ({ asset: "0x0", floor: toScale(asset.floor), diff --git a/lib/model.ts b/lib/model.ts index ac6dcb2..fa031c2 100644 --- a/lib/model.ts +++ b/lib/model.ts @@ -90,6 +90,7 @@ export interface FeeParams { } export interface CreatePoolParams { + pool_name: string; asset_params: AssetParams[]; v_token_params: VTokenParams[]; ltv_params: LTVParams[]; diff --git a/lib/protocol.ts b/lib/protocol.ts index af67ceb..3b83c31 100644 --- a/lib/protocol.ts +++ b/lib/protocol.ts @@ -36,6 +36,7 @@ export class Protocol implements ProtocolContracts { extension.connect(deployer.creator); const response = await extension.create_pool( + params.pool_name, params.asset_params, params.v_token_params, params.ltv_params, From ceb032c50d9a8e11aadffaf5c235d2cf48b72f22 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Mon, 4 Nov 2024 16:00:38 +0000 Subject: [PATCH 03/32] Add CreateVToken event --- src/extension/components/tokenization.cairo | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/extension/components/tokenization.cairo b/src/extension/components/tokenization.cairo index b6a3975..6d5f26a 100644 --- a/src/extension/components/tokenization.cairo +++ b/src/extension/components/tokenization.cairo @@ -20,9 +20,21 @@ mod tokenization_component { v_token_for_collateral_asset: LegacyMap::<(felt252, ContractAddress), ContractAddress> } + #[derive(Drop, starknet::Event)] + struct CreateVToken { + #[key] + v_token: ContractAddress, + #[key] + pool_id: felt252, + #[key] + collateral_asset: ContractAddress, + } + #[event] #[derive(Drop, starknet::Event)] - enum Event {} + enum Event { + CreateVToken: CreateVToken, + } #[generate_trait] impl TokenizationTrait< @@ -99,6 +111,8 @@ mod tokenization_component { ISingletonDispatcher { contract_address: self.get_contract().singleton() } .modify_delegation(pool_id, v_token, true); + + self.emit(CreateVToken { v_token, pool_id, collateral_asset }); } /// Mints or burns vTokens for a user for a given collateral asset. From dbcbcd966f9e0e85a62ac17917e164ee1e5726a8 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 6 Nov 2024 17:52:53 +0000 Subject: [PATCH 04/32] Push progress --- src/extension/default_extension_cl.cairo | 61 ++++++++- src/extension/default_extension_po.cairo | 60 ++++++++- src/test/setup.cairo | 164 +++++------------------ src/test/test_asset_retrieval.cairo | 16 ++- src/test/test_default_extension_cl.cairo | 53 ++++++-- src/test/test_default_extension_po.cairo | 45 +++++-- src/test/test_flash_loan.cairo | 6 +- src/test/test_modify_position.cairo | 10 +- src/test/test_pool_donations.cairo | 2 +- src/units.cairo | 2 + 10 files changed, 234 insertions(+), 185 deletions(-) diff --git a/src/extension/default_extension_cl.cairo b/src/extension/default_extension_cl.cairo index 4ee2b47..2fa1e0d 100644 --- a/src/extension/default_extension_cl.cairo +++ b/src/extension/default_extension_cl.cairo @@ -116,13 +116,19 @@ trait IDefaultExtensionCL { #[starknet::contract] mod DefaultExtensionCL { - use alexandria_math::i257::i257; - use starknet::{ContractAddress, get_contract_address, get_caller_address, event::EventEmitter}; - use vesu::extension::components::position_hooks::position_hooks_component::Trait; + use alexandria_math::i257::{i257, i257_new}; + use starknet::{ + ContractAddress, get_contract_address, get_caller_address, event::EventEmitter, contract_address_const + }; use vesu::{ map_list::{map_list_component, map_list_component::MapListTrait}, - data_model::{Amount, UnsignedAmount, AssetParams, AssetPrice, LTVParams, Context, LTVConfig}, + data_model::{ + Amount, UnsignedAmount, AssetParams, AssetPrice, LTVParams, Context, LTVConfig, ModifyPositionParams, + AmountDenomination, AmountType + }, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, + vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, + units::INFLATION_FEE, extension::{ default_extension_po::{ LiquidationParams, ShutdownParams, ITimestampManagerCallback, FeeParams, VTokenParams, @@ -475,8 +481,8 @@ mod DefaultExtensionCL { assert!(asset_params.len() == v_token_params.len(), "v-token-params-mismatch"); // create the pool in the singleton - let pool_id = ISingletonDispatcher { contract_address: self.singleton.read() } - .create_pool(asset_params, ltv_params, get_contract_address()); + let singleton = ISingletonDispatcher { contract_address: self.singleton.read() }; + let pool_id = singleton.create_pool(asset_params, ltv_params, get_contract_address()); // set the pool owner self.owner.write(pool_id, owner); @@ -503,6 +509,27 @@ mod DefaultExtensionCL { // deploy the vToken for the the collateral asset self.tokenization.create_v_token(pool_id, asset, v_token_name, v_token_symbol); + // burn inflation fee + let asset = IERC20Dispatcher { contract_address: asset }; + asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE); + asset.approve(singleton.contract_address, INFLATION_FEE); + singleton + .modify_position( + ModifyPositionParams { + pool_id, + collateral_asset: asset.contract_address, + debt_asset: Zeroable::zero(), + user: contract_address_const::<'ZERO'>(), + collateral: Amount { + amount_type: AmountType::Delta, + denomination: AmountDenomination::Assets, + value: i257_new(INFLATION_FEE, false), + }, + debt: Default::default(), + data: ArrayTrait::new().span() + } + ); + i += 1; }; @@ -589,6 +616,28 @@ mod DefaultExtensionCL { self.tokenization.create_v_token(pool_id, asset, v_token_name, v_token_symbol); ISingletonDispatcher { contract_address: self.singleton.read() }.set_asset_config(pool_id, asset_params); + + // burn inflation fee + let singleton = ISingletonDispatcher { contract_address: self.singleton.read() }; + let asset = IERC20Dispatcher { contract_address: asset }; + asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE); + asset.approve(singleton.contract_address, INFLATION_FEE); + singleton + .modify_position( + ModifyPositionParams { + pool_id, + collateral_asset: asset.contract_address, + debt_asset: Zeroable::zero(), + user: contract_address_const::<'ZERO'>(), + collateral: Amount { + amount_type: AmountType::Delta, + denomination: AmountDenomination::Assets, + value: i257_new(INFLATION_FEE, false), + }, + debt: Default::default(), + data: ArrayTrait::new().span() + } + ); } /// Sets the debt cap for a given asset in a pool diff --git a/src/extension/default_extension_po.cairo b/src/extension/default_extension_po.cairo index a695b6c..dbfe4ca 100644 --- a/src/extension/default_extension_po.cairo +++ b/src/extension/default_extension_po.cairo @@ -168,13 +168,18 @@ trait IDefaultExtension { #[starknet::contract] mod DefaultExtensionPO { - use alexandria_math::i257::i257; - use starknet::{ContractAddress, get_contract_address, get_caller_address, event::EventEmitter}; - use vesu::extension::components::position_hooks::position_hooks_component::Trait; + use alexandria_math::i257::{i257, i257_new}; + use starknet::{ + ContractAddress, get_contract_address, get_caller_address, event::EventEmitter, contract_address_const + }; use vesu::{ map_list::{map_list_component, map_list_component::MapListTrait}, - data_model::{Amount, UnsignedAmount, AssetParams, AssetPrice, LTVParams, Context, LTVConfig}, + data_model::{ + Amount, UnsignedAmount, AssetParams, AssetPrice, LTVParams, Context, LTVConfig, ModifyPositionParams, + AmountDenomination, AmountType + }, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, + vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, units::INFLATION_FEE, extension::{ default_extension_po::{ LiquidationParams, ShutdownParams, PragmaOracleParams, ITimestampManagerCallback, IDefaultExtension, @@ -536,8 +541,8 @@ mod DefaultExtensionPO { assert!(asset_params.len() == v_token_params.len(), "v-token-params-mismatch"); // create the pool in the singleton - let pool_id = ISingletonDispatcher { contract_address: self.singleton.read() } - .create_pool(asset_params, ltv_params, get_contract_address()); + let singleton = ISingletonDispatcher { contract_address: self.singleton.read() }; + let pool_id = singleton.create_pool(asset_params, ltv_params, get_contract_address()); // set the pool owner self.owner.write(pool_id, owner); @@ -564,6 +569,27 @@ mod DefaultExtensionPO { // deploy the vToken for the the collateral asset self.tokenization.create_v_token(pool_id, asset, v_token_name, v_token_symbol); + // burn inflation fee + let asset = IERC20Dispatcher { contract_address: asset }; + asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE); + asset.approve(singleton.contract_address, INFLATION_FEE); + singleton + .modify_position( + ModifyPositionParams { + pool_id, + collateral_asset: asset.contract_address, + debt_asset: Zeroable::zero(), + user: contract_address_const::<'ZERO'>(), + collateral: Amount { + amount_type: AmountType::Delta, + denomination: AmountDenomination::Assets, + value: i257_new(INFLATION_FEE, false), + }, + debt: Default::default(), + data: ArrayTrait::new().span() + } + ); + i += 1; }; @@ -652,6 +678,28 @@ mod DefaultExtensionPO { self.tokenization.create_v_token(pool_id, asset, v_token_name, v_token_symbol); ISingletonDispatcher { contract_address: self.singleton.read() }.set_asset_config(pool_id, asset_params); + + // burn inflation fee + let singleton = ISingletonDispatcher { contract_address: self.singleton.read() }; + let asset = IERC20Dispatcher { contract_address: asset }; + asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE); + asset.approve(singleton.contract_address, INFLATION_FEE); + singleton + .modify_position( + ModifyPositionParams { + pool_id, + collateral_asset: asset.contract_address, + debt_asset: Zeroable::zero(), + user: contract_address_const::<'ZERO'>(), + collateral: Amount { + amount_type: AmountType::Delta, + denomination: AmountDenomination::Assets, + value: i257_new(INFLATION_FEE, false), + }, + debt: Default::default(), + data: ArrayTrait::new().span() + } + ); } /// Sets the debt cap for a given asset in a pool diff --git a/src/test/setup.cairo b/src/test/setup.cairo index dd00169..c378430 100644 --- a/src/test/setup.cairo +++ b/src/test/setup.cairo @@ -1,10 +1,10 @@ use snforge_std::{ - declare, ContractClass, ContractClassTrait, start_prank, stop_prank, start_warp, stop_warp, CheatTarget, - get_class_hash + declare, ContractClass, ContractClassTrait, start_prank, stop_prank, start_warp, stop_warp, CheatTarget, prank, + CheatSpan, get_class_hash }; use starknet::{ContractAddress, contract_address_const, get_block_timestamp}; use vesu::{ - units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS}, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, + units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS, INFLATION_FEE}, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, data_model::{Amount, AmountDenomination, AmountType, ModifyPositionParams, AssetParams, LTVParams}, extension::interface::{IExtensionDispatcher, IExtensionDispatcherTrait}, extension::default_extension_po::{ @@ -156,6 +156,31 @@ fn setup_env( deploy_assets(users.lender) }; + // transfer 2x INFLATION_FEE to creator + start_prank(CheatTarget::One(collateral_asset.contract_address), users.lender); + collateral_asset.transfer(users.creator, INFLATION_FEE * 2); + stop_prank(CheatTarget::One(collateral_asset.contract_address)); + start_prank(CheatTarget::One(debt_asset.contract_address), users.lender); + debt_asset.transfer(users.creator, INFLATION_FEE * 2); + stop_prank(CheatTarget::One(debt_asset.contract_address)); + start_prank(CheatTarget::One(third_asset.contract_address), users.lender); + third_asset.transfer(users.creator, INFLATION_FEE * 2); + stop_prank(CheatTarget::One(third_asset.contract_address)); + + // approve Extension and ExtensionV2 to transfer assets on behalf of creator + start_prank(CheatTarget::One(collateral_asset.contract_address), users.creator); + collateral_asset.approve(extension.contract_address, integer::BoundedInt::max()); + collateral_asset.approve(extension_v2.contract_address, integer::BoundedInt::max()); + stop_prank(CheatTarget::One(collateral_asset.contract_address)); + start_prank(CheatTarget::One(debt_asset.contract_address), users.creator); + debt_asset.approve(extension.contract_address, integer::BoundedInt::max()); + debt_asset.approve(extension_v2.contract_address, integer::BoundedInt::max()); + stop_prank(CheatTarget::One(debt_asset.contract_address)); + start_prank(CheatTarget::One(third_asset.contract_address), users.creator); + third_asset.approve(extension.contract_address, integer::BoundedInt::max()); + third_asset.approve(extension_v2.contract_address, integer::BoundedInt::max()); + stop_prank(CheatTarget::One(third_asset.contract_address)); + // approve Singleton to transfer assets on behalf of lender start_prank(CheatTarget::One(debt_asset.contract_address), users.lender); debt_asset.approve(singleton.contract_address, integer::BoundedInt::max()); @@ -320,7 +345,7 @@ fn create_pool( recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension.contract_address), creator); + prank(CheatTarget::One(extension.contract_address), creator, CheatSpan::TargetCalls(1)); extension .create_pool( asset_params, @@ -470,7 +495,7 @@ fn create_pool_v2( recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension.contract_address), creator); + prank(CheatTarget::One(extension.contract_address), creator, CheatSpan::TargetCalls(1)); extension .create_pool( asset_params, @@ -554,141 +579,12 @@ fn setup_pool( stop_prank(CheatTarget::One(collateral_asset.contract_address)); } - // make first deposit into pool start_prank(CheatTarget::One(extension.contract_address), users.creator); extension.set_asset_parameter(pool_id, collateral_asset.contract_address, 'floor', 0); extension.set_asset_parameter(pool_id, debt_asset.contract_address, 'floor', 0); extension.set_asset_parameter(pool_id, third_asset.contract_address, 'floor', 0); stop_prank(CheatTarget::One(extension.contract_address)); - start_prank(CheatTarget::One(collateral_asset.contract_address), users.lender); - collateral_asset.transfer(users.seeder, 2000); - stop_prank(CheatTarget::One(collateral_asset.contract_address)); - start_prank(CheatTarget::One(debt_asset.contract_address), users.lender); - debt_asset.transfer(users.seeder, 2000); - stop_prank(CheatTarget::One(debt_asset.contract_address)); - start_prank(CheatTarget::One(third_asset.contract_address), users.lender); - third_asset.transfer(users.seeder, 2000); - stop_prank(CheatTarget::One(third_asset.contract_address)); - - let params = ModifyPositionParams { - pool_id, - collateral_asset: collateral_asset.contract_address, - debt_asset: debt_asset.contract_address, - user: users.seeder, - collateral: Amount { - amount_type: AmountType::Delta, denomination: AmountDenomination::Native, value: 1000.into(), - }, - debt: Default::default(), - data: ArrayTrait::new().span() - }; - start_prank(CheatTarget::One(collateral_asset.contract_address), users.seeder); - collateral_asset.approve(singleton.contract_address, 1000); - stop_prank(CheatTarget::One(collateral_asset.contract_address)); - - start_prank(CheatTarget::One(singleton.contract_address), users.seeder); - singleton.modify_position(params); - stop_prank(CheatTarget::One(singleton.contract_address)); - - let (position, _, _) = singleton - .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, Zeroable::zero()); - assert!(position.collateral_shares > 0, "Inflation fee not minted"); - - let params = ModifyPositionParams { - pool_id, - collateral_asset: collateral_asset.contract_address, - debt_asset: third_asset.contract_address, - user: users.seeder, - collateral: Amount { - amount_type: AmountType::Delta, denomination: AmountDenomination::Native, value: 1000.into(), - }, - debt: Default::default(), - data: ArrayTrait::new().span() - }; - start_prank(CheatTarget::One(third_asset.contract_address), users.seeder); - third_asset.approve(singleton.contract_address, 1000); - stop_prank(CheatTarget::One(third_asset.contract_address)); - - start_prank(CheatTarget::One(singleton.contract_address), users.seeder); - singleton.modify_position(params); - stop_prank(CheatTarget::One(singleton.contract_address)); - - let params = ModifyPositionParams { - pool_id, - collateral_asset: debt_asset.contract_address, - debt_asset: collateral_asset.contract_address, - user: users.seeder, - collateral: Amount { - amount_type: AmountType::Delta, denomination: AmountDenomination::Native, value: 1000.into(), - }, - debt: Default::default(), - data: ArrayTrait::new().span() - }; - start_prank(CheatTarget::One(debt_asset.contract_address), users.seeder); - debt_asset.approve(singleton.contract_address, 1000); - stop_prank(CheatTarget::One(debt_asset.contract_address)); - - start_prank(CheatTarget::One(singleton.contract_address), users.seeder); - singleton.modify_position(params); - stop_prank(CheatTarget::One(singleton.contract_address)); - - let params = ModifyPositionParams { - pool_id, - collateral_asset: debt_asset.contract_address, - debt_asset: third_asset.contract_address, - user: users.seeder, - collateral: Amount { - amount_type: AmountType::Delta, denomination: AmountDenomination::Native, value: 1000.into(), - }, - debt: Default::default(), - data: ArrayTrait::new().span() - }; - start_prank(CheatTarget::One(debt_asset.contract_address), users.seeder); - debt_asset.approve(singleton.contract_address, 1000); - stop_prank(CheatTarget::One(debt_asset.contract_address)); - - start_prank(CheatTarget::One(singleton.contract_address), users.seeder); - singleton.modify_position(params); - stop_prank(CheatTarget::One(singleton.contract_address)); - - let params = ModifyPositionParams { - pool_id, - collateral_asset: third_asset.contract_address, - debt_asset: collateral_asset.contract_address, - user: users.seeder, - collateral: Amount { - amount_type: AmountType::Delta, denomination: AmountDenomination::Native, value: 1000.into(), - }, - debt: Default::default(), - data: ArrayTrait::new().span() - }; - start_prank(CheatTarget::One(third_asset.contract_address), users.seeder); - third_asset.approve(singleton.contract_address, 1000); - stop_prank(CheatTarget::One(third_asset.contract_address)); - - start_prank(CheatTarget::One(singleton.contract_address), users.seeder); - singleton.modify_position(params); - stop_prank(CheatTarget::One(singleton.contract_address)); - - let params = ModifyPositionParams { - pool_id, - collateral_asset: third_asset.contract_address, - debt_asset: debt_asset.contract_address, - user: users.seeder, - collateral: Amount { - amount_type: AmountType::Delta, denomination: AmountDenomination::Native, value: 1000.into(), - }, - debt: Default::default(), - data: ArrayTrait::new().span() - }; - start_prank(CheatTarget::One(third_asset.contract_address), users.seeder); - third_asset.approve(singleton.contract_address, 1000); - stop_prank(CheatTarget::One(third_asset.contract_address)); - - start_prank(CheatTarget::One(singleton.contract_address), users.seeder); - singleton.modify_position(params); - stop_prank(CheatTarget::One(singleton.contract_address)); - start_prank(CheatTarget::One(extension.contract_address), users.creator); extension.set_asset_parameter(pool_id, collateral_asset.contract_address, 'floor', SCALE / 10_000); extension.set_asset_parameter(pool_id, debt_asset.contract_address, 'floor', SCALE / 10_000); diff --git a/src/test/test_asset_retrieval.cairo b/src/test/test_asset_retrieval.cairo index 9a4b712..e37e664 100644 --- a/src/test/test_asset_retrieval.cairo +++ b/src/test/test_asset_retrieval.cairo @@ -16,6 +16,7 @@ mod TestAssetRetrieval { let LendingTerms { liquidity_to_deposit, .. } = terms; let initial_lender_debt_asset_balance = debt_asset.balance_of(users.lender); + let pre_deposit_balance = debt_asset.balance_of(singleton.contract_address); // deposit collateral which is later borrowed by the borrower let params = ModifyPositionParams { @@ -38,10 +39,9 @@ mod TestAssetRetrieval { // check that liquidity has been deposited let pre_retrieval_balance = debt_asset.balance_of(singleton.contract_address); - assert!(pre_retrieval_balance - 2 == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(pre_retrieval_balance == pre_deposit_balance + liquidity_to_deposit, "Not transferred to Singleton"); // retrieve entire balance - start_prank(CheatTarget::One(singleton.contract_address), extension.contract_address); singleton.retrieve_from_reserve(pool_id, debt_asset.contract_address, users.lender, pre_retrieval_balance); stop_prank(CheatTarget::One(singleton.contract_address)); @@ -50,8 +50,10 @@ mod TestAssetRetrieval { let post_retrieval_user_balance = debt_asset.balance_of(users.lender); assert!(post_retrieval_balance == 0, "Asset not transferred out of the Singleton"); + println!("post_retrieval_user_balance: {}", post_retrieval_user_balance); + println!("initial_lender_debt_asset_balance: {}", initial_lender_debt_asset_balance); assert!( - post_retrieval_user_balance - 2 == initial_lender_debt_asset_balance, "Asset not transferred to the user" + post_retrieval_user_balance == initial_lender_debt_asset_balance, "Asset not transferred to the user" ); let (asset_config, _) = singleton.asset_config(pool_id, debt_asset.contract_address); @@ -87,10 +89,10 @@ mod TestAssetRetrieval { // check that liquidity has been deposited let pre_retrieval_balance = debt_asset.balance_of(singleton.contract_address); - assert!(pre_retrieval_balance - 2 == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(pre_retrieval_balance == liquidity_to_deposit, "Not transferred to Singleton"); let (asset_config_pre_retrieval, _) = singleton.asset_config(pool_id, debt_asset.contract_address); - assert!(asset_config_pre_retrieval.reserve - 2 == liquidity_to_deposit, "Reserve not updated"); + assert!(asset_config_pre_retrieval.reserve == liquidity_to_deposit, "Reserve not updated"); // retrieve % of total balance let amount_to_retrieve = pre_retrieval_balance / 2; @@ -106,7 +108,7 @@ mod TestAssetRetrieval { "Asset not transferred out of the Singleton" ); assert!( - post_retrieval_user_balance - 2 == initial_lender_debt_asset_balance - amount_to_retrieve, + post_retrieval_user_balance == initial_lender_debt_asset_balance - amount_to_retrieve, "Asset not transferred to the user" ); @@ -216,7 +218,7 @@ mod TestAssetRetrieval { // check that liquidity has been deposited let pre_retrieval_balance = debt_asset.balance_of(singleton.contract_address); - assert!(pre_retrieval_balance - 2 == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(pre_retrieval_balance == liquidity_to_deposit, "Not transferred to Singleton"); let incorrect_caller = contract_address_const::<'incorrect_caller'>(); diff --git a/src/test/test_default_extension_cl.cairo b/src/test/test_default_extension_cl.cairo index 02d606d..1b36a8d 100644 --- a/src/test/test_default_extension_cl.cairo +++ b/src/test/test_default_extension_cl.cairo @@ -1,11 +1,12 @@ #[cfg(test)] mod TestDefaultExtensionCL { - use snforge_std::{start_prank, stop_prank, CheatTarget, get_class_hash, ContractClass, declare}; - use starknet::{get_contract_address, contract_address_const, get_block_number}; + use snforge_std::{start_prank, stop_prank, CheatTarget, get_class_hash, ContractClass, declare, prank, CheatSpan}; + use starknet::{get_contract_address, contract_address_const, get_block_number, get_caller_address}; use vesu::{ - units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS}, + units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS, INFLATION_FEE}, test::setup::{setup_env, create_pool, create_pool_v2, TestConfig, deploy_assets, deploy_asset, Env}, - singleton::{ISingletonDispatcherTrait}, data_model::{AssetParams, LTVParams, LTVConfig}, + vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, + singleton::{ISingletonDispatcherTrait}, data_model::{AssetParams, LTVParams, LTVConfig, ModifyPositionParams}, extension::default_extension_po::{ InterestRateConfig, LiquidationParams, ShutdownParams, FeeParams, VTokenParams, LiquidationConfig, ShutdownConfig, FeeConfig @@ -72,7 +73,7 @@ mod TestDefaultExtensionCL { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); + prank(CheatTarget::One(extension_v2.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v2 .create_pool( asset_params, @@ -118,7 +119,11 @@ mod TestDefaultExtensionCL { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension_v2.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension_v2.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v2 .create_pool( asset_params, @@ -164,7 +169,11 @@ mod TestDefaultExtensionCL { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension_v2.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension_v2.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v2 .create_pool( asset_params, @@ -210,7 +219,11 @@ mod TestDefaultExtensionCL { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension_v2.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension_v2.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v2 .create_pool( asset_params, @@ -304,7 +317,11 @@ mod TestDefaultExtensionCL { let chainlink_oracle_params = ChainlinkOracleParams { aggregator: Zeroable::zero(), timeout: 1 }; - start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension_v2.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension_v2.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v2 .add_asset( config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params, 0 @@ -350,7 +367,11 @@ mod TestDefaultExtensionCL { let chainlink_oracle_params = ChainlinkOracleParams { aggregator: Zeroable::zero(), timeout: 1 }; - start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); + start_prank(CheatTarget::One(asset.contract_address), users.creator); + asset.approve(extension_v2.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(asset.contract_address)); + + prank(CheatTarget::One(extension_v2.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v2 .add_asset( config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params, 0 @@ -359,7 +380,7 @@ mod TestDefaultExtensionCL { } #[test] - fn test_add_asset() { + fn test_add_asset_cl() { let Env { singleton, extension_v2, config, users, .. } = setup_env( Zeroable::zero(), Zeroable::zero(), Zeroable::zero(), Zeroable::zero() ); @@ -393,11 +414,17 @@ mod TestDefaultExtensionCL { target_rate_percent: 20 * PERCENT, }; + let chainlink_oracle_config = extension_v2 + .chainlink_oracle_config(config.pool_id_v2, config.collateral_asset.contract_address); let chainlink_oracle_params = ChainlinkOracleParams { - aggregator: contract_address_const::<'aggregator'>(), timeout: 1 + aggregator: chainlink_oracle_config.aggregator, timeout: 1 }; - start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); + start_prank(CheatTarget::One(asset.contract_address), users.creator); + asset.approve(extension_v2.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(asset.contract_address)); + + prank(CheatTarget::One(extension_v2.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v2 .add_asset( config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params, 0 diff --git a/src/test/test_default_extension_po.cairo b/src/test/test_default_extension_po.cairo index 0b31fb1..62670ac 100644 --- a/src/test/test_default_extension_po.cairo +++ b/src/test/test_default_extension_po.cairo @@ -1,10 +1,11 @@ #[cfg(test)] mod TestDefaultExtensionPO { - use snforge_std::{start_prank, stop_prank, CheatTarget, get_class_hash, ContractClass, declare}; + use snforge_std::{start_prank, stop_prank, CheatTarget, get_class_hash, ContractClass, declare, prank, CheatSpan}; use starknet::get_contract_address; use vesu::{ - units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS}, + units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS, INFLATION_FEE}, test::setup::{setup_env, create_pool, TestConfig, deploy_assets, deploy_asset, Env}, + vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, singleton::{ISingletonDispatcherTrait}, data_model::{AssetParams, LTVParams, LTVConfig}, extension::default_extension_po::{ InterestRateConfig, PragmaOracleParams, LiquidationParams, IDefaultExtensionDispatcherTrait, ShutdownParams, @@ -62,7 +63,7 @@ mod TestDefaultExtensionPO { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension.contract_address), users.creator); + prank(CheatTarget::One(extension.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension .create_pool( asset_params, @@ -108,7 +109,11 @@ mod TestDefaultExtensionPO { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension .create_pool( asset_params, @@ -154,7 +159,11 @@ mod TestDefaultExtensionPO { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension .create_pool( asset_params, @@ -202,7 +211,11 @@ mod TestDefaultExtensionPO { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension .create_pool( asset_params, @@ -294,7 +307,11 @@ mod TestDefaultExtensionPO { let pragma_oracle_params = PragmaOracleParams { pragma_key: COLL_PRAGMA_KEY, timeout: 1, number_of_sources: 2 }; - start_prank(CheatTarget::One(extension.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension .add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params, 0); stop_prank(CheatTarget::One(extension.contract_address)); @@ -340,14 +357,18 @@ mod TestDefaultExtensionPO { pragma_key: Zeroable::zero(), timeout: 1, number_of_sources: 2 }; - start_prank(CheatTarget::One(extension.contract_address), users.creator); + start_prank(CheatTarget::One(asset.contract_address), users.creator); + asset.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(asset.contract_address)); + + prank(CheatTarget::One(extension.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension .add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params, 0); stop_prank(CheatTarget::One(extension.contract_address)); } #[test] - fn test_add_asset() { + fn test_add_asset_po() { let Env { singleton, extension, config, users, .. } = setup_env( Zeroable::zero(), Zeroable::zero(), Zeroable::zero(), Zeroable::zero() ); @@ -383,7 +404,11 @@ mod TestDefaultExtensionPO { let pragma_oracle_params = PragmaOracleParams { pragma_key: COLL_PRAGMA_KEY, timeout: 1, number_of_sources: 2 }; - start_prank(CheatTarget::One(extension.contract_address), users.creator); + start_prank(CheatTarget::One(asset.contract_address), users.creator); + asset.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(asset.contract_address)); + + prank(CheatTarget::One(extension.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension .add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params, 0); stop_prank(CheatTarget::One(extension.contract_address)); diff --git a/src/test/test_flash_loan.cairo b/src/test/test_flash_loan.cairo index a909714..66dd3ab 100644 --- a/src/test/test_flash_loan.cairo +++ b/src/test/test_flash_loan.cairo @@ -103,7 +103,7 @@ mod FlashLoans { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance - 2 == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(balance == liquidity_to_deposit, "Not transferred to Singleton"); let flash_loan_amount = (balance / 2); @@ -178,7 +178,7 @@ mod FlashLoans { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance - 2 == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(balance == liquidity_to_deposit, "Not transferred to Singleton"); // entire balance of the pool let flash_loan_amount = balance; @@ -248,7 +248,7 @@ mod FlashLoans { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance - 2 == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(balance == liquidity_to_deposit, "Not transferred to Singleton"); // entire balance of the pool let flash_loan_amount = balance; diff --git a/src/test/test_modify_position.cairo b/src/test/test_modify_position.cairo index 7f97b4d..bf84c87 100644 --- a/src/test/test_modify_position.cairo +++ b/src/test/test_modify_position.cairo @@ -1221,7 +1221,7 @@ mod TestModifyPosition { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance - 2 == liquidity_to_deposit, "Not transferred to Singleton"); // 2 due to inflation mitigation + assert!(balance == liquidity_to_deposit, "Not transferred to Singleton"); // 2 due to inflation mitigation let (position, collateral, debt) = singleton .position(pool_id, debt_asset.contract_address, collateral_asset.contract_address, users.lender); @@ -1264,21 +1264,21 @@ mod TestModifyPosition { "Not transferred from borrower" ); let balance = collateral_asset.balance_of(singleton.contract_address); - assert!(balance - 2 == collateral_to_deposit, "Not transferred to Singleton"); + assert!(balance == collateral_to_deposit, "Not transferred to Singleton"); // debt asset has been transferred from the singleton to the borrower let balance = debt_asset.balance_of(users.borrower); assert!(balance == initial_borrower_debt_asset_balance + debt_to_draw, "Debt asset not transferred"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance - 2 == liquidity_to_deposit - debt_to_draw, "Debt asset not transferred"); + assert!(balance == liquidity_to_deposit - debt_to_draw, "Debt asset not transferred"); // collateral asset reserve has been updated let (asset_config, _) = singleton.asset_config(pool_id, collateral_asset.contract_address); - assert!(asset_config.reserve - 2 == collateral_to_deposit, "Collateral not in reserve"); + assert!(asset_config.reserve == collateral_to_deposit, "Collateral not in reserve"); // debt asset reserve has been updated let (asset_config, _) = singleton.asset_config(pool_id, debt_asset.contract_address); - assert!(asset_config.reserve - 2 == liquidity_to_deposit - debt_to_draw, "Debt not taken from reserve"); + assert!(asset_config.reserve == liquidity_to_deposit - debt_to_draw, "Debt not taken from reserve"); // position's collateral balance has been updated let (position, collateral, debt) = singleton diff --git a/src/test/test_pool_donations.cairo b/src/test/test_pool_donations.cairo index 861612c..6e28028 100644 --- a/src/test/test_pool_donations.cairo +++ b/src/test/test_pool_donations.cairo @@ -51,7 +51,7 @@ mod TestPoolDonation { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance - 2 == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(balance == liquidity_to_deposit, "Not transferred to Singleton"); let (old_position, collateral, _) = singleton .position(pool_id, debt_asset.contract_address, collateral_asset.contract_address, users.lender); diff --git a/src/units.cairo b/src/units.cairo index 1295864..83681f1 100644 --- a/src/units.cairo +++ b/src/units.cairo @@ -5,3 +5,5 @@ const FRACTION: u256 = 10_000_000_000_000; // 1e13 const YEAR_IN_SECONDS: u256 = consteval_int!(360 * 24 * 60 * 60); const DAY_IN_SECONDS: u64 = consteval_int!(24 * 60 * 60); const INFLATION_FEE_SHARES: u256 = 1000; +// has to be greater than INFLATION_FEE_SHARES such that total_collateral_shares is not reset to 0 +const INFLATION_FEE: u256 = 2000; From ddd44ad54610d2e4dd6930d094fd7951be66c54c Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Fri, 8 Nov 2024 14:54:25 +0000 Subject: [PATCH 05/32] Push progress II --- Scarb.toml | 3 +- src/extension/default_extension_cl.cairo | 3 +- src/test/setup.cairo | 3 +- src/test/test_asset_retrieval.cairo | 21 ++-- src/test/test_flash_loan.cairo | 17 +-- src/test/test_forking.cairo | 133 +++++++++++++++++------ src/test/test_modify_position.cairo | 51 +++++++-- 7 files changed, 164 insertions(+), 67 deletions(-) diff --git a/Scarb.toml b/Scarb.toml index b3d6c0c..364f540 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -40,4 +40,5 @@ deploySepolia = "scarb --profile release build && node --loader ts-node/esm ./sc deployTimelock = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployTimelock.ts" checkGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --check" updateGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --write" -test = "snforge test" +# test = "snforge test" +test = "snforge test 'test_fuzz_modify_position_borrow_repay_debt'" diff --git a/src/extension/default_extension_cl.cairo b/src/extension/default_extension_cl.cairo index 2fa1e0d..abb14a9 100644 --- a/src/extension/default_extension_cl.cairo +++ b/src/extension/default_extension_cl.cairo @@ -127,8 +127,7 @@ mod DefaultExtensionCL { AmountDenomination, AmountType }, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, - vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, - units::INFLATION_FEE, + vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, units::INFLATION_FEE, extension::{ default_extension_po::{ LiquidationParams, ShutdownParams, ITimestampManagerCallback, FeeParams, VTokenParams, diff --git a/src/test/setup.cairo b/src/test/setup.cairo index c378430..d1a7e0a 100644 --- a/src/test/setup.cairo +++ b/src/test/setup.cairo @@ -4,7 +4,8 @@ use snforge_std::{ }; use starknet::{ContractAddress, contract_address_const, get_block_timestamp}; use vesu::{ - units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS, INFLATION_FEE}, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, + units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS, INFLATION_FEE}, + singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, data_model::{Amount, AmountDenomination, AmountType, ModifyPositionParams, AssetParams, LTVParams}, extension::interface::{IExtensionDispatcher, IExtensionDispatcherTrait}, extension::default_extension_po::{ diff --git a/src/test/test_asset_retrieval.cairo b/src/test/test_asset_retrieval.cairo index e37e664..8936fc1 100644 --- a/src/test/test_asset_retrieval.cairo +++ b/src/test/test_asset_retrieval.cairo @@ -49,11 +49,9 @@ mod TestAssetRetrieval { let post_retrieval_balance = debt_asset.balance_of(singleton.contract_address); let post_retrieval_user_balance = debt_asset.balance_of(users.lender); assert!(post_retrieval_balance == 0, "Asset not transferred out of the Singleton"); - - println!("post_retrieval_user_balance: {}", post_retrieval_user_balance); - println!("initial_lender_debt_asset_balance: {}", initial_lender_debt_asset_balance); assert!( - post_retrieval_user_balance == initial_lender_debt_asset_balance, "Asset not transferred to the user" + post_retrieval_user_balance - pre_deposit_balance == initial_lender_debt_asset_balance, + "Asset not transferred to the user" ); let (asset_config, _) = singleton.asset_config(pool_id, debt_asset.contract_address); @@ -67,6 +65,9 @@ mod TestAssetRetrieval { let LendingTerms { liquidity_to_deposit, .. } = terms; let initial_lender_debt_asset_balance = debt_asset.balance_of(users.lender); + let pre_deposit_balance = debt_asset.balance_of(singleton.contract_address); + let (asset_config, _) = singleton.asset_config(pool_id, debt_asset.contract_address); + let pre_deposit_reserve = asset_config.reserve; // deposit collateral which is later borrowed by the borrower let params = ModifyPositionParams { @@ -89,10 +90,12 @@ mod TestAssetRetrieval { // check that liquidity has been deposited let pre_retrieval_balance = debt_asset.balance_of(singleton.contract_address); - assert!(pre_retrieval_balance == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(pre_retrieval_balance == pre_deposit_balance + liquidity_to_deposit, "Not transferred to Singleton"); let (asset_config_pre_retrieval, _) = singleton.asset_config(pool_id, debt_asset.contract_address); - assert!(asset_config_pre_retrieval.reserve == liquidity_to_deposit, "Reserve not updated"); + assert!( + asset_config_pre_retrieval.reserve == pre_deposit_reserve + liquidity_to_deposit, "Reserve not updated" + ); // retrieve % of total balance let amount_to_retrieve = pre_retrieval_balance / 2; @@ -108,7 +111,7 @@ mod TestAssetRetrieval { "Asset not transferred out of the Singleton" ); assert!( - post_retrieval_user_balance == initial_lender_debt_asset_balance - amount_to_retrieve, + post_retrieval_user_balance - pre_deposit_balance == initial_lender_debt_asset_balance - amount_to_retrieve, "Asset not transferred to the user" ); @@ -197,6 +200,8 @@ mod TestAssetRetrieval { let TestConfig { pool_id, collateral_asset, debt_asset, .. } = config; let LendingTerms { liquidity_to_deposit, .. } = terms; + let pre_deposit_balance = debt_asset.balance_of(singleton.contract_address); + // deposit collateral which is later borrowed by the borrower let params = ModifyPositionParams { pool_id, @@ -218,7 +223,7 @@ mod TestAssetRetrieval { // check that liquidity has been deposited let pre_retrieval_balance = debt_asset.balance_of(singleton.contract_address); - assert!(pre_retrieval_balance == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(pre_retrieval_balance == pre_deposit_balance + liquidity_to_deposit, "Not transferred to Singleton"); let incorrect_caller = contract_address_const::<'incorrect_caller'>(); diff --git a/src/test/test_flash_loan.cairo b/src/test/test_flash_loan.cairo index 66dd3ab..02e3274 100644 --- a/src/test/test_flash_loan.cairo +++ b/src/test/test_flash_loan.cairo @@ -72,13 +72,11 @@ mod FlashLoans { let LendingTerms { liquidity_to_deposit, .. } = terms; let flash_loan_receiver_add = deploy_contract("FlashLoanreceiver"); - let flashloan_receiver = IFlashloanReceiverDispatcher { contract_address: flash_loan_receiver_add }; - let flashloan_receiver_view = IFlashLoanGenericDispatcher { contract_address: flash_loan_receiver_add }; let initial_lender_debt_asset_balance = debt_asset.balance_of(users.lender); - + let pre_deposit_balance = debt_asset.balance_of(singleton.contract_address); // deposit debt asset that will be used in flash loan let params = ModifyPositionParams { pool_id, @@ -103,7 +101,7 @@ mod FlashLoans { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(balance == pre_deposit_balance + liquidity_to_deposit, "Not transferred to Singleton"); let flash_loan_amount = (balance / 2); @@ -147,13 +145,11 @@ mod FlashLoans { let LendingTerms { liquidity_to_deposit, .. } = terms; let flash_loan_receiver_add = deploy_contract("FlashLoanreceiver"); - let flashloan_receiver = IFlashloanReceiverDispatcher { contract_address: flash_loan_receiver_add }; - let flashloan_receiver_view = IFlashLoanGenericDispatcher { contract_address: flash_loan_receiver_add }; let initial_lender_debt_asset_balance = debt_asset.balance_of(users.lender); - + let pre_deposit_balance = debt_asset.balance_of(singleton.contract_address); // deposit debt asset that will be used in flash loan let params = ModifyPositionParams { pool_id, @@ -178,7 +174,7 @@ mod FlashLoans { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(balance == pre_deposit_balance + liquidity_to_deposit, "Not transferred to Singleton"); // entire balance of the pool let flash_loan_amount = balance; @@ -217,13 +213,12 @@ mod FlashLoans { let LendingTerms { liquidity_to_deposit, .. } = terms; let malicious_flash_loan_receiver_add = deploy_contract("MaliciousFlashLoanReceiver"); - let malicious_flashloan_receiver = IFlashloanReceiverDispatcher { contract_address: malicious_flash_loan_receiver_add }; let initial_lender_debt_asset_balance = debt_asset.balance_of(users.lender); - + let pre_deposit_balance = debt_asset.balance_of(singleton.contract_address); // deposit debt asset that will be used in flash loan let params = ModifyPositionParams { pool_id, @@ -248,7 +243,7 @@ mod FlashLoans { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(balance == pre_deposit_balance + liquidity_to_deposit, "Not transferred to Singleton"); // entire balance of the pool let flash_loan_amount = balance; diff --git a/src/test/test_forking.cairo b/src/test/test_forking.cairo index 94aff35..989b3b3 100644 --- a/src/test/test_forking.cairo +++ b/src/test/test_forking.cairo @@ -12,7 +12,7 @@ fn to_percent(value: u256) -> u64 { #[cfg(test)] mod TestForking { - use snforge_std::{start_prank, stop_prank, CheatTarget, store, load, map_entry_address, declare, start_warp}; + use snforge_std::{start_prank, stop_prank, CheatTarget, store, load, map_entry_address, declare, start_warp, prank, CheatSpan}; use starknet::{ contract_address_const, get_caller_address, get_contract_address, ContractAddress, get_block_timestamp, get_block_number @@ -39,7 +39,7 @@ mod TestForking { }, components::position_hooks::LiquidationData }, - units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS}, + units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS, INFLATION_FEE}, data_model::{AssetParams, LTVParams, ModifyPositionParams, Amount, AmountType, AmountDenomination, AssetPrice}, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait, LiquidatePositionParams}, }; @@ -438,38 +438,8 @@ mod TestForking { ) }; - let creator = get_caller_address(); - let pool_id = singleton.calculate_pool_id(extension.contract_address, 1); - - extension - .create_pool( - asset_params, - v_token_params, - max_ltv_params, - interest_rate_configs, - oracle_params, - liquidation_params, - shutdown_params, - FeeParams { fee_recipient: creator }, - creator - ); - - start_warp(CheatTarget::All, get_block_timestamp() + DAY_IN_SECONDS * 30); - - let mut i = 0; - loop { - match asset_params.get(i) { - Option::Some(boxed_asset_params) => { - let mut asset_params = *boxed_asset_params.unbox(); - let price = IExtensionDispatcher { contract_address: extension.contract_address } - .price(pool_id, asset_params.asset); - assert!(price.value > 0, "No data"); - }, - Option::None(_) => { break; } - }; - i += 1; - }; - + // get funds + let creator = contract_address_const::<'creator'>(); let supplier = contract_address_const::<'supplier'>(); let borrower = contract_address_const::<'borrower'>(); let liquidator = contract_address_const::<'liquidator'>(); @@ -489,7 +459,25 @@ mod TestForking { .permissioned_mint(borrower, borrow_amount_eth * 2); IStarkgateERC20Dispatcher { contract_address: eth_asset_params.asset } .permissioned_mint(liquidator, borrow_amount_eth); + IStarkgateERC20Dispatcher { contract_address: eth_asset_params.asset } + .permissioned_mint(creator, INFLATION_FEE); stop_prank(CheatTarget::One(eth_asset_params.asset)); + start_prank(CheatTarget::One(eth.contract_address), creator); + eth.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(eth.contract_address)); + + let btc_asset_params: AssetParams = *asset_params[1]; + let btc = ERC20ABIDispatcher { contract_address: btc_asset_params.asset }; + let loaded = load(btc_asset_params.asset, selector!("permitted_minter"), 1); + let minter: ContractAddress = (*loaded[0]).try_into().unwrap(); + start_prank(CheatTarget::One(btc_asset_params.asset), minter); + IStarkgateERC20Dispatcher { contract_address: btc_asset_params.asset } + .permissioned_mint(creator, INFLATION_FEE); + stop_prank(CheatTarget::One(btc_asset_params.asset)); + start_prank(CheatTarget::One(btc.contract_address), creator); + btc.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(btc.contract_address)); + let usdc_asset_params: AssetParams = *asset_params[2]; let usdc = ERC20ABIDispatcher { contract_address: usdc_asset_params.asset }; @@ -500,7 +488,81 @@ mod TestForking { .permissioned_mint(supplier, supply_amount_usdc); IStarkgateERC20Dispatcher { contract_address: usdc_asset_params.asset } .permissioned_mint(borrower, borrow_amount_usdc); + IStarkgateERC20Dispatcher { contract_address: usdc_asset_params.asset } + .permissioned_mint(creator, INFLATION_FEE); stop_prank(CheatTarget::One(usdc_asset_params.asset)); + start_prank(CheatTarget::One(usdc.contract_address), creator); + usdc.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(usdc.contract_address)); + + let usdt_asset_params: AssetParams = *asset_params[3]; + let usdt = ERC20ABIDispatcher { contract_address: usdt_asset_params.asset }; + let loaded = load(usdt_asset_params.asset, selector!("permitted_minter"), 1); + let minter: ContractAddress = (*loaded[0]).try_into().unwrap(); + start_prank(CheatTarget::One(usdt_asset_params.asset), minter); + IStarkgateERC20Dispatcher { contract_address: usdt_asset_params.asset } + .permissioned_mint(creator, INFLATION_FEE); + stop_prank(CheatTarget::One(usdt_asset_params.asset)); + start_prank(CheatTarget::One(usdt.contract_address), creator); + usdt.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(usdt.contract_address)); + + let strk_asset_params: AssetParams = *asset_params[4]; + let strk = ERC20ABIDispatcher { contract_address: strk_asset_params.asset }; + let loaded = load(strk_asset_params.asset, selector!("permitted_minter"), 1); + let minter: ContractAddress = (*loaded[0]).try_into().unwrap(); + start_prank(CheatTarget::One(strk_asset_params.asset), minter); + IStarkgateERC20Dispatcher { contract_address: strk_asset_params.asset } + .permissioned_mint(creator, INFLATION_FEE); + stop_prank(CheatTarget::One(strk_asset_params.asset)); + start_prank(CheatTarget::One(strk.contract_address), creator); + strk.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(strk.contract_address)); + + let wsteth_asset_params: AssetParams = *asset_params[5]; + let wsteth = ERC20ABIDispatcher { contract_address: wsteth_asset_params.asset }; + let loaded = load(wsteth_asset_params.asset, selector!("permitted_minter"), 1); + let minter: ContractAddress = (*loaded[0]).try_into().unwrap(); + start_prank(CheatTarget::One(wsteth_asset_params.asset), minter); + IStarkgateERC20Dispatcher { contract_address: wsteth_asset_params.asset } + .permissioned_mint(creator, INFLATION_FEE); + stop_prank(CheatTarget::One(wsteth_asset_params.asset)); + start_prank(CheatTarget::One(wsteth.contract_address), creator); + wsteth.approve(extension.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(wsteth.contract_address)); + + let pool_id = singleton.calculate_pool_id(extension.contract_address, 1); + + prank(CheatTarget::One(extension.contract_address), creator, CheatSpan::TargetCalls(1)); + extension + .create_pool( + asset_params, + v_token_params, + max_ltv_params, + interest_rate_configs, + oracle_params, + liquidation_params, + shutdown_params, + FeeParams { fee_recipient: creator }, + creator + ); + stop_prank(CheatTarget::One(extension.contract_address)); + + start_warp(CheatTarget::All, get_block_timestamp() + DAY_IN_SECONDS * 30); + + let mut i = 0; + loop { + match asset_params.get(i) { + Option::Some(boxed_asset_params) => { + let mut asset_params = *boxed_asset_params.unbox(); + let price = IExtensionDispatcher { contract_address: extension.contract_address } + .price(pool_id, asset_params.asset); + assert!(price.value > 0, "No data"); + }, + Option::None(_) => { break; } + }; + i += 1; + }; SetupParams { singleton, @@ -795,7 +857,7 @@ mod TestForking { } #[test] - #[available_gas(2000000)] + #[available_gas(3000000)] #[fork("Mainnet")] fn test_fork_modify_position() { let params = setup(); @@ -916,6 +978,7 @@ mod TestForking { data: ArrayTrait::new().span() }; + // prank(CheatTarget::One(singleton.contract_address), borrower, CheatSpan::TargetCalls(1)); start_prank(CheatTarget::One(singleton.contract_address), borrower); singleton.modify_position(params); stop_prank(CheatTarget::One(singleton.contract_address)); diff --git a/src/test/test_modify_position.cairo b/src/test/test_modify_position.cairo index bf84c87..de75ae0 100644 --- a/src/test/test_modify_position.cairo +++ b/src/test/test_modify_position.cairo @@ -510,8 +510,8 @@ mod TestModifyPosition { start_prank(CheatTarget::One(singleton.contract_address), users.lender); // restrict values slightly to avoid overflow due to inflation mitigation deposit - let amount: u256 = if seed > 10000 { - seed.into() - 10000 + let amount: u256 = if seed > 20000000000000 { + seed.into() - 20000000000000 } else { seed.into() }; @@ -658,11 +658,13 @@ mod TestModifyPosition { #[test] #[fuzzer(runs: 256, seed: 100)] - fn test_fuzz_modify_position_borrow_repay_debt(seed: u128) { + // fn test_fuzz_modify_position_borrow_repay_debt(seed: u128) { + fn test_fuzz_modify_position_borrow_repay_debt() { + let seed: u128 = 49160906480394477896903869124991585048; let (singleton, _, config, users, _) = setup(); let TestConfig { pool_id, collateral_asset, debt_asset, debt_scale, .. } = config; - let amount: u256 = seed.into() / 10000; + let amount: u256 = seed.into() / 20000000000000; let collateral_amount = singleton .calculate_collateral(pool_id, collateral_asset.contract_address, amount.into()); let debt_amount = singleton.calculate_debt(amount.into(), SCALE, debt_scale); @@ -677,6 +679,8 @@ mod TestModifyPosition { // compensate for rounding up calculation of repayment amount (in two places) IMintableDispatcher { contract_address: debt_asset.contract_address }.mint(users.borrower, debt_amount + 2); + println!("A"); + // Add liquidity let params = ModifyPositionParams { @@ -693,6 +697,8 @@ mod TestModifyPosition { singleton.modify_position(params); + println!("B"); + // Delta, Native let params = ModifyPositionParams { @@ -711,6 +717,8 @@ mod TestModifyPosition { singleton.modify_position(params); + println!("C"); + let params = ModifyPositionParams { pool_id, collateral_asset: collateral_asset.contract_address, @@ -727,6 +735,16 @@ mod TestModifyPosition { singleton.modify_position(params); + println!("D"); + + println!("collateral_amount: {}", collateral_amount); + println!("debt_amount: {}", debt_amount); + + let (_, collateral, debt) = singleton + .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, users.borrower); + println!("collateral: {}", collateral); + println!("debt: {}", debt); + // Delta, Assets let params = ModifyPositionParams { @@ -747,6 +765,8 @@ mod TestModifyPosition { singleton.modify_position(params); + println!("E"); + let params = ModifyPositionParams { pool_id, collateral_asset: collateral_asset.contract_address, @@ -765,6 +785,8 @@ mod TestModifyPosition { singleton.modify_position(params); + println!("F"); + let collateral_shares = singleton .calculate_collateral_shares(pool_id, collateral_asset.contract_address, collateral_amount.into()); @@ -790,6 +812,8 @@ mod TestModifyPosition { singleton.modify_position(params); + println!("G"); + let params = ModifyPositionParams { pool_id, collateral_asset: collateral_asset.contract_address, @@ -806,6 +830,8 @@ mod TestModifyPosition { singleton.modify_position(params); + println!("H"); + // Target, Assets let params = ModifyPositionParams { @@ -826,6 +852,8 @@ mod TestModifyPosition { singleton.modify_position(params); + println!("I"); + let params = ModifyPositionParams { pool_id, collateral_asset: collateral_asset.contract_address, @@ -842,6 +870,8 @@ mod TestModifyPosition { singleton.modify_position(params); + println!("J"); + let (position, _, _) = singleton .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, users.lender); assert(position.collateral_shares == 0 && position.nominal_debt == 0, 'Position not zero'); @@ -1194,6 +1224,7 @@ mod TestModifyPosition { let initial_lender_debt_asset_balance = debt_asset.balance_of(users.lender); let initial_borrower_collateral_asset_balance = collateral_asset.balance_of(users.borrower); let initial_borrower_debt_asset_balance = debt_asset.balance_of(users.borrower); + let initial_singleton_debt_asset_balance = debt_asset.balance_of(singleton.contract_address); // LENDER @@ -1221,7 +1252,7 @@ mod TestModifyPosition { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance == liquidity_to_deposit, "Not transferred to Singleton"); // 2 due to inflation mitigation + assert!(balance == initial_singleton_debt_asset_balance + liquidity_to_deposit, "Not transferred to Singleton"); // 2 due to inflation mitigation let (position, collateral, debt) = singleton .position(pool_id, debt_asset.contract_address, collateral_asset.contract_address, users.lender); @@ -1232,6 +1263,8 @@ mod TestModifyPosition { // BORROWER + let initial_singleton_collateral_asset_balance = collateral_asset.balance_of(singleton.contract_address); + // deposit collateral and debt assets let params = ModifyPositionParams { pool_id, @@ -1264,21 +1297,21 @@ mod TestModifyPosition { "Not transferred from borrower" ); let balance = collateral_asset.balance_of(singleton.contract_address); - assert!(balance == collateral_to_deposit, "Not transferred to Singleton"); + assert!(balance == initial_singleton_collateral_asset_balance + collateral_to_deposit, "Not transferred to Singleton"); // debt asset has been transferred from the singleton to the borrower let balance = debt_asset.balance_of(users.borrower); assert!(balance == initial_borrower_debt_asset_balance + debt_to_draw, "Debt asset not transferred"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance == liquidity_to_deposit - debt_to_draw, "Debt asset not transferred"); + assert!(balance == initial_singleton_debt_asset_balance + liquidity_to_deposit - debt_to_draw, "Debt asset not transferred"); // collateral asset reserve has been updated let (asset_config, _) = singleton.asset_config(pool_id, collateral_asset.contract_address); - assert!(asset_config.reserve == collateral_to_deposit, "Collateral not in reserve"); + assert!(asset_config.reserve == initial_singleton_collateral_asset_balance + collateral_to_deposit, "Collateral not in reserve"); // debt asset reserve has been updated let (asset_config, _) = singleton.asset_config(pool_id, debt_asset.contract_address); - assert!(asset_config.reserve == liquidity_to_deposit - debt_to_draw, "Debt not taken from reserve"); + assert!(asset_config.reserve == initial_singleton_debt_asset_balance + liquidity_to_deposit - debt_to_draw, "Debt not taken from reserve"); // position's collateral balance has been updated let (position, collateral, debt) = singleton From b1bb6fda1be2eecf758fd4138cf20302cdc9c45e Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Fri, 8 Nov 2024 17:09:18 +0000 Subject: [PATCH 06/32] Push progress III --- Scarb.toml | 3 +-- src/test/test_modify_position.cairo | 10 ++++------ src/test/test_pool_donations.cairo | 4 +++- src/test/test_pragma_oracle.cairo | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Scarb.toml b/Scarb.toml index 364f540..b3d6c0c 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -40,5 +40,4 @@ deploySepolia = "scarb --profile release build && node --loader ts-node/esm ./sc deployTimelock = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployTimelock.ts" checkGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --check" updateGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --write" -# test = "snforge test" -test = "snforge test 'test_fuzz_modify_position_borrow_repay_debt'" +test = "snforge test" diff --git a/src/test/test_modify_position.cairo b/src/test/test_modify_position.cairo index de75ae0..8c1c699 100644 --- a/src/test/test_modify_position.cairo +++ b/src/test/test_modify_position.cairo @@ -658,9 +658,7 @@ mod TestModifyPosition { #[test] #[fuzzer(runs: 256, seed: 100)] - // fn test_fuzz_modify_position_borrow_repay_debt(seed: u128) { - fn test_fuzz_modify_position_borrow_repay_debt() { - let seed: u128 = 49160906480394477896903869124991585048; + fn test_fuzz_modify_position_borrow_repay_debt(seed: u128) { let (singleton, _, config, users, _) = setup(); let TestConfig { pool_id, collateral_asset, debt_asset, debt_scale, .. } = config; @@ -883,7 +881,7 @@ mod TestModifyPosition { let TestConfig { pool_id, collateral_asset, debt_asset, .. } = config; let LendingTerms { collateral_to_deposit, .. } = terms; - let inflation_fee: u256 = 2000; // 2x for each pair + let inflation_fee: u256 = 2000_0000000000; // 2x for each pair start_prank(CheatTarget::One(singleton.contract_address), users.lender); @@ -1041,8 +1039,8 @@ mod TestModifyPosition { asset_config.total_collateral_shares - inflation_fee == position.collateral_shares, 'Shares not matching' ); // rounding error might leave some extra units in the pool - assert(asset_config.reserve == 4, 'Reserve not zero'); - assert(asset_config.total_collateral_shares == 2000, 'Total shares not zero'); + assert(asset_config.reserve == 4000, 'Reserve not zero'); + assert(asset_config.total_collateral_shares == 2000_0000000000, 'Total shares not zero'); stop_prank(CheatTarget::One(singleton.contract_address)); } diff --git a/src/test/test_pool_donations.cairo b/src/test/test_pool_donations.cairo index 6e28028..c68f311 100644 --- a/src/test/test_pool_donations.cairo +++ b/src/test/test_pool_donations.cairo @@ -25,6 +25,8 @@ mod TestPoolDonation { singleton.set_asset_parameter(pool_id, debt_asset.contract_address, 'fee_rate', 10 * PERCENT); stop_prank(CheatTarget::One(singleton.contract_address)); + let initial_singleton_debt_asset_balance = debt_asset.balance_of(singleton.contract_address); + // LENDER // deposit collateral which is later borrowed by the borrower @@ -51,7 +53,7 @@ mod TestPoolDonation { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance == liquidity_to_deposit, "Not transferred to Singleton"); + assert!(balance == initial_singleton_debt_asset_balance + liquidity_to_deposit, "Not transferred to Singleton"); let (old_position, collateral, _) = singleton .position(pool_id, debt_asset.contract_address, collateral_asset.contract_address, users.lender); diff --git a/src/test/test_pragma_oracle.cairo b/src/test/test_pragma_oracle.cairo index 562e5e9..c034bf8 100644 --- a/src/test/test_pragma_oracle.cairo +++ b/src/test/test_pragma_oracle.cairo @@ -1,7 +1,7 @@ #[cfg(test)] mod TestPragmaOracle { use core::serde::Serde; - use snforge_std::{start_prank, stop_prank, start_warp, stop_warp, CheatTarget}; + use snforge_std::{start_prank, stop_prank, start_warp, stop_warp, CheatTarget, CheatSpan, prank}; use starknet::{ContractAddress, get_block_timestamp}; use vesu::{ units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS}, @@ -106,7 +106,7 @@ mod TestPragmaOracle { }; let fee_params = FeeParams { fee_recipient: creator }; - start_prank(CheatTarget::One(extension.contract_address), creator); + prank(CheatTarget::One(extension.contract_address), creator, CheatSpan::TargetCalls(1)); extension .create_pool( asset_params, From dae7f84de6002926f322ee4986b4c25f90087d28 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Mon, 11 Nov 2024 17:08:17 +0000 Subject: [PATCH 07/32] Push progress IV --- src/test/test_default_extension_cl.cairo | 2 - src/test/test_forking.cairo | 5 ++- src/test/test_modify_position.cairo | 57 +++++++++--------------- src/test/test_shutdown.cairo | 24 ++++++---- src/test/test_user.cairo | 13 ------ 5 files changed, 40 insertions(+), 61 deletions(-) diff --git a/src/test/test_default_extension_cl.cairo b/src/test/test_default_extension_cl.cairo index 1b36a8d..31d311a 100644 --- a/src/test/test_default_extension_cl.cairo +++ b/src/test/test_default_extension_cl.cairo @@ -441,8 +441,6 @@ mod TestDefaultExtensionCL { // #[test] // #[fork("Mainnet", block_number: 693670)] // fn test_add_asset_fork() { - // println!("{}", get_block_number()); - // let Env { singleton, extension_v2, config, users, .. } = setup_env( // Zeroable::zero(), Zeroable::zero(), Zeroable::zero(), Zeroable::zero() // ); diff --git a/src/test/test_forking.cairo b/src/test/test_forking.cairo index 989b3b3..cd1cdbc 100644 --- a/src/test/test_forking.cairo +++ b/src/test/test_forking.cairo @@ -12,7 +12,9 @@ fn to_percent(value: u256) -> u64 { #[cfg(test)] mod TestForking { - use snforge_std::{start_prank, stop_prank, CheatTarget, store, load, map_entry_address, declare, start_warp, prank, CheatSpan}; + use snforge_std::{ + start_prank, stop_prank, CheatTarget, store, load, map_entry_address, declare, start_warp, prank, CheatSpan + }; use starknet::{ contract_address_const, get_caller_address, get_contract_address, ContractAddress, get_block_timestamp, get_block_number @@ -478,7 +480,6 @@ mod TestForking { btc.approve(extension.contract_address, INFLATION_FEE); stop_prank(CheatTarget::One(btc.contract_address)); - let usdc_asset_params: AssetParams = *asset_params[2]; let usdc = ERC20ABIDispatcher { contract_address: usdc_asset_params.asset }; let loaded = load(usdc_asset_params.asset, selector!("permitted_minter"), 1); diff --git a/src/test/test_modify_position.cairo b/src/test/test_modify_position.cairo index 8c1c699..a574870 100644 --- a/src/test/test_modify_position.cairo +++ b/src/test/test_modify_position.cairo @@ -662,10 +662,11 @@ mod TestModifyPosition { let (singleton, _, config, users, _) = setup(); let TestConfig { pool_id, collateral_asset, debt_asset, debt_scale, .. } = config; - let amount: u256 = seed.into() / 20000000000000; + let amount: u256 = seed.into() / 10000000000000; let collateral_amount = singleton .calculate_collateral(pool_id, collateral_asset.contract_address, amount.into()); - let debt_amount = singleton.calculate_debt(amount.into(), SCALE, debt_scale); + let mut debt_amount = singleton.calculate_debt(amount.into(), SCALE, debt_scale); + debt_amount = debt_amount / 2; start_prank(CheatTarget::One(singleton.contract_address), users.lender); IMintableDispatcher { contract_address: debt_asset.contract_address }.mint(users.lender, debt_amount); @@ -677,8 +678,6 @@ mod TestModifyPosition { // compensate for rounding up calculation of repayment amount (in two places) IMintableDispatcher { contract_address: debt_asset.contract_address }.mint(users.borrower, debt_amount + 2); - println!("A"); - // Add liquidity let params = ModifyPositionParams { @@ -695,8 +694,6 @@ mod TestModifyPosition { singleton.modify_position(params); - println!("B"); - // Delta, Native let params = ModifyPositionParams { @@ -715,8 +712,6 @@ mod TestModifyPosition { singleton.modify_position(params); - println!("C"); - let params = ModifyPositionParams { pool_id, collateral_asset: collateral_asset.contract_address, @@ -733,16 +728,6 @@ mod TestModifyPosition { singleton.modify_position(params); - println!("D"); - - println!("collateral_amount: {}", collateral_amount); - println!("debt_amount: {}", debt_amount); - - let (_, collateral, debt) = singleton - .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, users.borrower); - println!("collateral: {}", collateral); - println!("debt: {}", debt); - // Delta, Assets let params = ModifyPositionParams { @@ -763,8 +748,6 @@ mod TestModifyPosition { singleton.modify_position(params); - println!("E"); - let params = ModifyPositionParams { pool_id, collateral_asset: collateral_asset.contract_address, @@ -783,8 +766,6 @@ mod TestModifyPosition { singleton.modify_position(params); - println!("F"); - let collateral_shares = singleton .calculate_collateral_shares(pool_id, collateral_asset.contract_address, collateral_amount.into()); @@ -810,8 +791,6 @@ mod TestModifyPosition { singleton.modify_position(params); - println!("G"); - let params = ModifyPositionParams { pool_id, collateral_asset: collateral_asset.contract_address, @@ -828,8 +807,6 @@ mod TestModifyPosition { singleton.modify_position(params); - println!("H"); - // Target, Assets let params = ModifyPositionParams { @@ -850,8 +827,6 @@ mod TestModifyPosition { singleton.modify_position(params); - println!("I"); - let params = ModifyPositionParams { pool_id, collateral_asset: collateral_asset.contract_address, @@ -868,8 +843,6 @@ mod TestModifyPosition { singleton.modify_position(params); - println!("J"); - let (position, _, _) = singleton .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, users.lender); assert(position.collateral_shares == 0 && position.nominal_debt == 0, 'Position not zero'); @@ -1250,7 +1223,9 @@ mod TestModifyPosition { assert!(balance == initial_lender_debt_asset_balance - liquidity_to_deposit, "Not transferred from Lender"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance == initial_singleton_debt_asset_balance + liquidity_to_deposit, "Not transferred to Singleton"); // 2 due to inflation mitigation + assert!( + balance == initial_singleton_debt_asset_balance + liquidity_to_deposit, "Not transferred to Singleton" + ); // 2 due to inflation mitigation let (position, collateral, debt) = singleton .position(pool_id, debt_asset.contract_address, collateral_asset.contract_address, users.lender); @@ -1295,21 +1270,33 @@ mod TestModifyPosition { "Not transferred from borrower" ); let balance = collateral_asset.balance_of(singleton.contract_address); - assert!(balance == initial_singleton_collateral_asset_balance + collateral_to_deposit, "Not transferred to Singleton"); + assert!( + balance == initial_singleton_collateral_asset_balance + collateral_to_deposit, + "Not transferred to Singleton" + ); // debt asset has been transferred from the singleton to the borrower let balance = debt_asset.balance_of(users.borrower); assert!(balance == initial_borrower_debt_asset_balance + debt_to_draw, "Debt asset not transferred"); let balance = debt_asset.balance_of(singleton.contract_address); - assert!(balance == initial_singleton_debt_asset_balance + liquidity_to_deposit - debt_to_draw, "Debt asset not transferred"); + assert!( + balance == initial_singleton_debt_asset_balance + liquidity_to_deposit - debt_to_draw, + "Debt asset not transferred" + ); // collateral asset reserve has been updated let (asset_config, _) = singleton.asset_config(pool_id, collateral_asset.contract_address); - assert!(asset_config.reserve == initial_singleton_collateral_asset_balance + collateral_to_deposit, "Collateral not in reserve"); + assert!( + asset_config.reserve == initial_singleton_collateral_asset_balance + collateral_to_deposit, + "Collateral not in reserve" + ); // debt asset reserve has been updated let (asset_config, _) = singleton.asset_config(pool_id, debt_asset.contract_address); - assert!(asset_config.reserve == initial_singleton_debt_asset_balance + liquidity_to_deposit - debt_to_draw, "Debt not taken from reserve"); + assert!( + asset_config.reserve == initial_singleton_debt_asset_balance + liquidity_to_deposit - debt_to_draw, + "Debt not taken from reserve" + ); // position's collateral balance has been updated let (position, collateral, debt) = singleton diff --git a/src/test/test_shutdown.cairo b/src/test/test_shutdown.cairo index bb21f25..03754e8 100644 --- a/src/test/test_shutdown.cairo +++ b/src/test/test_shutdown.cairo @@ -666,7 +666,9 @@ mod TestShutdown { debt_asset: debt_asset.contract_address, user: users.borrower, collateral: Amount { - amount_type: AmountType::Delta, denomination: AmountDenomination::Native, value: -1000.into(), + amount_type: AmountType::Delta, + denomination: AmountDenomination::Native, + value: -1000_0000000000.into(), }, debt: Default::default(), data: ArrayTrait::new().span() @@ -1013,17 +1015,17 @@ mod TestShutdown { }; start_prank(CheatTarget::One(v_token.contract_address), extension.contract_address); - IVTokenDispatcher { contract_address: v_token.contract_address }.mint_v_token(users.borrower, 10000000); + IVTokenDispatcher { contract_address: v_token.contract_address }.mint_v_token(users.borrower, 1000_0000000000); stop_prank(CheatTarget::One(v_token.contract_address)); assert(v_token.max_deposit(Zeroable::zero()) == 0, 'max_deposit neq'); - assert(v_token.preview_deposit(10000000) == 0, 'preview_deposit neq'); + assert(v_token.preview_deposit(1000_0000000000) == 0, 'preview_deposit neq'); assert(v_token.max_mint(Zeroable::zero()) == 0, 'max_mint neq'); - assert(v_token.preview_mint(100000000) == 0, 'preview_mint neq'); + assert(v_token.preview_mint(1000_0000000000) == 0, 'preview_mint neq'); assert(v_token.max_withdraw(users.borrower) > 0, 'max_withdraw neq'); - assert(v_token.preview_withdraw(10000000) > 0, 'preview_withdraw neq'); + assert(v_token.preview_withdraw(1000_0000000000) > 0, 'preview_withdraw neq'); assert(v_token.max_redeem(users.borrower) > 0, 'max_redeem neq'); - assert(v_token.preview_redeem(10000000) > 0, 'preview_redeem neq'); + assert(v_token.preview_redeem(1000_0000000000) > 0, 'preview_redeem neq'); let params = ModifyPositionParams { pool_id, @@ -1399,7 +1401,9 @@ mod TestShutdown { debt_asset: debt_asset.contract_address, user: users.borrower, collateral: Amount { - amount_type: AmountType::Delta, denomination: AmountDenomination::Native, value: -1000.into(), + amount_type: AmountType::Delta, + denomination: AmountDenomination::Native, + value: -1000_0000000000.into(), }, debt: Default::default(), data: ArrayTrait::new().span() @@ -1560,6 +1564,8 @@ mod TestShutdown { let status = extension.shutdown_status(pool_id, collateral_asset.contract_address, debt_asset.contract_address); assert(status.shutdown_mode == ShutdownMode::Redemption, 'not-in-redemption'); + let (asset_config, _) = singleton.asset_config(pool_id, collateral_asset.contract_address); + let params = ModifyPositionParams { pool_id, collateral_asset: collateral_asset.contract_address, @@ -1567,8 +1573,8 @@ mod TestShutdown { user: borrower, collateral: Amount { amount_type: AmountType::Delta, - denomination: AmountDenomination::Native, - value: -(collateral_to_deposit / 10).into(), + denomination: AmountDenomination::Assets, + value: -(asset_config.reserve).into(), }, debt: Default::default(), data: ArrayTrait::new().span() diff --git a/src/test/test_user.cairo b/src/test/test_user.cairo index 25483a3..22f9091 100644 --- a/src/test/test_user.cairo +++ b/src/test/test_user.cairo @@ -78,16 +78,6 @@ mod TestUser { let (position, _, _) = singleton .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, user); - // println!("position.collateral_shares: {}", position.collateral_shares); - // println!("position.nominal_debt: {}", position.nominal_debt); - - // let context = singleton.context(pool_id, collateral_asset.contract_address, debt_asset.contract_address, user); - // println!( - // "context.collateral_asset_config.total_collateral_shares: {}", - // context.collateral_asset_config.total_collateral_shares - // ); - // println!("context.collateral_asset_config.reserve: {}", context.collateral_asset_config.reserve); - start_prank(CheatTarget::One(singleton.contract_address), user); singleton .transfer_position( @@ -115,8 +105,5 @@ mod TestUser { // let collateral_shares = singleton.calculate_collateral_shares( // pool_id, wbtc, i257_new(270738, false) // ); - - // println!("collateral: {}", 270738); - // println!("collateral_shares: {}", collateral_shares); } } From 2d173603226b0bba8329bc274f7b3eaa476fcc40 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 13 Nov 2024 14:16:44 +0000 Subject: [PATCH 08/32] Update max steps --- Scarb.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Scarb.toml b/Scarb.toml index b3d6c0c..d7619b0 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -22,7 +22,7 @@ sort-module-level-items = true [[tool.snforge.fork]] name = "Mainnet" url = "https://starknet-mainnet.public.blastapi.io/rpc/v0_7" -block_id.number = "652612" # "700000" +block_id.number = "652612" [tool.voyager] singleton = { path = "singleton.cairo" } @@ -40,4 +40,4 @@ deploySepolia = "scarb --profile release build && node --loader ts-node/esm ./sc deployTimelock = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployTimelock.ts" checkGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --check" updateGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --write" -test = "snforge test" +test = "snforge test --max-n-steps 10000000" From e65f27baeea82b4ba4857441be401771a75fad99 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 13 Nov 2024 16:04:04 +0000 Subject: [PATCH 09/32] Update gas report script --- .github/workflows/test.yml | 2 +- gas-report.txt | 18 +++++++++--------- lib/deployer.protocol.ts | 16 +++++++++++++--- scripts/gasReport.ts | 9 +++++++-- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4d43641..f9de4ef 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,4 +18,4 @@ jobs: - name: Patch Scarb.toml run: ./scripts/patchScarbToml.sh - - run: snforge test + - run: scarb run test diff --git a/gas-report.txt b/gas-report.txt index ab353db..0f384de 100644 --- a/gas-report.txt +++ b/gas-report.txt @@ -2,19 +2,19 @@ Summary: ┌─────────────┬─────────────────────────┬─────────┬────────────────┬────────────────┬─────────────────┬───────────┬──────────────┬──────────────────────────────┬───────────────┬──────────────────┬─────────┐ │ (index) │ Actual fee │ Fee usd │ Fee without DA │ Gas without DA │ Computation gas │ Event gas │ Calldata gas │ Max computation per Category │ Storage diffs │ DA fee │ DA mode │ ├─────────────┼─────────────────────────┼─────────┼────────────────┼────────────────┼─────────────────┼───────────┼──────────────┼──────────────────────────────┼───────────────┼──────────────────┼─────────┤ -│ Create pool │ '1.452.040.000.000.000' │ 5.8081 │ 24840000000000 │ 690 │ 628 │ 144 │ 62 │ 'steps' │ 206 │ 1427200000000000 │ 'BLOB' │ -│ Lend │ '111.768.000.000.000' │ 0.447 │ 15768000000000 │ 438 │ 436 │ 12 │ 2 │ 'range_check' │ 12 │ 96000000000000 │ 'BLOB' │ +│ Create pool │ '1.714.444.000.000.000' │ 6.8577 │ 56844000000000 │ 1579 │ 1517 │ 238 │ 62 │ 'range_check' │ 242 │ 1657600000000000 │ 'BLOB' │ +│ Lend │ '106.340.000.000.000' │ 0.4253 │ 16740000000000 │ 465 │ 463 │ 12 │ 2 │ 'range_check' │ 11 │ 89600000000000 │ 'BLOB' │ │ Transfer │ '102.684.000.000.000' │ 0.4107 │ 25884000000000 │ 719 │ 717 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ -│ Borrow │ '146.900.000.000.000' │ 0.5876 │ 18900000000000 │ 525 │ 523 │ 13 │ 2 │ 'range_check' │ 16 │ 128000000000000 │ 'BLOB' │ -│ Liquidate │ '143.344.000.000.000' │ 0.5733 │ 21744000000000 │ 604 │ 602 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ +│ Borrow │ '140.932.000.000.000' │ 0.5637 │ 19332000000000 │ 537 │ 535 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ +│ Liquidate │ '144.136.000.000.000' │ 0.5765 │ 22536000000000 │ 626 │ 624 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ └─────────────┴─────────────────────────┴─────────┴────────────────┴────────────────┴─────────────────┴───────────┴──────────────┴──────────────────────────────┴───────────────┴──────────────────┴─────────┘ Resources: ┌─────────────┬─────────┬───────┬───────┬────────┬──────────┬──────────┬─────────────┬────────┐ │ (index) │ bitwise │ ec_op │ ecdsa │ keccak │ pedersen │ poseidon │ range_check │ steps │ ├─────────────┼─────────┼───────┼───────┼────────┼──────────┼──────────┼─────────────┼────────┤ -│ Create pool │ 57 │ 3 │ 0 │ 0 │ 1019 │ 1 │ 14528 │ 251057 │ -│ Lend │ 26 │ 3 │ 0 │ 0 │ 134 │ 0 │ 10892 │ 93965 │ -│ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17924 │ 142928 │ -│ Borrow │ 33 │ 3 │ 0 │ 0 │ 146 │ 0 │ 13058 │ 107000 │ -│ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15044 │ 117441 │ +│ Create pool │ 138 │ 3 │ 0 │ 0 │ 1541 │ 1 │ 37918 │ 540202 │ +│ Lend │ 26 │ 3 │ 0 │ 0 │ 130 │ 0 │ 11575 │ 95937 │ +│ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17922 │ 142569 │ +│ Borrow │ 33 │ 3 │ 0 │ 0 │ 142 │ 0 │ 13371 │ 108313 │ +│ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15584 │ 118048 │ └─────────────┴─────────┴───────┴───────┴────────┴──────────┴──────────┴─────────────┴────────┘ diff --git a/lib/deployer.protocol.ts b/lib/deployer.protocol.ts index 1c45e47..e4e6435 100644 --- a/lib/deployer.protocol.ts +++ b/lib/deployer.protocol.ts @@ -30,6 +30,7 @@ export class Deployer extends BaseDeployer { await this.waitForTransaction(response.transaction_hash); const contracts = { ...protocolContracts, ...envContracts }; await this.setApprovals(contracts.singleton, contracts.assets); + await this.setApprovals(contracts.extension, contracts.assets); logAddresses("Deployed:", contracts); return Protocol.from(contracts, this); } @@ -105,14 +106,23 @@ export class Deployer extends BaseDeployer { return [oracle, [...calls, ...setupCalls]] as const; } - async setApprovals(singleton: Contract, assets: Contract[]) { + async setApprovals(contract: Contract, assets: Contract[]) { const approvalCalls = assets.map((asset, index) => { const { initial_supply } = this.config.env![index].erc20Params(); - return asset.populateTransaction.approve(singleton.address, initial_supply); + return asset.populateTransaction.approve(contract.address, initial_supply); }); - let response = await this.lender.execute(approvalCalls); + let response = await this.creator.execute(approvalCalls); + await this.waitForTransaction(response.transaction_hash); + response = await this.lender.execute(approvalCalls); await this.waitForTransaction(response.transaction_hash); response = await this.borrower.execute(approvalCalls); await this.waitForTransaction(response.transaction_hash); + + // transfer INFLATION_FEE to creator + const transferCalls = assets.map((asset, index) => { + return asset.populateTransaction.transfer(this.creator.address, 2000); + }); + response = await this.lender.execute(transferCalls); + await this.waitForTransaction(response.transaction_hash); } } diff --git a/scripts/gasReport.ts b/scripts/gasReport.ts index 3ccef0b..524dedc 100644 --- a/scripts/gasReport.ts +++ b/scripts/gasReport.ts @@ -9,6 +9,8 @@ const profiler = newProfiler(deployer); // CREATE POOL +console.log("Create pool"); + const [pool, response] = await protocol.createPool("gas-report-pool", { devnetEnv: true }); await profiler.profile("Create pool", response); @@ -75,9 +77,12 @@ for (const [index, asset] of assets.entries()) { ); const { "0": asset_config } = await singleton.asset_config_unsafe(pool.id, asset.address); - assert(asset_config.total_collateral_shares === 0n, "total_collateral_shares-neq"); + assert( + asset_config.total_collateral_shares === (2000n * BigInt(1e18)) / BigInt(asset_config.scale), + "total_collateral_shares-neq", + ); assert(asset_config.total_nominal_debt === 0n, "total_nominal_debt-neq"); - assert(asset_config.reserve === 0n, "reserve-neq"); + assert(asset_config.reserve === 2000n, "reserve-neq"); assert(asset_config.max_utilization > 0n, "max_utilization-neq"); assert(asset_config.floor > 0n, "floor-neq"); assert(asset_config.scale > 0n, "scale-neq"); From 6a2ef8a11eae9f1d54bf1d3e6677324062137c76 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 13 Nov 2024 19:42:27 +0000 Subject: [PATCH 10/32] Fix CI --- Scarb.toml.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Scarb.toml.template b/Scarb.toml.template index 8e2b04f..0284d6a 100644 --- a/Scarb.toml.template +++ b/Scarb.toml.template @@ -40,4 +40,4 @@ deploySepolia = "scarb --profile release build && node --loader ts-node/esm ./sc deployTimelock = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployTimelock.ts" checkGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --check" updateGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --write" -test = "snforge test" +test = "snforge test --max-n-steps 10000000" From 1e45d28733eb2c076f186d1691c2160821b9206a Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Thu, 14 Nov 2024 13:58:20 +0000 Subject: [PATCH 11/32] Add gas report --- gas-report.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 gas-report.txt diff --git a/gas-report.txt b/gas-report.txt new file mode 100644 index 0000000..39fff72 --- /dev/null +++ b/gas-report.txt @@ -0,0 +1,20 @@ +Summary: +┌─────────────┬─────────────────────────┬─────────┬────────────────┬────────────────┬─────────────────┬───────────┬──────────────┬──────────────────────────────┬───────────────┬──────────────────┬─────────┐ +│ (index) │ Actual fee │ Fee usd │ Fee without DA │ Gas without DA │ Computation gas │ Event gas │ Calldata gas │ Max computation per Category │ Storage diffs │ DA fee │ DA mode │ +├─────────────┼─────────────────────────┼─────────┼────────────────┼────────────────┼─────────────────┼───────────┼──────────────┼──────────────────────────────┼───────────────┼──────────────────┼─────────┤ +│ Create pool │ '1.720.844.000.000.000' │ 6.8833 │ 56844000000000 │ 1579 │ 1517 │ 238 │ 62 │ 'range_check' │ 243 │ 1664000000000000 │ 'BLOB' │ +│ Lend │ '106.340.000.000.000' │ 0.4253 │ 16740000000000 │ 465 │ 463 │ 12 │ 2 │ 'range_check' │ 11 │ 89600000000000 │ 'BLOB' │ +│ Transfer │ '102.684.000.000.000' │ 0.4107 │ 25884000000000 │ 719 │ 717 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ +│ Borrow │ '141.220.000.000.000' │ 0.5648 │ 19620000000000 │ 545 │ 543 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ +│ Liquidate │ '143.344.000.000.000' │ 0.5733 │ 21744000000000 │ 604 │ 602 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ +└─────────────┴─────────────────────────┴─────────┴────────────────┴────────────────┴─────────────────┴───────────┴──────────────┴──────────────────────────────┴───────────────┴──────────────────┴─────────┘ +Resources: +┌─────────────┬─────────┬───────┬───────┬────────┬──────────┬──────────┬─────────────┬────────┐ +│ (index) │ bitwise │ ec_op │ ecdsa │ keccak │ pedersen │ poseidon │ range_check │ steps │ +├─────────────┼─────────┼───────┼───────┼────────┼──────────┼──────────┼─────────────┼────────┤ +│ Create pool │ 138 │ 3 │ 0 │ 0 │ 1543 │ 1 │ 37924 │ 540429 │ +│ Lend │ 26 │ 3 │ 0 │ 0 │ 130 │ 0 │ 11575 │ 95937 │ +│ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17922 │ 142569 │ +│ Borrow │ 33 │ 3 │ 0 │ 0 │ 142 │ 0 │ 13551 │ 108517 │ +│ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15044 │ 117436 │ +└─────────────┴─────────┴───────┴───────┴────────┴──────────┴──────────┴─────────────┴────────┘ From fa72fbb76d94bc58797c8e2ae603a91d4b663c34 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Tue, 19 Nov 2024 16:54:48 +0000 Subject: [PATCH 12/32] Push progress --- lib/config.ts | 8 ++- lib/deployer.protocol.ts | 57 +++++++++++------ lib/protocol.ts | 21 ++++--- scripts/deployMainnet.ts | 22 ++++--- src/extension/components/pragma_oracle.cairo | 52 ++++++++++++++-- src/extension/default_extension_po.cairo | 29 +++++++-- src/test/mock_oracle.cairo | 47 +++++++++++++- src/test/setup.cairo | 37 +++++++++-- src/test/test_default_extension_po.cairo | 43 +++++++++++-- src/test/test_forking.cairo | 65 +++++++++++++++++--- src/test/test_pragma_oracle.cairo | 17 ++++- src/vendor/pragma.cairo | 12 +++- 12 files changed, 335 insertions(+), 75 deletions(-) diff --git a/lib/config.ts b/lib/config.ts index c766b13..b8c0b33 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -10,8 +10,12 @@ export const YEAR_IN_SECONDS = 360 * 24 * 60 * 60; interface ProtocolConfig { singleton: string | undefined; - extension: string | undefined; - oracle: string | undefined; + extensionPO: string | undefined; + extensionCL: string | undefined; + pragma: { + oracle: string | undefined; + summary_stats: string | undefined; + }; } export class EnvAssetParams { diff --git a/lib/deployer.protocol.ts b/lib/deployer.protocol.ts index e4e6435..fdfbe22 100644 --- a/lib/deployer.protocol.ts +++ b/lib/deployer.protocol.ts @@ -3,10 +3,16 @@ import { unzip } from "lodash-es"; import { Account, Call, CallData, Contract, RpcProvider } from "starknet"; import { BaseDeployer, Config, Protocol, logAddresses } from "."; +export interface PragmaContracts { + oracle: Contract; + summary_stats: Contract; +} + export interface ProtocolContracts { singleton: Contract; - extension: Contract; - oracle: Contract; + extensionPO: Contract; + extensionCL: Contract; + pragma: PragmaContracts; assets: Contract[]; } @@ -25,12 +31,13 @@ export class Deployer extends BaseDeployer { async deployEnvAndProtocol(): Promise { assert(this.config.env, "Test environment not defined, use loadProtocol for existing networks"); const [envContracts, envCalls] = await this.deferEnv(); - const [protocolContracts, protocolCalls] = await this.deferProtocol(envContracts.oracle.address); + const [protocolContracts, protocolCalls] = await this.deferProtocol(envContracts.pragma); let response = await this.execute([...envCalls, ...protocolCalls]); await this.waitForTransaction(response.transaction_hash); const contracts = { ...protocolContracts, ...envContracts }; await this.setApprovals(contracts.singleton, contracts.assets); - await this.setApprovals(contracts.extension, contracts.assets); + await this.setApprovals(contracts.extensionPO, contracts.assets); + await this.setApprovals(contracts.extensionCL, contracts.assets); logAddresses("Deployed:", contracts); return Protocol.from(contracts, this); } @@ -42,31 +49,41 @@ export class Deployer extends BaseDeployer { .map(this.loadContract.bind(this)); const contracts = { singleton: await this.loadContract(protocol.singleton!), - extension: await this.loadContract(protocol.extension!), - oracle: await this.loadContract(protocol.oracle!), + extensionPO: await this.loadContract(protocol.extensionPO!), + extensionCL: await this.loadContract(protocol.extensionCL!), + pragma: { + oracle: await this.loadContract(protocol.pragma.oracle!), + summary_stats: await this.loadContract(protocol.pragma.summary_stats!), + }, assets: await Promise.all(addresses), }; logAddresses("Loaded:", contracts); return Protocol.from(contracts, this); } - async deployProtocol(oracleAddress: string) { - const [contracts, calls] = await this.deferProtocol(oracleAddress); + async deployProtocol(pragma: PragmaContracts) { + const [contracts, calls] = await this.deferProtocol(pragma); const response = await this.execute([...calls]); await this.waitForTransaction(response.transaction_hash); return [contracts, response] as const; } - async deferProtocol(oracleAddress: string) { + async deferProtocol(pragma: PragmaContracts) { const [singleton, calls1] = await this.deferContract("Singleton"); const v_token_class_hash = await this.declareCached("VToken"); - const calldata = CallData.compile({ + const calldataPO = CallData.compile({ singleton: singleton.address, - oracle_address: oracleAddress, + oracle_address: pragma.oracle.address, + summary_stats_address: pragma.summary_stats.address, v_token_class_hash: v_token_class_hash, }); - const [extension, calls2] = await this.deferContract("DefaultExtensionPO", calldata); - return [{ singleton, extension }, [...calls1, ...calls2]] as const; + const [extensionPO, calls2] = await this.deferContract("DefaultExtensionPO", calldataPO); + const calldataCL = CallData.compile({ + singleton: singleton.address, + v_token_class_hash: v_token_class_hash + }); + const [extensionCL, calls3] = await this.deferContract("DefaultExtensionCL", calldataCL); + return [{ singleton, extensionPO, extensionCL }, [...calls1, ...calls2, ...calls3]] as const; } async deployEnv() { @@ -78,8 +95,11 @@ export class Deployer extends BaseDeployer { async deferEnv() { const [assets, assetCalls] = await this.deferMockAssets(this.lender.address); - const [oracle, oracleCalls] = await this.deferOracle(); - return [{ assets, oracle }, [...assetCalls, ...oracleCalls]] as const; + const [oracle, summary_stats, pragmaCalls] = await this.deferPragmaOracle(); + return [ + { assets, pragma: { oracle, summary_stats } }, + [...assetCalls, ...pragmaCalls] + ] as const; } async deferMockAssets(recipient: string) { @@ -98,12 +118,13 @@ export class Deployer extends BaseDeployer { return [assets, calls] as const; } - async deferOracle() { - const [oracle, calls] = await this.deferContract("MockPragmaOracle"); + async deferPragmaOracle() { + const [oracle, oracleCalls] = await this.deferContract("MockPragmaOracle"); + const [summary_stats, summaryStatsCalls] = await this.deferContract("MockSummaryStats"); const setupCalls = this.config.env!.map(({ pragmaKey, price }) => oracle.populateTransaction.set_price(pragmaKey, price), ); - return [oracle, [...calls, ...setupCalls]] as const; + return [oracle, summary_stats, [...oracleCalls, ...summaryStatsCalls, ...setupCalls]] as const; } async setApprovals(contract: Contract, assets: Contract[]) { diff --git a/lib/protocol.ts b/lib/protocol.ts index 3b83c31..73879b5 100644 --- a/lib/protocol.ts +++ b/lib/protocol.ts @@ -1,19 +1,20 @@ import assert from "assert"; import { Contract } from "starknet"; -import { CreatePoolParams, Deployer, Pool, ProtocolContracts } from "."; +import { CreatePoolParams, Deployer, Pool, PragmaContracts, ProtocolContracts } from "."; export class Protocol implements ProtocolContracts { constructor( public singleton: Contract, - public extension: Contract, - public oracle: Contract, + public extensionPO: Contract, + public extensionCL: Contract, + public pragma: PragmaContracts, public assets: Contract[], public deployer: Deployer, ) {} static from(contracts: ProtocolContracts, deployer: Deployer) { - const { singleton, extension, oracle, assets } = contracts; - return new Protocol(singleton, extension, oracle, assets, deployer); + const { singleton, extensionPO, extensionCL, pragma, assets } = contracts; + return new Protocol(singleton, extensionPO, extensionCL, pragma, assets, deployer); } async createPool(name: string, { devnetEnv = false, printParams = false } = {}) { @@ -29,13 +30,13 @@ export class Protocol implements ProtocolContracts { } async createPoolFromParams(params: CreatePoolParams) { - const { singleton, extension, deployer } = this; - const nonce = await singleton.creator_nonce(extension.address); - const poolId = await singleton.calculate_pool_id(extension.address, nonce + 1n); + const { singleton, extensionPO, deployer } = this; + const nonce = await singleton.creator_nonce(extensionPO.address); + const poolId = await singleton.calculate_pool_id(extensionPO.address, nonce + 1n); assert((await singleton.extension(poolId)) === 0n, "extension should be set"); - extension.connect(deployer.creator); - const response = await extension.create_pool( + extensionPO.connect(deployer.creator); + const response = await extensionPO.create_pool( params.pool_name, params.asset_params, params.v_token_params, diff --git a/scripts/deployMainnet.ts b/scripts/deployMainnet.ts index 0ecc937..808adba 100644 --- a/scripts/deployMainnet.ts +++ b/scripts/deployMainnet.ts @@ -5,23 +5,24 @@ import { setup, toAddress } from "../lib"; const deployer = await setup("mainnet"); -const [contracts] = await deployer.deployProtocol(deployer.config.protocol.oracle!); +const [contracts] = await deployer.deployProtocol(deployer.config.protocol.pragma); deployer.config.protocol.singleton = contracts.singleton.address; -deployer.config.protocol.extension = contracts.extension.address; +deployer.config.protocol.extensionPO = contracts.extensionPO.address; +deployer.config.protocol.extensionCL = contracts.extensionCL.address; const protocol = await deployer.loadProtocol(); -const { singleton, assets, extension } = protocol; +const { singleton, assets, extensionPO } = protocol; const [pool] = await protocol.createPool("genesis-pool"); console.log("Pool ID: ", pool.id.toString()); -assert(toAddress(await extension.pragma_oracle()) === protocol.oracle.address.toLowerCase(), "pragma_oracle-neq"); +assert(toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), "pragma_oracle-neq"); // assert(toAddress(await extension.pool_owner(pool.id)) === pool.params.owner.toLowerCase(), "pool_owner-neq"); // assert( // toAddress((await extension.fee_config(pool.id)).fee_recipient) === pool.params.fee_params.fee_recipient.toLowerCase(), // "fee_recipient-neq", // ); -const shutdown_config = await extension.shutdown_config(pool.id); +const shutdown_config = await extensionPO.shutdown_config(pool.id); assert(shutdown_config.recovery_period === pool.params.shutdown_params.recovery_period, "recovery_period-neq"); assert( shutdown_config.subscription_period === pool.params.shutdown_params.subscription_period, @@ -29,7 +30,7 @@ assert( ); for (const [index, asset] of assets.entries()) { - const oracle_config = await extension.oracle_config(pool.id, asset.address); + const oracle_config = await extensionPO.oracle_config(pool.id, asset.address); assert( shortString.decodeShortString(oracle_config.pragma_key) === pool.params.pragma_oracle_params[index].pragma_key, "pragma_key-neq", @@ -40,7 +41,7 @@ for (const [index, asset] of assets.entries()) { "number_of_sources-neq", ); - const interest_rate_config = await extension.interest_rate_config(pool.id, asset.address); + const interest_rate_config = await extensionPO.interest_rate_config(pool.id, asset.address); assert( interest_rate_config.min_target_utilization === pool.params.interest_rate_configs[index].min_target_utilization, "min_target_utilization-neq", @@ -89,15 +90,16 @@ for (const [index, asset] of assets.entries()) { assert(asset_config.last_full_utilization_rate > 0n, "last_full_utilization_rate-neq"); assert(asset_config.fee_rate === 0n, "fee_rate-neq"); - assert((await extension.price(pool.id, asset.address)).value > 0n, "price-neq"); + assert((await extensionPO.price(pool.id, asset.address)).value > 0n, "price-neq"); assert((await singleton.rate_accumulator_unsafe(pool.id, asset.address)) > 0n, "rate_accumulator-neq"); assert((await singleton.utilization_unsafe(pool.id, asset.address)) === 0n, "utilization-neq"); } const deployment = { singleton: protocol.singleton.address, - extension: protocol.extension.address, - oracle: protocol.oracle.address, + extensionPO: protocol.extensionPO.address, + extensionCL: protocol.extensionCL.address, + oracle: protocol.pragma.oracle.address, assets: protocol.assets.map((asset) => asset.address), pools: [pool.id.toString()], }; diff --git a/src/extension/components/pragma_oracle.cairo b/src/extension/components/pragma_oracle.cairo index 4a68453..09c6ac5 100644 --- a/src/extension/components/pragma_oracle.cairo +++ b/src/extension/components/pragma_oracle.cairo @@ -1,21 +1,32 @@ +use vesu::vendor::pragma::AggregationMode; + #[derive(PartialEq, Copy, Drop, Serde, starknet::Store)] struct OracleConfig { pragma_key: felt252, timeout: u64, // [seconds] number_of_sources: u32, // [0, 255] + start_time: u64, // [seconds] + time_window: u64, // [seconds] + aggregation_mode: AggregationMode } fn assert_oracle_config(oracle_config: OracleConfig) { assert!(oracle_config.pragma_key != 0, "pragma-key-must-be-set"); + assert!( + (oracle_config.start_time == 0 && oracle_config.time_window == 0) + || (oracle_config.start_time != 0 && oracle_config.time_window != 0), + "pragma-start-time-and-time-window-must-be-set-together" + ); } #[starknet::component] mod pragma_oracle_component { use starknet::{ContractAddress, get_block_timestamp}; use vesu::{ - units::{SCALE}, math::{pow_10}, + units::{SCALE, SCALE_128}, math::{pow_10}, vendor::pragma::{ - PragmaPricesResponse, DataType, AggregationMode, IPragmaABIDispatcher, IPragmaABIDispatcherTrait + PragmaPricesResponse, DataType, AggregationMode, IPragmaABIDispatcher, IPragmaABIDispatcherTrait, + ISummaryStatsABIDispatcher, ISummaryStatsABIDispatcherTrait }, extension::components::pragma_oracle::{OracleConfig, assert_oracle_config} }; @@ -23,6 +34,7 @@ mod pragma_oracle_component { #[storage] struct Storage { oracle_address: ContractAddress, + summary_address: ContractAddress, // (pool_id, asset) -> oracle configuration oracle_configs: LegacyMap::<(felt252, ContractAddress), OracleConfig>, } @@ -51,6 +63,20 @@ mod pragma_oracle_component { #[generate_trait] impl PragmaOracleTrait> of Trait { + /// Sets the address of the summary contract + /// # Arguments + /// * `summary_address` - address of the summary contract + fn set_summary_address(ref self: ComponentState, summary_address: ContractAddress) { + self.summary_address.write(summary_address); + } + + /// Returns the address of the summary contract + /// # Returns + /// * `summary_address` - address of the summary contract + fn summary_address(self: @ComponentState) -> ContractAddress { + self.summary_address.read() + } + /// Sets the address of the pragma oracle contract /// # Arguments /// * `oracle_address` - address of the pragma oracle contract @@ -75,12 +101,25 @@ mod pragma_oracle_component { /// * `price` - current price of the asset /// * `valid` - whether the price is valid fn price(self: @ComponentState, pool_id: felt252, asset: ContractAddress) -> (u256, bool) { - let OracleConfig { pragma_key, timeout, number_of_sources } = self.oracle_configs.read((pool_id, asset)); + let OracleConfig { pragma_key, timeout, number_of_sources, start_time, time_window, aggregation_mode } = + self + .oracle_configs + .read((pool_id, asset)); let dispatcher = IPragmaABIDispatcher { contract_address: self.oracle_address.read() }; - let response = dispatcher.get_data_median(DataType::SpotEntry(pragma_key)); - let denominator = pow_10(response.decimals); - let price = response.price.into() * SCALE / denominator; + let response = dispatcher.get_data(DataType::SpotEntry(pragma_key), aggregation_mode); + + // calculate the twap if start_time and time_window are set + let price = if start_time == 0 || time_window == 0 { + response.price.into() * SCALE / pow_10(response.decimals.into()) + } else { + let summary = ISummaryStatsABIDispatcher { contract_address: self.summary_address.read() }; + let (value, decimals) = summary + .calculate_twap(DataType::SpotEntry(pragma_key), aggregation_mode, start_time, time_window,); + value.into() * SCALE / pow_10(decimals.into()) + }; + + // ensure that price is not stale and that the number of sources is sufficient let time_delta = if response.last_updated_timestamp >= get_block_timestamp() { 0 } else { @@ -89,6 +128,7 @@ mod pragma_oracle_component { let valid = (timeout == 0 || (timeout != 0 && time_delta <= timeout)) && (number_of_sources == 0 || (number_of_sources != 0 && number_of_sources <= response.num_sources_aggregated)); + (price, valid) } diff --git a/src/extension/default_extension_po.cairo b/src/extension/default_extension_po.cairo index a6f286c..426e92c 100644 --- a/src/extension/default_extension_po.cairo +++ b/src/extension/default_extension_po.cairo @@ -7,6 +7,7 @@ use vesu::{ position_hooks::{ShutdownMode, ShutdownStatus, ShutdownConfig, LiquidationConfig, Pair}, fee_model::FeeConfig, pragma_oracle::OracleConfig, }, + vendor::pragma::{AggregationMode} }; #[derive(PartialEq, Copy, Drop, Serde)] @@ -19,7 +20,10 @@ struct VTokenParams { struct PragmaOracleParams { pragma_key: felt252, timeout: u64, // [seconds] - number_of_sources: u32 + number_of_sources: u32, + start_time: u64, // [seconds] + time_window: u64, // [seconds] + aggregation_mode: AggregationMode } #[derive(PartialEq, Copy, Drop, Serde)] @@ -277,10 +281,12 @@ mod DefaultExtensionPO { ref self: ContractState, singleton: ContractAddress, oracle_address: ContractAddress, + summary_address: ContractAddress, v_token_class_hash: felt252 ) { self.singleton.write(singleton); self.pragma_oracle.set_oracle(oracle_address); + self.pragma_oracle.set_summary_address(summary_address); self.tokenization.set_v_token_class_hash(v_token_class_hash); } @@ -573,10 +579,22 @@ mod DefaultExtensionPO { // set the oracle config let params = *pragma_oracle_params.pop_front().unwrap(); - let PragmaOracleParams { pragma_key, timeout, number_of_sources } = params; + let PragmaOracleParams { pragma_key, + timeout, + number_of_sources, + start_time, + time_window, + aggregation_mode } = + params; self .pragma_oracle - .set_oracle_config(pool_id, asset, OracleConfig { pragma_key, timeout, number_of_sources }); + .set_oracle_config( + pool_id, + asset, + OracleConfig { + pragma_key, timeout, number_of_sources, start_time, time_window, aggregation_mode + } + ); // set the interest rate model configuration let interest_rate_config = *interest_rate_configs.pop_front().unwrap(); @@ -682,7 +700,10 @@ mod DefaultExtensionPO { OracleConfig { pragma_key: pragma_oracle_params.pragma_key, timeout: pragma_oracle_params.timeout, - number_of_sources: pragma_oracle_params.number_of_sources + number_of_sources: pragma_oracle_params.number_of_sources, + start_time: pragma_oracle_params.start_time, + time_window: pragma_oracle_params.time_window, + aggregation_mode: pragma_oracle_params.aggregation_mode } ); diff --git a/src/test/mock_oracle.cairo b/src/test/mock_oracle.cairo index 508a156..0f027a3 100644 --- a/src/test/mock_oracle.cairo +++ b/src/test/mock_oracle.cairo @@ -1,7 +1,44 @@ -use vesu::vendor::pragma::{PragmaPricesResponse, DataType}; +use vesu::vendor::pragma::{PragmaPricesResponse, DataType, AggregationMode}; + +#[starknet::interface] +trait IMockPragmaSummary { + fn calculate_twap( + self: @TContractState, data_type: DataType, aggregation_mode: AggregationMode, time: u64, start_time: u64, + ) -> (u128, u32); + fn set_twap(ref self: TContractState, twap: u128, decimals: u32); +} + +#[starknet::contract] +mod MockPragmaSummary { + use starknet::{get_block_timestamp, get_caller_address}; + use vesu::{vendor::pragma::{DataType, AggregationMode}, test::mock_oracle::IMockPragmaSummary}; + + #[storage] + struct Storage { + twap: u128, + decimals: u32, + } + + #[abi(embed_v0)] + impl MockPragmaSummaryImpl of IMockPragmaSummary { + fn calculate_twap( + self: @ContractState, data_type: DataType, aggregation_mode: AggregationMode, time: u64, start_time: u64 + ) -> (u128, u32) { + (self.twap.read(), self.decimals.read()) + } + + fn set_twap(ref self: ContractState, twap: u128, decimals: u32) { + self.twap.write(twap); + self.decimals.write(decimals); + } + } +} #[starknet::interface] trait IMockPragmaOracle { + fn get_data( + ref self: TContractState, data_type: DataType, aggregation_mode: AggregationMode + ) -> PragmaPricesResponse; fn get_data_median(ref self: TContractState, data_type: DataType) -> PragmaPricesResponse; fn get_num_sources_aggregated(ref self: TContractState, key: felt252) -> u32; fn get_last_updated_timestamp(ref self: TContractState, key: felt252) -> u64; @@ -13,7 +50,7 @@ trait IMockPragmaOracle { #[starknet::contract] mod MockPragmaOracle { use starknet::{get_block_timestamp, get_caller_address}; - use vesu::{vendor::pragma::{PragmaPricesResponse, DataType}, test::mock_oracle::IMockPragmaOracle}; + use vesu::{vendor::pragma::{PragmaPricesResponse, DataType, AggregationMode}, test::mock_oracle::IMockPragmaOracle}; #[derive(Copy, Drop, Serde)] struct BaseEntry { @@ -68,6 +105,12 @@ mod MockPragmaOracle { } } + fn get_data( + ref self: ContractState, data_type: DataType, aggregation_mode: AggregationMode + ) -> PragmaPricesResponse { + self.get_data_median(data_type) + } + fn get_data_median(ref self: ContractState, data_type: DataType) -> PragmaPricesResponse { match data_type { DataType::SpotEntry(key) => { diff --git a/src/test/setup.cairo b/src/test/setup.cairo index c497221..ce2d084 100644 --- a/src/test/setup.cairo +++ b/src/test/setup.cairo @@ -16,8 +16,11 @@ use vesu::{ IDefaultExtensionCLDispatcher, IDefaultExtensionCLDispatcherTrait, ChainlinkOracleParams }, vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, math::{pow_10}, - vendor::pragma::{IPragmaABIDispatcher, IPragmaABIDispatcherTrait}, - test::mock_oracle::{IMockPragmaOracleDispatcher, IMockPragmaOracleDispatcherTrait}, + vendor::pragma::{IPragmaABIDispatcher, IPragmaABIDispatcherTrait, AggregationMode}, + test::mock_oracle::{ + IMockPragmaOracleDispatcher, IMockPragmaOracleDispatcherTrait, IMockPragmaSummaryDispatcher, + IMockPragmaSummaryDispatcherTrait + }, test::mock_chainlink_aggregator::{IMockChainlinkAggregatorDispatcher, IMockChainlinkAggregatorDispatcherTrait} }; @@ -134,10 +137,15 @@ fn setup_env( } }; + let mock_pragma_summary = IMockPragmaSummaryDispatcher { contract_address: deploy_contract("MockPragmaSummary") }; + let v_token_class_hash = declare("VToken").class_hash; let args = array![ - singleton.contract_address.into(), mock_pragma_oracle.contract_address.into(), v_token_class_hash.into() + singleton.contract_address.into(), + mock_pragma_oracle.contract_address.into(), + mock_pragma_summary.contract_address.into(), + v_token_class_hash.into() ]; let extension = IDefaultExtensionDispatcher { contract_address: deploy_with_args("DefaultExtensionPO", args) }; @@ -273,11 +281,28 @@ fn create_pool( }; let collateral_asset_oracle_params = PragmaOracleParams { - pragma_key: COLL_PRAGMA_KEY, timeout: 0, number_of_sources: 2 + pragma_key: COLL_PRAGMA_KEY, + timeout: 0, + number_of_sources: 2, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) + }; + let debt_asset_oracle_params = PragmaOracleParams { + pragma_key: DEBT_PRAGMA_KEY, + timeout: 0, + number_of_sources: 2, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) }; - let debt_asset_oracle_params = PragmaOracleParams { pragma_key: DEBT_PRAGMA_KEY, timeout: 0, number_of_sources: 2 }; let third_asset_oracle_params = PragmaOracleParams { - pragma_key: THIRD_PRAGMA_KEY, timeout: 0, number_of_sources: 2 + pragma_key: THIRD_PRAGMA_KEY, + timeout: 0, + number_of_sources: 2, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) }; let collateral_asset_v_token_params = VTokenParams { v_token_name: 'Vesu Collateral', v_token_symbol: 'vCOLL' }; diff --git a/src/test/test_default_extension_po.cairo b/src/test/test_default_extension_po.cairo index 01a6705..5cb9b1e 100644 --- a/src/test/test_default_extension_po.cairo +++ b/src/test/test_default_extension_po.cairo @@ -5,7 +5,7 @@ mod TestDefaultExtensionPO { use vesu::{ units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS, INFLATION_FEE}, test::setup::{setup_env, create_pool, TestConfig, deploy_assets, deploy_asset, Env}, - vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, + vendor::{erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, pragma::{AggregationMode}}, singleton::{ISingletonDispatcherTrait}, data_model::{AssetParams, LTVParams, LTVConfig}, extension::default_extension_po::{ InterestRateConfig, PragmaOracleParams, LiquidationParams, IDefaultExtensionDispatcherTrait, ShutdownParams, @@ -200,7 +200,12 @@ mod TestDefaultExtensionPO { }; let collateral_asset_oracle_params = PragmaOracleParams { - pragma_key: COLL_PRAGMA_KEY, timeout: 0, number_of_sources: 2 + pragma_key: COLL_PRAGMA_KEY, + timeout: 0, + number_of_sources: 2, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) }; let asset_params = array![collateral_asset_params].span(); @@ -271,7 +276,14 @@ mod TestDefaultExtensionPO { target_rate_percent: 20 * PERCENT, }; - let pragma_oracle_params = PragmaOracleParams { pragma_key: COLL_PRAGMA_KEY, timeout: 1, number_of_sources: 2 }; + let pragma_oracle_params = PragmaOracleParams { + pragma_key: COLL_PRAGMA_KEY, + timeout: 1, + number_of_sources: 2, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) + }; extension .add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params, 0); @@ -309,7 +321,14 @@ mod TestDefaultExtensionPO { target_rate_percent: 20 * PERCENT, }; - let pragma_oracle_params = PragmaOracleParams { pragma_key: COLL_PRAGMA_KEY, timeout: 1, number_of_sources: 2 }; + let pragma_oracle_params = PragmaOracleParams { + pragma_key: COLL_PRAGMA_KEY, + timeout: 1, + number_of_sources: 2, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) + }; start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); config.collateral_asset.approve(extension.contract_address, INFLATION_FEE); @@ -358,7 +377,12 @@ mod TestDefaultExtensionPO { }; let pragma_oracle_params = PragmaOracleParams { - pragma_key: Zeroable::zero(), timeout: 1, number_of_sources: 2 + pragma_key: Zeroable::zero(), + timeout: 1, + number_of_sources: 2, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) }; start_prank(CheatTarget::One(asset.contract_address), users.creator); @@ -406,7 +430,14 @@ mod TestDefaultExtensionPO { target_rate_percent: 20 * PERCENT, }; - let pragma_oracle_params = PragmaOracleParams { pragma_key: COLL_PRAGMA_KEY, timeout: 1, number_of_sources: 2 }; + let pragma_oracle_params = PragmaOracleParams { + pragma_key: COLL_PRAGMA_KEY, + timeout: 1, + number_of_sources: 2, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) + }; start_prank(CheatTarget::One(asset.contract_address), users.creator); asset.approve(extension.contract_address, INFLATION_FEE); diff --git a/src/test/test_forking.cairo b/src/test/test_forking.cairo index b4002c4..fc98dba 100644 --- a/src/test/test_forking.cairo +++ b/src/test/test_forking.cairo @@ -28,7 +28,8 @@ mod TestForking { }, vendor::{ erc20::{ERC20ABIDispatcher, ERC20ABIDispatcherTrait}, - chainlink::{IChainlinkAggregatorDispatcher, IChainlinkAggregatorDispatcherTrait, Round} + chainlink::{IChainlinkAggregatorDispatcher, IChainlinkAggregatorDispatcherTrait, Round}, + pragma::{AggregationMode} }, extension::{ interface::{IExtensionDispatcher, IExtensionDispatcherTrait}, @@ -193,6 +194,9 @@ mod TestForking { let pragma_oracle_address = contract_address_const::< 0x2a85bd616f912537c50a49a4076db02c00b29b2cdc8a197ce92ed1837fa875b >(); + let summary_stats_address = contract_address_const::< + 0x049eefafae944d07744d07cc72a5bf14728a6fb463c3eae5bca13552f5d455fd + >(); let eth_asset_params = AssetParams { asset: contract_address_const::<0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7>(), @@ -204,7 +208,14 @@ mod TestForking { fee_rate: 0 }; - let eth_asset_oracle_params = PragmaOracleParams { pragma_key: 'ETH/USD', timeout: 0, number_of_sources: 0 }; + let eth_asset_oracle_params = PragmaOracleParams { + pragma_key: 'ETH/USD', + timeout: 0, + number_of_sources: 0, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) + }; let eth_asset_v_token_params = VTokenParams { v_token_name: 'Vesu Ethereum', v_token_symbol: 'vETH' }; @@ -218,7 +229,14 @@ mod TestForking { fee_rate: 0 }; - let wbtc_asset_oracle_params = PragmaOracleParams { pragma_key: 'WBTC/USD', timeout: 0, number_of_sources: 0 }; + let wbtc_asset_oracle_params = PragmaOracleParams { + pragma_key: 'WBTC/USD', + timeout: 0, + number_of_sources: 0, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) + }; let wbtc_asset_v_token_params = VTokenParams { v_token_name: 'Vesu Wrapped Bitcoin', v_token_symbol: 'vWBTC' }; @@ -232,7 +250,14 @@ mod TestForking { fee_rate: 0 }; - let usdc_asset_oracle_params = PragmaOracleParams { pragma_key: 'USDC/USD', timeout: 0, number_of_sources: 2 }; + let usdc_asset_oracle_params = PragmaOracleParams { + pragma_key: 'USDC/USD', + timeout: 0, + number_of_sources: 2, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) + }; let usdc_asset_v_token_params = VTokenParams { v_token_name: 'Vesu USD Coin', v_token_symbol: 'vUSDC' }; @@ -246,7 +271,14 @@ mod TestForking { fee_rate: 0 }; - let usdt_asset_oracle_params = PragmaOracleParams { pragma_key: 'USDT/USD', timeout: 0, number_of_sources: 0 }; + let usdt_asset_oracle_params = PragmaOracleParams { + pragma_key: 'USDT/USD', + timeout: 0, + number_of_sources: 0, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) + }; let usdt_asset_v_token_params = VTokenParams { v_token_name: 'Vesu Tether', v_token_symbol: 'vUSDT' }; @@ -261,7 +293,12 @@ mod TestForking { }; let wsteth_asset_oracle_params = PragmaOracleParams { - pragma_key: 'WSTETH/USD', timeout: 0, number_of_sources: 0 + pragma_key: 'WSTETH/USD', + timeout: 0, + number_of_sources: 0, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) }; let wsteth_asset_v_token_params = VTokenParams { @@ -278,7 +315,14 @@ mod TestForking { fee_rate: 0 }; - let strk_asset_oracle_params = PragmaOracleParams { pragma_key: 'STRK/USD', timeout: 0, number_of_sources: 0 }; + let strk_asset_oracle_params = PragmaOracleParams { + pragma_key: 'STRK/USD', + timeout: 0, + number_of_sources: 0, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) + }; let strk_asset_v_token_params = VTokenParams { v_token_name: 'Vesu Starknet', v_token_symbol: 'vSTRK' }; @@ -436,7 +480,12 @@ mod TestForking { let extension = IDefaultExtensionDispatcher { contract_address: deploy_with_args( "DefaultExtensionPO", - array![singleton.contract_address.into(), pragma_oracle_address.into(), v_token_class_hash.into()] + array![ + singleton.contract_address.into(), + pragma_oracle_address.into(), + summary_stats_address.into(), + v_token_class_hash.into() + ] ) }; diff --git a/src/test/test_pragma_oracle.cairo b/src/test/test_pragma_oracle.cairo index a05348e..31c8093 100644 --- a/src/test/test_pragma_oracle.cairo +++ b/src/test/test_pragma_oracle.cairo @@ -19,6 +19,7 @@ mod TestPragmaOracle { } }, data_model::{AssetParams, LTVParams}, math::pow_10, common::{is_collateralized}, + vendor::pragma::{AggregationMode} }; @@ -64,9 +65,21 @@ mod TestPragmaOracle { }; let collateral_asset_oracle_params = PragmaOracleParams { - pragma_key: COLL_PRAGMA_KEY, timeout, number_of_sources + pragma_key: COLL_PRAGMA_KEY, + timeout, + number_of_sources, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) + }; + let debt_asset_oracle_params = PragmaOracleParams { + pragma_key: DEBT_PRAGMA_KEY, + timeout, + number_of_sources, + start_time: 0, + time_window: 0, + aggregation_mode: AggregationMode::Median(()) }; - let debt_asset_oracle_params = PragmaOracleParams { pragma_key: DEBT_PRAGMA_KEY, timeout, number_of_sources }; let collateral_asset_v_token_params = VTokenParams { v_token_name: 'Vesu Collateral', v_token_symbol: 'vCOLL' }; let debt_asset_v_token_params = VTokenParams { v_token_name: 'Vesu Debt', v_token_symbol: 'vDEBT' }; diff --git a/src/vendor/pragma.cairo b/src/vendor/pragma.cairo index 3a0bdde..2dc233f 100644 --- a/src/vendor/pragma.cairo +++ b/src/vendor/pragma.cairo @@ -1,3 +1,5 @@ +use starknet::ContractAddress; + #[derive(Drop, Copy, Serde)] enum DataType { SpotEntry: felt252, @@ -5,8 +7,9 @@ enum DataType { GenericEntry: felt252, } -#[derive(Serde, Drop, Copy)] +#[derive(Serde, Drop, Copy, PartialEq, Default, starknet::Store)] enum AggregationMode { + #[default] Median, Mean, Error, @@ -26,3 +29,10 @@ trait IPragmaABI { fn get_data(self: @TContractState, data_type: DataType, aggregation_mode: AggregationMode) -> PragmaPricesResponse; fn get_data_median(self: @TContractState, data_type: DataType) -> PragmaPricesResponse; } + +#[starknet::interface] +trait ISummaryStatsABI { + fn calculate_twap( + self: @TContractState, data_type: DataType, aggregation_mode: AggregationMode, time: u64, start_time: u64, + ) -> (u128, u32); +} From 89f05eee120baf684f7131e71ebdbedf1f159410 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 20 Nov 2024 16:36:32 +0000 Subject: [PATCH 13/32] Update scripts --- gas-report.txt | 20 ++++++++++---------- lib/config.devnet.ts | 16 ++++++++++++---- lib/config.mainnet.ts | 20 ++++++++++++++------ lib/config.sepolia.ts | 20 ++++++++++++++------ lib/deployer.protocol.ts | 21 +++++++++++++++------ lib/rates.ts | 4 ++-- package.json | 2 +- scripts/deployDevnet.ts | 8 ++++++-- scripts/deploySepolia.ts | 32 ++++++++++++++++---------------- scripts/gasReport.ts | 36 ++++++++++++++++++------------------ yarn.lock | 4 ++-- 11 files changed, 110 insertions(+), 73 deletions(-) diff --git a/gas-report.txt b/gas-report.txt index 39fff72..71c001c 100644 --- a/gas-report.txt +++ b/gas-report.txt @@ -2,19 +2,19 @@ Summary: ┌─────────────┬─────────────────────────┬─────────┬────────────────┬────────────────┬─────────────────┬───────────┬──────────────┬──────────────────────────────┬───────────────┬──────────────────┬─────────┐ │ (index) │ Actual fee │ Fee usd │ Fee without DA │ Gas without DA │ Computation gas │ Event gas │ Calldata gas │ Max computation per Category │ Storage diffs │ DA fee │ DA mode │ ├─────────────┼─────────────────────────┼─────────┼────────────────┼────────────────┼─────────────────┼───────────┼──────────────┼──────────────────────────────┼───────────────┼──────────────────┼─────────┤ -│ Create pool │ '1.720.844.000.000.000' │ 6.8833 │ 56844000000000 │ 1579 │ 1517 │ 238 │ 62 │ 'range_check' │ 243 │ 1664000000000000 │ 'BLOB' │ -│ Lend │ '106.340.000.000.000' │ 0.4253 │ 16740000000000 │ 465 │ 463 │ 12 │ 2 │ 'range_check' │ 11 │ 89600000000000 │ 'BLOB' │ -│ Transfer │ '102.684.000.000.000' │ 0.4107 │ 25884000000000 │ 719 │ 717 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ -│ Borrow │ '141.220.000.000.000' │ 0.5648 │ 19620000000000 │ 545 │ 543 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ -│ Liquidate │ '143.344.000.000.000' │ 0.5733 │ 21744000000000 │ 604 │ 602 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ +│ Create pool │ '1.721.348.000.000.000' │ 6.8853 │ 57348000000000 │ 1593 │ 1529 │ 240 │ 64 │ 'range_check' │ 243 │ 1664000000000000 │ 'BLOB' │ +│ Lend │ '106.412.000.000.000' │ 0.4256 │ 16812000000000 │ 467 │ 465 │ 12 │ 2 │ 'range_check' │ 11 │ 89600000000000 │ 'BLOB' │ +│ Transfer │ '102.792.000.000.000' │ 0.4111 │ 25992000000000 │ 722 │ 720 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ +│ Borrow │ '141.004.000.000.000' │ 0.564 │ 19404000000000 │ 539 │ 537 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ +│ Liquidate │ '143.668.000.000.000' │ 0.5746 │ 22068000000000 │ 613 │ 611 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ └─────────────┴─────────────────────────┴─────────┴────────────────┴────────────────┴─────────────────┴───────────┴──────────────┴──────────────────────────────┴───────────────┴──────────────────┴─────────┘ Resources: ┌─────────────┬─────────┬───────┬───────┬────────┬──────────┬──────────┬─────────────┬────────┐ │ (index) │ bitwise │ ec_op │ ecdsa │ keccak │ pedersen │ poseidon │ range_check │ steps │ ├─────────────┼─────────┼───────┼───────┼────────┼──────────┼──────────┼─────────────┼────────┤ -│ Create pool │ 138 │ 3 │ 0 │ 0 │ 1543 │ 1 │ 37924 │ 540429 │ -│ Lend │ 26 │ 3 │ 0 │ 0 │ 130 │ 0 │ 11575 │ 95937 │ -│ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17922 │ 142569 │ -│ Borrow │ 33 │ 3 │ 0 │ 0 │ 142 │ 0 │ 13551 │ 108517 │ -│ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15044 │ 117436 │ +│ Create pool │ 138 │ 3 │ 0 │ 0 │ 1561 │ 1 │ 38224 │ 551983 │ +│ Lend │ 26 │ 3 │ 0 │ 0 │ 130 │ 0 │ 11619 │ 97469 │ +│ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17988 │ 144867 │ +│ Borrow │ 33 │ 3 │ 0 │ 0 │ 142 │ 0 │ 13415 │ 109845 │ +│ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15268 │ 119172 │ └─────────────┴─────────┴───────┴───────┴────────┴──────────┴──────────┴─────────────┴────────┘ diff --git a/lib/config.devnet.ts b/lib/config.devnet.ts index 45729bb..aa61fbf 100644 --- a/lib/config.devnet.ts +++ b/lib/config.devnet.ts @@ -1,3 +1,4 @@ +import { CairoCustomEnum } from "starknet"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; @@ -27,7 +28,7 @@ const env = CONFIG.asset_parameters.map( asset.token.symbol, BigInt(asset.token.decimals), toScale(10000), - asset.oracle.pragma_key, + asset.pragma.pragma_key, price(asset.token.symbol), asset.token.is_legacy, BigInt(asset.fee_rate), @@ -41,8 +42,12 @@ export const config: Config = { name: "devnet", protocol: { singleton: "0x0", - extension: "0x0", - oracle: "0x0", + extensionPO: "0x0", + extensionCL: "0x0", + pragma: { + oracle: "0x0", + summary_stats: "0x0", + } }, env, pools: { @@ -85,9 +90,12 @@ export const config: Config = { target_rate_percent: toScale(asset.target_rate_percent), })), pragma_oracle_params: CONFIG.asset_parameters.map((asset: any) => ({ - pragma_key: asset.oracle.pragma_key, + pragma_key: asset.pragma.pragma_key, timeout: 0n, number_of_sources: 0n, + start_time: 0n, // BigInt(asset.pragma.start_time), + time_window: 0n, // BigInt(asset.pragma.time_window), + aggregation_mode: new CairoCustomEnum({ Median: {} }), // new CairoCustomEnum({ [(asset.pragma.aggregation_mode == 0) ? "Median" : "Error"]: {} }) })), liquidation_params: CONFIG.pair_parameters.map((pair: any) => { const collateral_asset_index = CONFIG.asset_parameters.findIndex( diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index f6d5379..87ef982 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -1,3 +1,4 @@ +import { CairoCustomEnum } from "starknet"; import fs from "fs"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; @@ -14,7 +15,7 @@ const env = CONFIG.asset_parameters.map( asset.token.symbol, BigInt(asset.token.decimals), 0n, - asset.oracle.pragma_key, + asset.pragma.pragma_key, 0n, asset.token.is_legacy, BigInt(asset.fee_rate), @@ -28,8 +29,12 @@ export const config: Config = { name: "mainnet", protocol: { singleton: DEPLOYMENT.singleton || "0x0", - extension: DEPLOYMENT.extension || "0x0", - oracle: DEPLOYMENT.oracle || CONFIG.asset_parameters[0].oracle.address, + extensionPO: DEPLOYMENT.extensionPO || "0x0", + extensionCL: DEPLOYMENT.extensionCL || "0x0", + pragma: { + oracle: DEPLOYMENT.oracle || CONFIG.asset_parameters[0].pragma.oracle, + summary_stats: DEPLOYMENT.summary_stats || CONFIG.asset_parameters[0].pragma.oracle, + }, }, env, pools: { @@ -72,9 +77,12 @@ export const config: Config = { target_rate_percent: toScale(asset.target_rate_percent), })), pragma_oracle_params: CONFIG.asset_parameters.map((asset: any) => ({ - pragma_key: asset.oracle.pragma_key, - timeout: BigInt(asset.oracle.timeout), - number_of_sources: BigInt(asset.oracle.number_of_sources), + pragma_key: asset.pragma.pragma_key, + timeout: BigInt(asset.pragma.timeout), + number_of_sources: BigInt(asset.pragma.number_of_sources), + start_time: 0n, // BigInt(asset.pragma.start_time), + time_window: 0n, // BigInt(asset.pragma.time_window), + aggregation_mode: new CairoCustomEnum({ Median: {} }), // new CairoCustomEnum({ [(asset.pragma.aggregation_mode == 0) ? "Median" : "Error"]: {} }) })), liquidation_params: CONFIG.pair_parameters.map((pair: any) => { const collateral_asset_index = CONFIG.asset_parameters.findIndex( diff --git a/lib/config.sepolia.ts b/lib/config.sepolia.ts index fcfd6e9..6e75a3a 100644 --- a/lib/config.sepolia.ts +++ b/lib/config.sepolia.ts @@ -1,3 +1,4 @@ +import { CairoCustomEnum } from "starknet"; import fs from "fs"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; @@ -33,7 +34,7 @@ const env = CONFIG.asset_parameters.map( asset.token.symbol, BigInt(asset.token.decimals), toScale(10000), - asset.oracle.pragma_key, + asset.pragma.pragma_key, price(asset.token.symbol), asset.token.is_legacy, BigInt(asset.fee_rate), @@ -47,8 +48,12 @@ export const config: Config = { name: "sepolia", protocol: { singleton: DEPLOYMENT.singleton || "0x0", - extension: DEPLOYMENT.extension || "0x0", - oracle: DEPLOYMENT.oracle || "0x0", + extensionPO: DEPLOYMENT.extensionPO || "0x0", + extensionCL: DEPLOYMENT.extensionCL || "0x0", + pragma: { + oracle: DEPLOYMENT.oracle || CONFIG.asset_parameters[0].pragma.oracle || "0x0", + summary_stats: DEPLOYMENT.summary_stats || CONFIG.asset_parameters[0].pragma.oracle || "0x0", + }, }, env, pools: { @@ -91,9 +96,12 @@ export const config: Config = { target_rate_percent: toScale(asset.target_rate_percent), })), pragma_oracle_params: CONFIG.asset_parameters.map((asset: any) => ({ - pragma_key: asset.oracle.pragma_key, - timeout: 0n, // BigInt(asset.oracle.timeout), - number_of_sources: 0n, // BigInt(asset.oracle.number_of_sources), + pragma_key: asset.pragma.pragma_key, + timeout: 0n, // BigInt(asset.pragma.timeout), + number_of_sources: 0n, // BigInt(asset.pragma.number_of_sources), + start_time: 0n, // BigInt(asset.pragma.start_time), + time_window: 0n, // BigInt(asset.pragma.time_window), + aggregation_mode: new CairoCustomEnum({ Median: {} }), // new CairoCustomEnum({ [(asset.pragma.aggregation_mode == 0) ? "Median" : "Error"]: {} }) })), liquidation_params: CONFIG.pair_parameters.map((pair: any) => { const collateral_asset_index = CONFIG.asset_parameters.findIndex( diff --git a/lib/deployer.protocol.ts b/lib/deployer.protocol.ts index fdfbe22..e0f26da 100644 --- a/lib/deployer.protocol.ts +++ b/lib/deployer.protocol.ts @@ -3,6 +3,11 @@ import { unzip } from "lodash-es"; import { Account, Call, CallData, Contract, RpcProvider } from "starknet"; import { BaseDeployer, Config, Protocol, logAddresses } from "."; +export interface PragmaConfig { + oracle: string | undefined; + summary_stats: string | undefined; +} + export interface PragmaContracts { oracle: Contract; summary_stats: Contract; @@ -31,7 +36,11 @@ export class Deployer extends BaseDeployer { async deployEnvAndProtocol(): Promise { assert(this.config.env, "Test environment not defined, use loadProtocol for existing networks"); const [envContracts, envCalls] = await this.deferEnv(); - const [protocolContracts, protocolCalls] = await this.deferProtocol(envContracts.pragma); + const pragma = { + oracle: envContracts.pragma.oracle.address, + summary_stats: envContracts.pragma.summary_stats.address, + }; + const [protocolContracts, protocolCalls] = await this.deferProtocol(pragma); let response = await this.execute([...envCalls, ...protocolCalls]); await this.waitForTransaction(response.transaction_hash); const contracts = { ...protocolContracts, ...envContracts }; @@ -61,20 +70,20 @@ export class Deployer extends BaseDeployer { return Protocol.from(contracts, this); } - async deployProtocol(pragma: PragmaContracts) { + async deployProtocol(pragma: PragmaConfig) { const [contracts, calls] = await this.deferProtocol(pragma); const response = await this.execute([...calls]); await this.waitForTransaction(response.transaction_hash); return [contracts, response] as const; } - async deferProtocol(pragma: PragmaContracts) { + async deferProtocol(pragma: PragmaConfig) { const [singleton, calls1] = await this.deferContract("Singleton"); const v_token_class_hash = await this.declareCached("VToken"); const calldataPO = CallData.compile({ singleton: singleton.address, - oracle_address: pragma.oracle.address, - summary_stats_address: pragma.summary_stats.address, + oracle_address: pragma.oracle!, + summary_stats_address: pragma.summary_stats!, v_token_class_hash: v_token_class_hash, }); const [extensionPO, calls2] = await this.deferContract("DefaultExtensionPO", calldataPO); @@ -120,7 +129,7 @@ export class Deployer extends BaseDeployer { async deferPragmaOracle() { const [oracle, oracleCalls] = await this.deferContract("MockPragmaOracle"); - const [summary_stats, summaryStatsCalls] = await this.deferContract("MockSummaryStats"); + const [summary_stats, summaryStatsCalls] = await this.deferContract("MockPragmaSummary"); const setupCalls = this.config.env!.map(({ pragmaKey, price }) => oracle.populateTransaction.set_price(pragmaKey, price), ); diff --git a/lib/rates.ts b/lib/rates.ts index 1037e5c..6428d02 100644 --- a/lib/rates.ts +++ b/lib/rates.ts @@ -5,7 +5,7 @@ const UTILIZATION_SCALE = 10n ** 5n; const UTILIZATION_SCALE_TO_SCALE = 10n ** 13n; export async function calculateRates( - { singleton, extension }: ProtocolContracts, + { singleton, extensionPO }: ProtocolContracts, poolId: bigint, asset: string, interest_rate_config: InterestRateConfig, @@ -19,7 +19,7 @@ export async function calculateRates( const offchainRate = calculateInterestRate(interest_rate_config, utilization, timeDelta, lastFullUtilizationRate); // onchain, comment out in prod - const onchainRate = await extension.interest_rate(poolId, asset, utilization, lastUpdated, lastFullUtilizationRate); + const onchainRate = await extensionPO.interest_rate(poolId, asset, utilization, lastUpdated, lastFullUtilizationRate); assert(formatRate(Number(onchainRate) / 1e18) == formatRate(Number(offchainRate) / 1e18), "Offchain rate mismatch"); return toAnnualRates(offchainRate, asset_config); diff --git a/package.json b/package.json index 25d38d2..6b72305 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@types/lodash-es": "^4.17.12", "@types/node": "^20.10.5", "bignumber.js": "9.1.2", - "vesu_changelog": "https://github.com/vesuxyz/changelog.git#85eb833cbd196740c3d945d8481b369ddef73de3", + "vesu_changelog": "https://github.com/vesuxyz/changelog.git#921891b7e9afa7b66fefc386ba29bb2f4de08bc5", "dotenv": "^16.3.1", "lodash-es": "^4.17.21", "prettier": "^3.1.1", diff --git a/scripts/deployDevnet.ts b/scripts/deployDevnet.ts index aaf6adb..d5af5e7 100644 --- a/scripts/deployDevnet.ts +++ b/scripts/deployDevnet.ts @@ -7,8 +7,12 @@ const protocol = await deployer.deployEnvAndProtocol(); const deployment = { singleton: protocol.singleton.address, - extension: protocol.extension.address, - oracle: protocol.oracle.address, + extensionPO: protocol.extensionPO.address, + extensionCL: protocol.extensionCL.address, + pragma: { + oracle: protocol.pragma.oracle.address, + summary_stats: protocol.pragma.summary_stats.address, + }, assets: protocol.assets.map((asset) => asset.address), pools: [], }; diff --git a/scripts/deploySepolia.ts b/scripts/deploySepolia.ts index 2181ade..a0130c8 100644 --- a/scripts/deploySepolia.ts +++ b/scripts/deploySepolia.ts @@ -5,19 +5,19 @@ import { Amount, SCALE, formatRate, setup, toAddress, toI257 } from "../lib"; const deployer = await setup("sepolia"); const protocol = await deployer.deployEnvAndProtocol(); -const { singleton, assets, extension } = protocol; +const { singleton, assets, extensionPO } = protocol; // CREATE POOL const [pool] = await protocol.createPool("genesis-pool", { devnetEnv: true }); -assert(toAddress(await extension.pragma_oracle()) === protocol.oracle.address.toLowerCase(), "pragma_oracle-neq"); -assert(toAddress(await extension.pool_owner(pool.id)) === pool.params.owner.toLowerCase(), "pool_owner-neq"); +assert(toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), "pragma_oracle-neq"); +assert(toAddress(await extensionPO.pool_owner(pool.id)) === pool.params.owner.toLowerCase(), "pool_owner-neq"); assert( - toAddress((await extension.fee_config(pool.id)).fee_recipient) === pool.params.fee_params.fee_recipient.toLowerCase(), + toAddress((await extensionPO.fee_config(pool.id)).fee_recipient) === pool.params.fee_params.fee_recipient.toLowerCase(), "fee_recipient-neq", ); -const shutdown_config = await extension.shutdown_config(pool.id); +const shutdown_config = await extensionPO.shutdown_config(pool.id); assert(shutdown_config.recovery_period === pool.params.shutdown_params.recovery_period, "recovery_period-neq"); assert( shutdown_config.subscription_period === pool.params.shutdown_params.subscription_period, @@ -25,7 +25,7 @@ assert( ); for (const [index, asset] of assets.entries()) { - const oracle_config = await extension.oracle_config(pool.id, asset.address); + const oracle_config = await extensionPO.oracle_config(pool.id, asset.address); assert( shortString.decodeShortString(oracle_config.pragma_key) === pool.params.pragma_oracle_params[index].pragma_key, "pragma_key-neq", @@ -36,7 +36,7 @@ for (const [index, asset] of assets.entries()) { "number_of_sources-neq", ); - const interest_rate_config = await extension.interest_rate_config(pool.id, asset.address); + const interest_rate_config = await extensionPO.interest_rate_config(pool.id, asset.address); assert( interest_rate_config.min_target_utilization === pool.params.interest_rate_configs[index].min_target_utilization, "min_target_utilization-neq", @@ -85,7 +85,7 @@ for (const [index, asset] of assets.entries()) { assert(asset_config.last_full_utilization_rate > 0n, "last_full_utilization_rate-neq"); assert(asset_config.fee_rate === 0n, "fee_rate-neq"); - assert((await extension.price(pool.id, asset.address)).value > 0n, "price-neq"); + assert((await extensionPO.price(pool.id, asset.address)).value > 0n, "price-neq"); assert((await singleton.rate_accumulator_unsafe(pool.id, asset.address)) > 0n, "rate_accumulator-neq"); assert((await singleton.utilization_unsafe(pool.id, asset.address)) === 0n, "utilization-neq"); } @@ -144,9 +144,9 @@ assert(formatRate(supplyAPY) === "2.64%", `Incorrect supply APY: ${formatRate(su { // reduce oracle price - const { oracle } = protocol; - oracle.connect(deployer); - const response = await oracle.set_price("WBTC/USD", 10_000n * SCALE); + const { pragma } = protocol; + pragma.oracle.connect(deployer); + const response = await pragma.oracle.set_price("WBTC/USD", 10_000n * SCALE); await deployer.provider.waitForTransaction(response.transaction_hash); } @@ -169,16 +169,16 @@ assert(collateralized === false, "Not undercollateralized"); { // reset oracle price - const { oracle } = protocol; - oracle.connect(deployer); - const response = await oracle.set_price("WBTC/USD", 40_000n * SCALE); + const { pragma } = protocol; + pragma.oracle.connect(deployer); + const response = await pragma.oracle.set_price("WBTC/USD", 40_000n * SCALE); await deployer.provider.waitForTransaction(response.transaction_hash); } const deployment = { singleton: protocol.singleton.address, - extension: protocol.extension.address, - oracle: protocol.oracle.address, + extensionPO: protocol.extensionPO.address, + oracle: protocol.pragma.oracle.address, assets: protocol.assets.map((asset) => asset.address), pools: [pool.id.toString()], }; diff --git a/scripts/gasReport.ts b/scripts/gasReport.ts index 524dedc..b47cca6 100644 --- a/scripts/gasReport.ts +++ b/scripts/gasReport.ts @@ -4,7 +4,7 @@ import { Amount, SCALE, UnsignedAmount, formatRate, newProfiler, setup, toAddres const deployer = await setup(undefined); const protocol = await deployer.deployEnvAndProtocol(); -const { singleton, assets, extension } = protocol; +const { singleton, assets, extensionPO } = protocol; const profiler = newProfiler(deployer); // CREATE POOL @@ -14,14 +14,14 @@ console.log("Create pool"); const [pool, response] = await protocol.createPool("gas-report-pool", { devnetEnv: true }); await profiler.profile("Create pool", response); -assert(toAddress(await extension.pragma_oracle()) === protocol.oracle.address.toLowerCase(), "pragma_oracle-neq"); -assert(toAddress(await extension.pool_owner(pool.id)) === pool.params.owner.toLowerCase(), "pool_owner-neq"); +assert(toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), "pragma_oracle-neq"); +assert(toAddress(await extensionPO.pool_owner(pool.id)) === pool.params.owner.toLowerCase(), "pool_owner-neq"); assert( - toAddress((await extension.fee_config(pool.id)).fee_recipient) === pool.params.fee_params.fee_recipient.toLowerCase(), + toAddress((await extensionPO.fee_config(pool.id)).fee_recipient) === pool.params.fee_params.fee_recipient.toLowerCase(), "fee_recipient-neq", ); -const shutdown_config = await extension.shutdown_config(pool.id); +const shutdown_config = await extensionPO.shutdown_config(pool.id); assert(shutdown_config.recovery_period === pool.params.shutdown_params.recovery_period, "recovery_period-neq"); assert( shutdown_config.subscription_period === pool.params.shutdown_params.subscription_period, @@ -29,7 +29,7 @@ assert( ); for (const [index, asset] of assets.entries()) { - const oracle_config = await extension.oracle_config(pool.id, asset.address); + const oracle_config = await extensionPO.oracle_config(pool.id, asset.address); assert( shortString.decodeShortString(oracle_config.pragma_key) === pool.params.pragma_oracle_params[index].pragma_key, "pragma_key-neq", @@ -40,7 +40,7 @@ for (const [index, asset] of assets.entries()) { "number_of_sources-neq", ); - const interest_rate_config = await extension.interest_rate_config(pool.id, asset.address); + const interest_rate_config = await extensionPO.interest_rate_config(pool.id, asset.address); assert( interest_rate_config.min_target_utilization === pool.params.interest_rate_configs[index].min_target_utilization, "min_target_utilization-neq", @@ -92,7 +92,7 @@ for (const [index, asset] of assets.entries()) { assert(asset_config.last_full_utilization_rate > 0n, "last_full_utilization_rate-neq"); assert(asset_config.fee_rate === 0n, "fee_rate-neq"); - assert((await extension.price(pool.id, asset.address)).value > 0n, "price-neq"); + assert((await extensionPO.price(pool.id, asset.address)).value > 0n, "price-neq"); assert((await singleton.rate_accumulator_unsafe(pool.id, asset.address)) > 0n, "rate_accumulator-neq"); assert((await singleton.utilization_unsafe(pool.id, asset.address)) === 0n, "utilization-neq"); } @@ -133,7 +133,7 @@ const nominalDebtToDraw = await singleton.calculate_nominal_debt(toI257(debtToDr from_debt_asset: collateralAsset.address, to_debt_asset: "0x0", from_user: deployer.lender.address, - to_user: extension.address, + to_user: extensionPO.address, collateral: UnsignedAmount({ amountType: "Delta", denomination: "Assets", value: liquidityToDeposit }), debt: UnsignedAmount(), from_data: CallData.compile([]), @@ -144,14 +144,14 @@ const nominalDebtToDraw = await singleton.calculate_nominal_debt(toI257(debtToDr } { - const v_token_address = await extension.v_token_for_collateral_asset(pool.id, debtAsset.address); + const v_token_address = await extensionPO.v_token_for_collateral_asset(pool.id, debtAsset.address); const v_token = await protocol.deployer.loadContract(toAddress(v_token_address)); const balance = await v_token.balance_of(deployer.lender.address); assert(balance > 0n, "balance-neq"); { v_token.connect(deployer.lender); - const response = await v_token.approve(extension.address, balance); + const response = await v_token.approve(extensionPO.address, balance); await deployer.provider.waitForTransaction(response.transaction_hash); } @@ -160,7 +160,7 @@ const nominalDebtToDraw = await singleton.calculate_nominal_debt(toI257(debtToDr to_collateral_asset: debtAsset.address, from_debt_asset: "0x0", to_debt_asset: collateralAsset.address, - from_user: extension.address, + from_user: extensionPO.address, to_user: deployer.lender.address, collateral: UnsignedAmount({ amountType: "Delta", denomination: "Native", value: balance }), debt: UnsignedAmount(), @@ -200,9 +200,9 @@ assert(formatRate(supplyAPY) === "2.64%", `Incorrect supply APY: ${formatRate(su { // reduce oracle price - const { oracle } = protocol; - oracle.connect(deployer); - const response = await oracle.set_price("WBTC/USD", 10_000n * SCALE); + const { pragma } = protocol; + pragma.oracle.connect(deployer); + const response = await pragma.oracle.set_price("WBTC/USD", 10_000n * SCALE); await deployer.provider.waitForTransaction(response.transaction_hash); } @@ -226,9 +226,9 @@ assert(collateralized === false, "Not undercollateralized"); { // reset oracle price - const { oracle } = protocol; - oracle.connect(deployer); - const response = await oracle.set_price("WBTC/USD", 40_000n * SCALE); + const { pragma } = protocol; + pragma.oracle.connect(deployer); + const response = await pragma.oracle.set_price("WBTC/USD", 40_000n * SCALE); await deployer.provider.waitForTransaction(response.transaction_hash); } diff --git a/yarn.lock b/yarn.lock index 53b98a4..0a71a92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -429,9 +429,9 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -"vesu_changelog@https://github.com/vesuxyz/changelog.git#85eb833cbd196740c3d945d8481b369ddef73de3": +"vesu_changelog@https://github.com/vesuxyz/changelog.git#921891b7e9afa7b66fefc386ba29bb2f4de08bc5": version "0.0.0" - resolved "https://github.com/vesuxyz/changelog.git#85eb833cbd196740c3d945d8481b369ddef73de3" + resolved "https://github.com/vesuxyz/changelog.git#921891b7e9afa7b66fefc386ba29bb2f4de08bc5" webidl-conversions@^3.0.0: version "3.0.1" From 8e0489a6ee15ed603561be8b150a6e13e9424614 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 20 Nov 2024 16:37:19 +0000 Subject: [PATCH 14/32] Fmt --- lib/config.devnet.ts | 2 +- lib/config.mainnet.ts | 2 +- lib/config.sepolia.ts | 2 +- lib/deployer.protocol.ts | 7 ++----- scripts/deployMainnet.ts | 5 ++++- scripts/deploySepolia.ts | 8 ++++++-- scripts/gasReport.ts | 8 ++++++-- 7 files changed, 21 insertions(+), 13 deletions(-) diff --git a/lib/config.devnet.ts b/lib/config.devnet.ts index aa61fbf..e14c126 100644 --- a/lib/config.devnet.ts +++ b/lib/config.devnet.ts @@ -47,7 +47,7 @@ export const config: Config = { pragma: { oracle: "0x0", summary_stats: "0x0", - } + }, }, env, pools: { diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index 87ef982..a7f5902 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -1,5 +1,5 @@ -import { CairoCustomEnum } from "starknet"; import fs from "fs"; +import { CairoCustomEnum } from "starknet"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; diff --git a/lib/config.sepolia.ts b/lib/config.sepolia.ts index 6e75a3a..40e4be5 100644 --- a/lib/config.sepolia.ts +++ b/lib/config.sepolia.ts @@ -1,5 +1,5 @@ -import { CairoCustomEnum } from "starknet"; import fs from "fs"; +import { CairoCustomEnum } from "starknet"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; diff --git a/lib/deployer.protocol.ts b/lib/deployer.protocol.ts index e0f26da..01f3525 100644 --- a/lib/deployer.protocol.ts +++ b/lib/deployer.protocol.ts @@ -89,7 +89,7 @@ export class Deployer extends BaseDeployer { const [extensionPO, calls2] = await this.deferContract("DefaultExtensionPO", calldataPO); const calldataCL = CallData.compile({ singleton: singleton.address, - v_token_class_hash: v_token_class_hash + v_token_class_hash: v_token_class_hash, }); const [extensionCL, calls3] = await this.deferContract("DefaultExtensionCL", calldataCL); return [{ singleton, extensionPO, extensionCL }, [...calls1, ...calls2, ...calls3]] as const; @@ -105,10 +105,7 @@ export class Deployer extends BaseDeployer { async deferEnv() { const [assets, assetCalls] = await this.deferMockAssets(this.lender.address); const [oracle, summary_stats, pragmaCalls] = await this.deferPragmaOracle(); - return [ - { assets, pragma: { oracle, summary_stats } }, - [...assetCalls, ...pragmaCalls] - ] as const; + return [{ assets, pragma: { oracle, summary_stats } }, [...assetCalls, ...pragmaCalls]] as const; } async deferMockAssets(recipient: string) { diff --git a/scripts/deployMainnet.ts b/scripts/deployMainnet.ts index 808adba..484771f 100644 --- a/scripts/deployMainnet.ts +++ b/scripts/deployMainnet.ts @@ -16,7 +16,10 @@ const { singleton, assets, extensionPO } = protocol; const [pool] = await protocol.createPool("genesis-pool"); console.log("Pool ID: ", pool.id.toString()); -assert(toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), "pragma_oracle-neq"); +assert( + toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), + "pragma_oracle-neq", +); // assert(toAddress(await extension.pool_owner(pool.id)) === pool.params.owner.toLowerCase(), "pool_owner-neq"); // assert( // toAddress((await extension.fee_config(pool.id)).fee_recipient) === pool.params.fee_params.fee_recipient.toLowerCase(), diff --git a/scripts/deploySepolia.ts b/scripts/deploySepolia.ts index a0130c8..48e04d3 100644 --- a/scripts/deploySepolia.ts +++ b/scripts/deploySepolia.ts @@ -11,10 +11,14 @@ const { singleton, assets, extensionPO } = protocol; const [pool] = await protocol.createPool("genesis-pool", { devnetEnv: true }); -assert(toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), "pragma_oracle-neq"); +assert( + toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), + "pragma_oracle-neq", +); assert(toAddress(await extensionPO.pool_owner(pool.id)) === pool.params.owner.toLowerCase(), "pool_owner-neq"); assert( - toAddress((await extensionPO.fee_config(pool.id)).fee_recipient) === pool.params.fee_params.fee_recipient.toLowerCase(), + toAddress((await extensionPO.fee_config(pool.id)).fee_recipient) === + pool.params.fee_params.fee_recipient.toLowerCase(), "fee_recipient-neq", ); const shutdown_config = await extensionPO.shutdown_config(pool.id); diff --git a/scripts/gasReport.ts b/scripts/gasReport.ts index b47cca6..ca55c8d 100644 --- a/scripts/gasReport.ts +++ b/scripts/gasReport.ts @@ -14,10 +14,14 @@ console.log("Create pool"); const [pool, response] = await protocol.createPool("gas-report-pool", { devnetEnv: true }); await profiler.profile("Create pool", response); -assert(toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), "pragma_oracle-neq"); +assert( + toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), + "pragma_oracle-neq", +); assert(toAddress(await extensionPO.pool_owner(pool.id)) === pool.params.owner.toLowerCase(), "pool_owner-neq"); assert( - toAddress((await extensionPO.fee_config(pool.id)).fee_recipient) === pool.params.fee_params.fee_recipient.toLowerCase(), + toAddress((await extensionPO.fee_config(pool.id)).fee_recipient) === + pool.params.fee_params.fee_recipient.toLowerCase(), "fee_recipient-neq", ); From 53852cb43530cb5fa5791857ea8cac3711f5843c Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:09:45 +0000 Subject: [PATCH 15/32] Add test for twap --- lib/config.devnet.ts | 2 +- lib/config.mainnet.ts | 2 +- lib/config.sepolia.ts | 2 +- src/extension/components/pragma_oracle.cairo | 25 ++++++--- src/extension/default_extension_po.cairo | 16 ++++-- src/test/mock_oracle.cairo | 14 +++-- src/test/setup.cairo | 6 +- src/test/test_default_extension_po.cairo | 10 ++-- src/test/test_forking.cairo | 24 +++++--- src/test/test_pragma_oracle.cairo | 59 ++++++++++++++++++-- src/vendor/pragma.cairo | 2 +- 11 files changed, 120 insertions(+), 42 deletions(-) diff --git a/lib/config.devnet.ts b/lib/config.devnet.ts index e14c126..2db263b 100644 --- a/lib/config.devnet.ts +++ b/lib/config.devnet.ts @@ -93,7 +93,7 @@ export const config: Config = { pragma_key: asset.pragma.pragma_key, timeout: 0n, number_of_sources: 0n, - start_time: 0n, // BigInt(asset.pragma.start_time), + start_time_offset: 0n, // BigInt(asset.pragma.start_time_offset), time_window: 0n, // BigInt(asset.pragma.time_window), aggregation_mode: new CairoCustomEnum({ Median: {} }), // new CairoCustomEnum({ [(asset.pragma.aggregation_mode == 0) ? "Median" : "Error"]: {} }) })), diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index a7f5902..f0697f7 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -80,7 +80,7 @@ export const config: Config = { pragma_key: asset.pragma.pragma_key, timeout: BigInt(asset.pragma.timeout), number_of_sources: BigInt(asset.pragma.number_of_sources), - start_time: 0n, // BigInt(asset.pragma.start_time), + start_time_offset: 0n, // BigInt(asset.pragma.start_time_offset), time_window: 0n, // BigInt(asset.pragma.time_window), aggregation_mode: new CairoCustomEnum({ Median: {} }), // new CairoCustomEnum({ [(asset.pragma.aggregation_mode == 0) ? "Median" : "Error"]: {} }) })), diff --git a/lib/config.sepolia.ts b/lib/config.sepolia.ts index 40e4be5..2befcea 100644 --- a/lib/config.sepolia.ts +++ b/lib/config.sepolia.ts @@ -99,7 +99,7 @@ export const config: Config = { pragma_key: asset.pragma.pragma_key, timeout: 0n, // BigInt(asset.pragma.timeout), number_of_sources: 0n, // BigInt(asset.pragma.number_of_sources), - start_time: 0n, // BigInt(asset.pragma.start_time), + start_time_offset: 0n, // BigInt(asset.pragma.start_time_offset), time_window: 0n, // BigInt(asset.pragma.time_window), aggregation_mode: new CairoCustomEnum({ Median: {} }), // new CairoCustomEnum({ [(asset.pragma.aggregation_mode == 0) ? "Median" : "Error"]: {} }) })), diff --git a/src/extension/components/pragma_oracle.cairo b/src/extension/components/pragma_oracle.cairo index 09c6ac5..6728a2a 100644 --- a/src/extension/components/pragma_oracle.cairo +++ b/src/extension/components/pragma_oracle.cairo @@ -5,7 +5,7 @@ struct OracleConfig { pragma_key: felt252, timeout: u64, // [seconds] number_of_sources: u32, // [0, 255] - start_time: u64, // [seconds] + start_time_offset: u64, // [seconds] time_window: u64, // [seconds] aggregation_mode: AggregationMode } @@ -13,8 +13,8 @@ struct OracleConfig { fn assert_oracle_config(oracle_config: OracleConfig) { assert!(oracle_config.pragma_key != 0, "pragma-key-must-be-set"); assert!( - (oracle_config.start_time == 0 && oracle_config.time_window == 0) - || (oracle_config.start_time != 0 && oracle_config.time_window != 0), + (oracle_config.start_time_offset == 0 && oracle_config.time_window == 0) + || (oracle_config.start_time_offset != 0 && oracle_config.time_window != 0), "pragma-start-time-and-time-window-must-be-set-together" ); } @@ -101,21 +101,30 @@ mod pragma_oracle_component { /// * `price` - current price of the asset /// * `valid` - whether the price is valid fn price(self: @ComponentState, pool_id: felt252, asset: ContractAddress) -> (u256, bool) { - let OracleConfig { pragma_key, timeout, number_of_sources, start_time, time_window, aggregation_mode } = + let OracleConfig { pragma_key, + timeout, + number_of_sources, + start_time_offset, + time_window, + aggregation_mode } = self .oracle_configs .read((pool_id, asset)); let dispatcher = IPragmaABIDispatcher { contract_address: self.oracle_address.read() }; let response = dispatcher.get_data(DataType::SpotEntry(pragma_key), aggregation_mode); - // calculate the twap if start_time and time_window are set - let price = if start_time == 0 || time_window == 0 { + // calculate the twap if start_time_offset and time_window are set + let price = if start_time_offset == 0 || time_window == 0 { response.price.into() * SCALE / pow_10(response.decimals.into()) } else { let summary = ISummaryStatsABIDispatcher { contract_address: self.summary_address.read() }; let (value, decimals) = summary - .calculate_twap(DataType::SpotEntry(pragma_key), aggregation_mode, start_time, time_window,); - + .calculate_twap( + DataType::SpotEntry(pragma_key), + aggregation_mode, + time_window, + get_block_timestamp() - start_time_offset + ); value.into() * SCALE / pow_10(decimals.into()) }; diff --git a/src/extension/default_extension_po.cairo b/src/extension/default_extension_po.cairo index 426e92c..5174579 100644 --- a/src/extension/default_extension_po.cairo +++ b/src/extension/default_extension_po.cairo @@ -21,7 +21,7 @@ struct PragmaOracleParams { pragma_key: felt252, timeout: u64, // [seconds] number_of_sources: u32, - start_time: u64, // [seconds] + start_time_offset: u64, // [seconds] time_window: u64, // [seconds] aggregation_mode: AggregationMode } @@ -80,6 +80,7 @@ trait IDefaultExtension { fn pool_name(self: @TContractState, pool_id: felt252) -> felt252; fn pool_owner(self: @TContractState, pool_id: felt252) -> ContractAddress; fn pragma_oracle(self: @TContractState) -> ContractAddress; + fn pragma_summary(self: @TContractState) -> ContractAddress; fn oracle_config(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> OracleConfig; fn fee_config(self: @TContractState, pool_id: felt252) -> FeeConfig; fn debt_caps(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> u256; @@ -373,6 +374,13 @@ mod DefaultExtensionPO { self.pragma_oracle.oracle_address() } + /// Returns the address of the pragma summary contract + /// # Returns + /// * `summary_address` - address of the pragma summary contract + fn pragma_summary(self: @ContractState) -> ContractAddress { + self.pragma_oracle.summary_address() + } + /// Returns the oracle configuration for a given pool and asset /// # Arguments /// * `pool_id` - id of the pool @@ -582,7 +590,7 @@ mod DefaultExtensionPO { let PragmaOracleParams { pragma_key, timeout, number_of_sources, - start_time, + start_time_offset, time_window, aggregation_mode } = params; @@ -592,7 +600,7 @@ mod DefaultExtensionPO { pool_id, asset, OracleConfig { - pragma_key, timeout, number_of_sources, start_time, time_window, aggregation_mode + pragma_key, timeout, number_of_sources, start_time_offset, time_window, aggregation_mode } ); @@ -701,7 +709,7 @@ mod DefaultExtensionPO { pragma_key: pragma_oracle_params.pragma_key, timeout: pragma_oracle_params.timeout, number_of_sources: pragma_oracle_params.number_of_sources, - start_time: pragma_oracle_params.start_time, + start_time_offset: pragma_oracle_params.start_time_offset, time_window: pragma_oracle_params.time_window, aggregation_mode: pragma_oracle_params.aggregation_mode } diff --git a/src/test/mock_oracle.cairo b/src/test/mock_oracle.cairo index 0f027a3..e492c63 100644 --- a/src/test/mock_oracle.cairo +++ b/src/test/mock_oracle.cairo @@ -5,7 +5,7 @@ trait IMockPragmaSummary { fn calculate_twap( self: @TContractState, data_type: DataType, aggregation_mode: AggregationMode, time: u64, start_time: u64, ) -> (u128, u32); - fn set_twap(ref self: TContractState, twap: u128, decimals: u32); + fn set_twap(ref self: TContractState, key: felt252, twap: u128, decimals: u32); } #[starknet::contract] @@ -15,7 +15,7 @@ mod MockPragmaSummary { #[storage] struct Storage { - twap: u128, + twaps: LegacyMap::, decimals: u32, } @@ -24,11 +24,15 @@ mod MockPragmaSummary { fn calculate_twap( self: @ContractState, data_type: DataType, aggregation_mode: AggregationMode, time: u64, start_time: u64 ) -> (u128, u32) { - (self.twap.read(), self.decimals.read()) + match data_type { + DataType::SpotEntry(key) => { (self.twaps.read(key), self.decimals.read()) }, + DataType::FutureEntry => { (0, 0) }, + DataType::GenericEntry => { (0, 0) } + } } - fn set_twap(ref self: ContractState, twap: u128, decimals: u32) { - self.twap.write(twap); + fn set_twap(ref self: ContractState, key: felt252, twap: u128, decimals: u32) { + self.twaps.write(key, twap); self.decimals.write(decimals); } } diff --git a/src/test/setup.cairo b/src/test/setup.cairo index ce2d084..0904eef 100644 --- a/src/test/setup.cairo +++ b/src/test/setup.cairo @@ -284,7 +284,7 @@ fn create_pool( pragma_key: COLL_PRAGMA_KEY, timeout: 0, number_of_sources: 2, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -292,7 +292,7 @@ fn create_pool( pragma_key: DEBT_PRAGMA_KEY, timeout: 0, number_of_sources: 2, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -300,7 +300,7 @@ fn create_pool( pragma_key: THIRD_PRAGMA_KEY, timeout: 0, number_of_sources: 2, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; diff --git a/src/test/test_default_extension_po.cairo b/src/test/test_default_extension_po.cairo index 5cb9b1e..96ade94 100644 --- a/src/test/test_default_extension_po.cairo +++ b/src/test/test_default_extension_po.cairo @@ -203,7 +203,7 @@ mod TestDefaultExtensionPO { pragma_key: COLL_PRAGMA_KEY, timeout: 0, number_of_sources: 2, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -280,7 +280,7 @@ mod TestDefaultExtensionPO { pragma_key: COLL_PRAGMA_KEY, timeout: 1, number_of_sources: 2, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -325,7 +325,7 @@ mod TestDefaultExtensionPO { pragma_key: COLL_PRAGMA_KEY, timeout: 1, number_of_sources: 2, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -380,7 +380,7 @@ mod TestDefaultExtensionPO { pragma_key: Zeroable::zero(), timeout: 1, number_of_sources: 2, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -434,7 +434,7 @@ mod TestDefaultExtensionPO { pragma_key: COLL_PRAGMA_KEY, timeout: 1, number_of_sources: 2, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; diff --git a/src/test/test_forking.cairo b/src/test/test_forking.cairo index fc98dba..ecedf3b 100644 --- a/src/test/test_forking.cairo +++ b/src/test/test_forking.cairo @@ -212,7 +212,7 @@ mod TestForking { pragma_key: 'ETH/USD', timeout: 0, number_of_sources: 0, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -233,7 +233,7 @@ mod TestForking { pragma_key: 'WBTC/USD', timeout: 0, number_of_sources: 0, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -254,8 +254,8 @@ mod TestForking { pragma_key: 'USDC/USD', timeout: 0, number_of_sources: 2, - start_time: 0, - time_window: 0, + start_time_offset: 86400 * 7, + time_window: 86400 * 6, aggregation_mode: AggregationMode::Median(()) }; @@ -275,7 +275,7 @@ mod TestForking { pragma_key: 'USDT/USD', timeout: 0, number_of_sources: 0, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -296,7 +296,7 @@ mod TestForking { pragma_key: 'WSTETH/USD', timeout: 0, number_of_sources: 0, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -319,7 +319,7 @@ mod TestForking { pragma_key: 'STRK/USD', timeout: 0, number_of_sources: 0, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -599,8 +599,6 @@ mod TestForking { ); stop_prank(CheatTarget::One(extension.contract_address)); - start_warp(CheatTarget::All, get_block_timestamp() + DAY_IN_SECONDS * 30); - let mut i = 0; loop { match asset_params.get(i) { @@ -615,6 +613,14 @@ mod TestForking { i += 1; }; + store( + extension.contract_address, + map_entry_address(selector!("oracle_configs"), array![pool_id, usdc.contract_address.into()].span(),), + array!['USDC/USD', 0, 2, 0, 0, 1].span() + ); + + start_warp(CheatTarget::All, get_block_timestamp() + DAY_IN_SECONDS * 30); + SetupParams { singleton, extension, diff --git a/src/test/test_pragma_oracle.cairo b/src/test/test_pragma_oracle.cairo index 31c8093..8a24afc 100644 --- a/src/test/test_pragma_oracle.cairo +++ b/src/test/test_pragma_oracle.cairo @@ -1,7 +1,9 @@ #[cfg(test)] mod TestPragmaOracle { use core::serde::Serde; - use snforge_std::{start_prank, stop_prank, start_warp, stop_warp, CheatTarget, CheatSpan, prank}; + use snforge_std::{ + start_prank, stop_prank, start_warp, stop_warp, CheatTarget, CheatSpan, prank, store, map_entry_address + }; use starknet::{ContractAddress, get_block_timestamp}; use vesu::{ units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS}, @@ -9,7 +11,12 @@ mod TestPragmaOracle { singleton::{ISingletonDispatcherTrait, ISingletonDispatcher}, test::{ setup::{setup, setup_env, TestConfig, LendingTerms, COLL_PRAGMA_KEY, DEBT_PRAGMA_KEY, Env}, - mock_oracle::{{IMockPragmaOracleDispatcher, IMockPragmaOracleDispatcherTrait}} + mock_oracle::{ + { + IMockPragmaOracleDispatcher, IMockPragmaOracleDispatcherTrait, IMockPragmaSummaryDispatcher, + IMockPragmaSummaryDispatcherTrait + } + } }, extension::{ interface::{IExtensionDispatcher, IExtensionDispatcherTrait}, @@ -68,7 +75,7 @@ mod TestPragmaOracle { pragma_key: COLL_PRAGMA_KEY, timeout, number_of_sources, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -76,7 +83,7 @@ mod TestPragmaOracle { pragma_key: DEBT_PRAGMA_KEY, timeout, number_of_sources, - start_time: 0, + start_time_offset: 0, time_window: 0, aggregation_mode: AggregationMode::Median(()) }; @@ -324,4 +331,48 @@ mod TestPragmaOracle { assert!(!collateral_asset_price.is_valid, "Debt asset validity should be false"); } + + #[test] + fn test_price_twap() { + let (_, default_extension_po, config, _, _) = setup(); + let TestConfig { pool_id, collateral_asset, debt_asset, .. } = config; + + store( + default_extension_po.contract_address, + map_entry_address( + selector!("oracle_configs"), array![pool_id, collateral_asset.contract_address.into()].span(), + ), + array![COLL_PRAGMA_KEY, 0, 2, 1, 1, 1].span() + ); + + store( + default_extension_po.contract_address, + map_entry_address(selector!("oracle_configs"), array![pool_id, debt_asset.contract_address.into()].span(),), + array![DEBT_PRAGMA_KEY, 0, 2, 1, 1, 1].span() + ); + + let extension_dispatcher = IExtensionDispatcher { contract_address: default_extension_po.contract_address }; + let pragma_oracle = IMockPragmaOracleDispatcher { contract_address: default_extension_po.pragma_oracle() }; + let pragma_summary = IMockPragmaSummaryDispatcher { contract_address: default_extension_po.pragma_summary() }; + + let max: u128 = integer::BoundedInt::max(); + // set collateral asset price + pragma_oracle.set_price(COLL_PRAGMA_KEY, 0); + pragma_summary.set_twap(COLL_PRAGMA_KEY, max, 18); + // set debt asset price + pragma_oracle.set_price(DEBT_PRAGMA_KEY, 0); + pragma_summary.set_twap(DEBT_PRAGMA_KEY, max, 18); + + let collateral_asset_price = extension_dispatcher.price(pool_id, collateral_asset.contract_address); + let debt_asset_price = extension_dispatcher.price(pool_id, debt_asset.contract_address); + + assert!(collateral_asset_price.value == max.into(), "Collateral asset price not correctly set"); + assert!(debt_asset_price.value == max.into(), "Debt asset price not correctly set"); + assert!(collateral_asset_price.is_valid, "Debt asset validity should be true"); + assert!(debt_asset_price.is_valid, "Debt asset validity should be true"); + + let max_pair_LTV_ratio = 10 * SCALE; + let check_collat = is_collateralized(collateral_asset_price.value, debt_asset_price.value, max_pair_LTV_ratio); + assert!(check_collat, "Collateralization check failed"); + } } diff --git a/src/vendor/pragma.cairo b/src/vendor/pragma.cairo index 2dc233f..4431fba 100644 --- a/src/vendor/pragma.cairo +++ b/src/vendor/pragma.cairo @@ -33,6 +33,6 @@ trait IPragmaABI { #[starknet::interface] trait ISummaryStatsABI { fn calculate_twap( - self: @TContractState, data_type: DataType, aggregation_mode: AggregationMode, time: u64, start_time: u64, + self: @TContractState, data_type: DataType, aggregation_mode: AggregationMode, time: u64, start_time: u64 ) -> (u128, u32); } From 3912f54e72f1e4078fb940272b8ca1cfed5172b7 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Thu, 21 Nov 2024 18:11:44 +0000 Subject: [PATCH 16/32] Update debt_caps to be pair specific --- gas-report.txt | 16 ++--- lib/config.devnet.ts | 9 +++ lib/config.mainnet.ts | 9 +++ lib/config.sepolia.ts | 9 +++ lib/model.ts | 5 ++ lib/protocol.ts | 1 + package.json | 2 +- src/data_model.cairo | 7 +++ src/extension/components/position_hooks.cairo | 41 +++++++++--- src/extension/default_extension_cl.cairo | 59 ++++++++++++----- src/extension/default_extension_po.cairo | 63 +++++++++++++------ src/test/setup.cairo | 16 ++++- src/test/test_default_extension_cl.cairo | 50 ++++++++++----- src/test/test_default_extension_po.cairo | 44 +++++++++---- src/test/test_forking.cairo | 48 +++++++++++++- src/test/test_pragma_oracle.cairo | 9 ++- yarn.lock | 4 +- 17 files changed, 304 insertions(+), 88 deletions(-) diff --git a/gas-report.txt b/gas-report.txt index 71c001c..9263265 100644 --- a/gas-report.txt +++ b/gas-report.txt @@ -2,19 +2,19 @@ Summary: ┌─────────────┬─────────────────────────┬─────────┬────────────────┬────────────────┬─────────────────┬───────────┬──────────────┬──────────────────────────────┬───────────────┬──────────────────┬─────────┐ │ (index) │ Actual fee │ Fee usd │ Fee without DA │ Gas without DA │ Computation gas │ Event gas │ Calldata gas │ Max computation per Category │ Storage diffs │ DA fee │ DA mode │ ├─────────────┼─────────────────────────┼─────────┼────────────────┼────────────────┼─────────────────┼───────────┼──────────────┼──────────────────────────────┼───────────────┼──────────────────┼─────────┤ -│ Create pool │ '1.721.348.000.000.000' │ 6.8853 │ 57348000000000 │ 1593 │ 1529 │ 240 │ 64 │ 'range_check' │ 243 │ 1664000000000000 │ 'BLOB' │ -│ Lend │ '106.412.000.000.000' │ 0.4256 │ 16812000000000 │ 467 │ 465 │ 12 │ 2 │ 'range_check' │ 11 │ 89600000000000 │ 'BLOB' │ +│ Create pool │ '1.914.968.000.000.000' │ 7.6598 │ 58968000000000 │ 1638 │ 1558 │ 310 │ 80 │ 'range_check' │ 273 │ 1856000000000000 │ 'BLOB' │ +│ Lend │ '106.160.000.000.000' │ 0.4246 │ 16560000000000 │ 460 │ 458 │ 12 │ 2 │ 'range_check' │ 11 │ 89600000000000 │ 'BLOB' │ │ Transfer │ '102.792.000.000.000' │ 0.4111 │ 25992000000000 │ 722 │ 720 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ -│ Borrow │ '141.004.000.000.000' │ 0.564 │ 19404000000000 │ 539 │ 537 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ -│ Liquidate │ '143.668.000.000.000' │ 0.5746 │ 22068000000000 │ 613 │ 611 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ +│ Borrow │ '141.472.000.000.000' │ 0.5658 │ 19872000000000 │ 552 │ 550 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ +│ Liquidate │ '143.416.000.000.000' │ 0.5736 │ 21816000000000 │ 606 │ 604 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ └─────────────┴─────────────────────────┴─────────┴────────────────┴────────────────┴─────────────────┴───────────┴──────────────┴──────────────────────────────┴───────────────┴──────────────────┴─────────┘ Resources: ┌─────────────┬─────────┬───────┬───────┬────────┬──────────┬──────────┬─────────────┬────────┐ │ (index) │ bitwise │ ec_op │ ecdsa │ keccak │ pedersen │ poseidon │ range_check │ steps │ ├─────────────┼─────────┼───────┼───────┼────────┼──────────┼──────────┼─────────────┼────────┤ -│ Create pool │ 138 │ 3 │ 0 │ 0 │ 1561 │ 1 │ 38224 │ 551983 │ -│ Lend │ 26 │ 3 │ 0 │ 0 │ 130 │ 0 │ 11619 │ 97469 │ +│ Create pool │ 138 │ 3 │ 0 │ 0 │ 1772 │ 1 │ 38948 │ 580724 │ +│ Lend │ 26 │ 3 │ 0 │ 0 │ 130 │ 0 │ 11439 │ 97265 │ │ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17988 │ 144867 │ -│ Borrow │ 33 │ 3 │ 0 │ 0 │ 142 │ 0 │ 13415 │ 109845 │ -│ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15268 │ 119172 │ +│ Borrow │ 33 │ 3 │ 0 │ 0 │ 143 │ 0 │ 13748 │ 110679 │ +│ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15088 │ 118968 │ └─────────────┴─────────┴───────┴───────┴────────┴──────────┴──────────┴─────────────┴────────┘ diff --git a/lib/config.devnet.ts b/lib/config.devnet.ts index 2db263b..1ab0cfb 100644 --- a/lib/config.devnet.ts +++ b/lib/config.devnet.ts @@ -106,6 +106,15 @@ export const config: Config = { ); return { collateral_asset_index, debt_asset_index, liquidation_factor: toScale(pair.liquidation_discount) }; }), + debt_caps_params: CONFIG.pair_parameters.map((pair: any) => { + const collateral_asset_index = CONFIG.asset_parameters.findIndex( + (asset: any) => asset.asset_name === pair.collateral_asset_name, + ); + const debt_asset_index = CONFIG.asset_parameters.findIndex( + (asset: any) => asset.asset_name === pair.debt_asset_name, + ); + return { collateral_asset_index, debt_asset_index, debt_cap: toScale(pair.debt_cap) }; + }), shutdown_params: { recovery_period: BigInt(CONFIG.pool_parameters.recovery_period), subscription_period: BigInt(CONFIG.pool_parameters.subscription_period), diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index f0697f7..5b1e390 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -93,6 +93,15 @@ export const config: Config = { ); return { collateral_asset_index, debt_asset_index, liquidation_factor: toScale(pair.liquidation_discount) }; }), + debt_caps_params: CONFIG.pair_parameters.map((pair: any) => { + const collateral_asset_index = CONFIG.asset_parameters.findIndex( + (asset: any) => asset.asset_name === pair.collateral_asset_name, + ); + const debt_asset_index = CONFIG.asset_parameters.findIndex( + (asset: any) => asset.asset_name === pair.debt_asset_name, + ); + return { collateral_asset_index, debt_asset_index, debt_cap: toScale(pair.debt_cap) }; + }), shutdown_params: { recovery_period: BigInt(CONFIG.pool_parameters.recovery_period), subscription_period: BigInt(CONFIG.pool_parameters.subscription_period), diff --git a/lib/config.sepolia.ts b/lib/config.sepolia.ts index 2befcea..fa87f84 100644 --- a/lib/config.sepolia.ts +++ b/lib/config.sepolia.ts @@ -112,6 +112,15 @@ export const config: Config = { ); return { collateral_asset_index, debt_asset_index, liquidation_factor: toScale(pair.liquidation_discount) }; }), + debt_caps_params: CONFIG.pair_parameters.map((pair: any) => { + const collateral_asset_index = CONFIG.asset_parameters.findIndex( + (asset: any) => asset.asset_name === pair.collateral_asset_name, + ); + const debt_asset_index = CONFIG.asset_parameters.findIndex( + (asset: any) => asset.asset_name === pair.debt_asset_name, + ); + return { collateral_asset_index, debt_asset_index, debt_cap: toScale(pair.debt_cap) }; + }), shutdown_params: { recovery_period: BigInt(CONFIG.pool_parameters.recovery_period), subscription_period: BigInt(CONFIG.pool_parameters.subscription_period), diff --git a/lib/model.ts b/lib/model.ts index fa031c2..6b53a5a 100644 --- a/lib/model.ts +++ b/lib/model.ts @@ -65,6 +65,10 @@ export interface LTVParams extends AssetIndexes { max_ltv: bigint; } +export interface DebtCapParams extends AssetIndexes { + debt_cap: bigint; +} + export interface AssetConfig { total_collateral_shares: bigint; total_nominal_debt: bigint; @@ -97,6 +101,7 @@ export interface CreatePoolParams { interest_rate_configs: InterestRateConfig[]; pragma_oracle_params: PragmaOracleParams[]; liquidation_params: LiquidationParams[]; + debt_caps_params: DebtCapParams[]; shutdown_params: ShutdownParams; fee_params: FeeParams; owner: string; diff --git a/lib/protocol.ts b/lib/protocol.ts index 73879b5..17f4a42 100644 --- a/lib/protocol.ts +++ b/lib/protocol.ts @@ -44,6 +44,7 @@ export class Protocol implements ProtocolContracts { params.interest_rate_configs, params.pragma_oracle_params, params.liquidation_params, + params.debt_caps_params, params.shutdown_params, params.fee_params, params.owner, diff --git a/package.json b/package.json index 6b72305..0128e5f 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@types/lodash-es": "^4.17.12", "@types/node": "^20.10.5", "bignumber.js": "9.1.2", - "vesu_changelog": "https://github.com/vesuxyz/changelog.git#921891b7e9afa7b66fefc386ba29bb2f4de08bc5", + "vesu_changelog": "https://github.com/vesuxyz/changelog.git#d4de336513547448de52c949ea8fe09cd9e5848a", "dotenv": "^16.3.1", "lodash-es": "^4.17.21", "prettier": "^3.1.1", diff --git a/src/data_model.cairo b/src/data_model.cairo index 164668a..884114d 100644 --- a/src/data_model.cairo +++ b/src/data_model.cairo @@ -97,6 +97,13 @@ struct LTVParams { max_ltv: u64, // [SCALE] } +#[derive(PartialEq, Copy, Drop, Serde)] +struct DebtCapParams { + collateral_asset_index: usize, + debt_asset_index: usize, + debt_cap: u256, // [SCALE] +} + #[derive(PartialEq, Copy, Drop, Serde)] struct ModifyPositionParams { pool_id: felt252, diff --git a/src/extension/components/position_hooks.cairo b/src/extension/components/position_hooks.cairo index c30b2a1..5d6ca22 100644 --- a/src/extension/components/position_hooks.cairo +++ b/src/extension/components/position_hooks.cairo @@ -109,37 +109,56 @@ mod position_hooks_component { // (pool_id, collateral asset, debt asset) -> pair configuration pairs: LegacyMap::<(felt252, ContractAddress, ContractAddress), Pair>, // tracks the debt caps for each asset - debt_caps: LegacyMap::<(felt252, ContractAddress), u256> + debt_caps: LegacyMap::<(felt252, ContractAddress, ContractAddress), u256> } #[derive(Drop, starknet::Event)] struct SetLiquidationConfig { + #[key] pool_id: felt252, + #[key] collateral_asset: ContractAddress, + #[key] debt_asset: ContractAddress, liquidation_config: LiquidationConfig, } #[derive(Drop, starknet::Event)] struct SetShutdownConfig { + #[key] pool_id: felt252, shutdown_config: ShutdownConfig } #[derive(Drop, starknet::Event)] struct SetShutdownLTVConfig { + #[key] pool_id: felt252, + #[key] collateral_asset: ContractAddress, + #[key] debt_asset: ContractAddress, shutdown_ltv_config: LTVConfig, } + #[derive(Drop, starknet::Event)] + struct SetDebtCap { + #[key] + pool_id: felt252, + #[key] + collateral_asset: ContractAddress, + #[key] + debt_asset: ContractAddress, + debt_cap: u256, + } + #[event] #[derive(Drop, starknet::Event)] enum Event { SetLiquidationConfig: SetLiquidationConfig, SetShutdownConfig: SetShutdownConfig, - SetShutdownLTVConfig: SetShutdownLTVConfig + SetShutdownLTVConfig: SetShutdownLTVConfig, + SetDebtCap: SetDebtCap } // Infers the shutdown_config from the timestamp at which the violation occurred and the current time @@ -187,12 +206,18 @@ mod position_hooks_component { /// Sets the debt cap for an asset in a pool. /// # Arguments /// * `pool_id` - id of the pool - /// * `asset` - address of the debt asset + /// * `collateral_asset` - address of the collateral asset + /// * `debt_asset` - address of the debt asset /// * `debt_cap` - debt cap fn set_debt_cap( - ref self: ComponentState, pool_id: felt252, asset: ContractAddress, debt_cap: u256 + ref self: ComponentState, + pool_id: felt252, + collateral_asset: ContractAddress, + debt_asset: ContractAddress, + debt_cap: u256 ) { - self.debt_caps.write((pool_id, asset), debt_cap); + self.debt_caps.write((pool_id, collateral_asset, debt_asset), debt_cap); + self.emit(SetDebtCap { pool_id, collateral_asset, debt_asset, debt_cap }); } /// Sets the liquidation configuration for an asset pairing in a pool. @@ -406,7 +431,7 @@ mod position_hooks_component { } if nominal_debt_delta > Zeroable::zero() { total_nominal_debt = total_nominal_debt + nominal_debt_delta.abs; - let debt_cap = self.debt_caps.read((context.pool_id, context.debt_asset)); + let debt_cap = self.debt_caps.read((context.pool_id, context.collateral_asset, context.debt_asset)); if debt_cap != 0 { let total_debt = calculate_debt( total_nominal_debt, @@ -414,9 +439,7 @@ mod position_hooks_component { context.debt_asset_config.scale, true ); - assert!( - total_debt <= self.debt_caps.read((context.pool_id, context.debt_asset)), "debt-cap-exceeded" - ); + assert!(total_debt <= debt_cap, "debt-cap-exceeded"); } } else if nominal_debt_delta < Zeroable::zero() { total_nominal_debt = total_nominal_debt - nominal_debt_delta.abs; diff --git a/src/extension/default_extension_cl.cairo b/src/extension/default_extension_cl.cairo index d568219..d8ab7cf 100644 --- a/src/extension/default_extension_cl.cairo +++ b/src/extension/default_extension_cl.cairo @@ -1,7 +1,7 @@ use alexandria_math::i257::i257; use starknet::ContractAddress; use vesu::{ - data_model::{AssetParams, LTVParams, LTVConfig}, + data_model::{AssetParams, LTVParams, LTVConfig, DebtCapParams}, extension::{ components::{ interest_rate_model::InterestRateConfig, @@ -25,7 +25,9 @@ trait IDefaultExtensionCL { fn chainlink_oracle_config( self: @TContractState, pool_id: felt252, asset: ContractAddress ) -> ChainlinkOracleConfig; - fn debt_caps(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> u256; + fn debt_caps( + self: @TContractState, pool_id: felt252, collateral_asset: ContractAddress, debt_asset: ContractAddress + ) -> u256; fn fee_config(self: @TContractState, pool_id: felt252) -> FeeConfig; fn interest_rate_config(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> InterestRateConfig; fn liquidation_config( @@ -62,6 +64,7 @@ trait IDefaultExtensionCL { interest_rate_configs: Span, chainlink_oracle_params: Span, liquidation_params: Span, + debt_caps: Span, shutdown_params: ShutdownParams, fee_params: FeeParams, owner: ContractAddress @@ -72,13 +75,18 @@ trait IDefaultExtensionCL { asset_params: AssetParams, v_token_params: VTokenParams, interest_rate_config: InterestRateConfig, - chainlink_oracle_params: ChainlinkOracleParams, - debt_cap: u256 + chainlink_oracle_params: ChainlinkOracleParams ); fn set_asset_parameter( ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u256 ); - fn set_debt_cap(ref self: TContractState, pool_id: felt252, asset: ContractAddress, debt_cap: u256); + fn set_debt_cap( + ref self: TContractState, + pool_id: felt252, + collateral_asset: ContractAddress, + debt_asset: ContractAddress, + debt_cap: u256 + ); fn set_interest_rate_parameter( ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u256 ); @@ -126,7 +134,7 @@ mod DefaultExtensionCL { map_list::{map_list_component, map_list_component::MapListTrait}, data_model::{ Amount, UnsignedAmount, AssetParams, AssetPrice, LTVParams, Context, LTVConfig, ModifyPositionParams, - AmountDenomination, AmountType + AmountDenomination, AmountType, DebtCapParams }, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, units::INFLATION_FEE, @@ -328,11 +336,14 @@ mod DefaultExtensionCL { /// Returns the debt cap for a given asset in a pool /// # Arguments /// * `pool_id` - id of the pool - /// * `asset` - address of the asset + /// * `collateral_asset` - address of the collateral asset + /// * `debt_asset` - address of the debt asset /// # Returns /// * `debt_cap` - debt cap - fn debt_caps(self: @ContractState, pool_id: felt252, asset: ContractAddress) -> u256 { - self.position_hooks.debt_caps.read((pool_id, asset)) + fn debt_caps( + self: @ContractState, pool_id: felt252, collateral_asset: ContractAddress, debt_asset: ContractAddress + ) -> u256 { + self.position_hooks.debt_caps.read((pool_id, collateral_asset, debt_asset)) } /// Returns the interest rate configuration for a given pool and asset @@ -471,6 +482,7 @@ mod DefaultExtensionCL { /// * `interest_rate_params` - interest rate model parameters /// * `chainlink_oracle_params` - chainlink oracle parameters /// * `liquidation_params` - liquidation parameters + /// * `debt_caps` - debt caps /// * `shutdown_params` - shutdown parameters /// * `fee_params` - fee model parameters /// # Returns @@ -484,6 +496,7 @@ mod DefaultExtensionCL { mut interest_rate_configs: Span, mut chainlink_oracle_params: Span, mut liquidation_params: Span, + mut debt_caps: Span, shutdown_params: ShutdownParams, fee_params: FeeParams, owner: ContractAddress @@ -568,6 +581,16 @@ mod DefaultExtensionCL { ); }; + // set the debt caps for each pair + let mut debt_caps = debt_caps; + while !debt_caps + .is_empty() { + let params = *debt_caps.pop_front().unwrap(); + let collateral_asset = *asset_params.at(params.collateral_asset_index).asset; + let debt_asset = *asset_params.at(params.debt_asset_index).asset; + self.position_hooks.set_debt_cap(pool_id, collateral_asset, debt_asset, params.debt_cap); + }; + // set the max shutdown LTVs for each asset let mut shutdown_ltv_params = shutdown_params.ltv_params; while !shutdown_ltv_params @@ -599,7 +622,6 @@ mod DefaultExtensionCL { /// * `v_token_params` - vToken parameters /// * `interest_rate_model` - interest rate model /// * `chainlink_oracle_params` - chainlink oracle parameters - /// * `debt_cap` - debt cap fn add_asset( ref self: ContractState, pool_id: felt252, @@ -607,7 +629,6 @@ mod DefaultExtensionCL { v_token_params: VTokenParams, interest_rate_config: InterestRateConfig, chainlink_oracle_params: ChainlinkOracleParams, - debt_cap: u256 ) { assert!(get_caller_address() == self.owner.read(pool_id), "caller-not-owner"); let asset = asset_params.asset; @@ -623,9 +644,6 @@ mod DefaultExtensionCL { } ); - // set the debt cap - self.position_hooks.set_debt_cap(pool_id, asset, debt_cap); - // set the interest rate model configuration self.interest_rate_model.set_interest_rate_config(pool_id, asset, interest_rate_config); @@ -661,11 +679,18 @@ mod DefaultExtensionCL { /// Sets the debt cap for a given asset in a pool /// # Arguments /// * `pool_id` - id of the pool - /// * `asset` - address of the asset + /// * `collateral_asset` - address of the collateral asset + /// * `debt_asset` - address of the debt asset /// * `debt_cap` - debt cap - fn set_debt_cap(ref self: ContractState, pool_id: felt252, asset: ContractAddress, debt_cap: u256) { + fn set_debt_cap( + ref self: ContractState, + pool_id: felt252, + collateral_asset: ContractAddress, + debt_asset: ContractAddress, + debt_cap: u256 + ) { assert!(get_caller_address() == self.owner.read(pool_id), "caller-not-owner"); - self.position_hooks.set_debt_cap(pool_id, asset, debt_cap); + self.position_hooks.set_debt_cap(pool_id, collateral_asset, debt_asset, debt_cap); } /// Sets a parameter for a given interest rate configuration for an asset in a pool diff --git a/src/extension/default_extension_po.cairo b/src/extension/default_extension_po.cairo index 5174579..96f116e 100644 --- a/src/extension/default_extension_po.cairo +++ b/src/extension/default_extension_po.cairo @@ -1,7 +1,7 @@ use alexandria_math::i257::i257; use starknet::ContractAddress; use vesu::{ - data_model::{AssetParams, LTVParams, LTVConfig}, + data_model::{AssetParams, LTVParams, LTVConfig, DebtCapParams}, extension::components::{ interest_rate_model::InterestRateConfig, position_hooks::{ShutdownMode, ShutdownStatus, ShutdownConfig, LiquidationConfig, Pair}, fee_model::FeeConfig, @@ -83,7 +83,9 @@ trait IDefaultExtension { fn pragma_summary(self: @TContractState) -> ContractAddress; fn oracle_config(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> OracleConfig; fn fee_config(self: @TContractState, pool_id: felt252) -> FeeConfig; - fn debt_caps(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> u256; + fn debt_caps( + self: @TContractState, pool_id: felt252, collateral_asset: ContractAddress, debt_asset: ContractAddress + ) -> u256; fn interest_rate_config(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> InterestRateConfig; fn liquidation_config( self: @TContractState, pool_id: felt252, collateral_asset: ContractAddress, debt_asset: ContractAddress @@ -119,6 +121,7 @@ trait IDefaultExtension { interest_rate_configs: Span, pragma_oracle_params: Span, liquidation_params: Span, + debt_caps: Span, shutdown_params: ShutdownParams, fee_params: FeeParams, owner: ContractAddress @@ -129,13 +132,18 @@ trait IDefaultExtension { asset_params: AssetParams, v_token_params: VTokenParams, interest_rate_config: InterestRateConfig, - pragma_oracle_params: PragmaOracleParams, - debt_cap: u256 + pragma_oracle_params: PragmaOracleParams ); fn set_asset_parameter( ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u256 ); - fn set_debt_cap(ref self: TContractState, pool_id: felt252, asset: ContractAddress, debt_cap: u256); + fn set_debt_cap( + ref self: TContractState, + pool_id: felt252, + collateral_asset: ContractAddress, + debt_asset: ContractAddress, + debt_cap: u256 + ); fn set_interest_rate_parameter( ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u256 ); @@ -183,7 +191,7 @@ mod DefaultExtensionPO { map_list::{map_list_component, map_list_component::MapListTrait}, data_model::{ Amount, UnsignedAmount, AssetParams, AssetPrice, LTVParams, Context, LTVConfig, ModifyPositionParams, - AmountDenomination, AmountType + AmountDenomination, AmountType, DebtCapParams }, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, units::INFLATION_FEE, @@ -403,11 +411,14 @@ mod DefaultExtensionPO { /// Returns the debt cap for a given asset in a pool /// # Arguments /// * `pool_id` - id of the pool - /// * `asset` - address of the asset + /// * `collateral_asset` - address of the collateral asset + /// * `debt_asset` - address of the debt asset /// # Returns /// * `debt_cap` - debt cap - fn debt_caps(self: @ContractState, pool_id: felt252, asset: ContractAddress) -> u256 { - self.position_hooks.debt_caps.read((pool_id, asset)) + fn debt_caps( + self: @ContractState, pool_id: felt252, collateral_asset: ContractAddress, debt_asset: ContractAddress + ) -> u256 { + self.position_hooks.debt_caps.read((pool_id, collateral_asset, debt_asset)) } /// Returns the interest rate configuration for a given pool and asset @@ -546,6 +557,7 @@ mod DefaultExtensionPO { /// * `interest_rate_params` - interest rate model parameters /// * `pragma_oracle_params` - pragma oracle parameters /// * `liquidation_params` - liquidation parameters + /// * `debt_caps` - debt caps /// * `shutdown_params` - shutdown parameters /// * `fee_params` - fee model parameters /// # Returns @@ -559,6 +571,7 @@ mod DefaultExtensionPO { mut interest_rate_configs: Span, mut pragma_oracle_params: Span, mut liquidation_params: Span, + mut debt_caps: Span, shutdown_params: ShutdownParams, fee_params: FeeParams, owner: ContractAddress @@ -655,7 +668,17 @@ mod DefaultExtensionPO { ); }; - // set the max shutdown LTVs for each asset + // set the debt caps for each pair + let mut debt_caps = debt_caps; + while !debt_caps + .is_empty() { + let params = *debt_caps.pop_front().unwrap(); + let collateral_asset = *asset_params.at(params.collateral_asset_index).asset; + let debt_asset = *asset_params.at(params.debt_asset_index).asset; + self.position_hooks.set_debt_cap(pool_id, collateral_asset, debt_asset, params.debt_cap); + }; + + // set the max shutdown LTVs for each pair let mut shutdown_ltv_params = shutdown_params.ltv_params; while !shutdown_ltv_params .is_empty() { @@ -686,15 +709,13 @@ mod DefaultExtensionPO { /// * `v_token_params` - vToken parameters /// * `interest_rate_model` - interest rate model /// * `pragma_oracle_params` - pragma oracle parameters - /// * `debt_cap` - debt cap fn add_asset( ref self: ContractState, pool_id: felt252, asset_params: AssetParams, v_token_params: VTokenParams, interest_rate_config: InterestRateConfig, - pragma_oracle_params: PragmaOracleParams, - debt_cap: u256 + pragma_oracle_params: PragmaOracleParams ) { assert!(get_caller_address() == self.owner.read(pool_id), "caller-not-owner"); let asset = asset_params.asset; @@ -715,9 +736,6 @@ mod DefaultExtensionPO { } ); - // set the debt cap - self.position_hooks.set_debt_cap(pool_id, asset, debt_cap); - // set the interest rate model configuration self.interest_rate_model.set_interest_rate_config(pool_id, asset, interest_rate_config); @@ -753,11 +771,18 @@ mod DefaultExtensionPO { /// Sets the debt cap for a given asset in a pool /// # Arguments /// * `pool_id` - id of the pool - /// * `asset` - address of the asset + /// * `collateral_asset` - address of the collateral asset + /// * `debt_asset` - address of the debt asset /// * `debt_cap` - debt cap - fn set_debt_cap(ref self: ContractState, pool_id: felt252, asset: ContractAddress, debt_cap: u256) { + fn set_debt_cap( + ref self: ContractState, + pool_id: felt252, + collateral_asset: ContractAddress, + debt_asset: ContractAddress, + debt_cap: u256 + ) { assert!(get_caller_address() == self.owner.read(pool_id), "caller-not-owner"); - self.position_hooks.set_debt_cap(pool_id, asset, debt_cap); + self.position_hooks.set_debt_cap(pool_id, collateral_asset, debt_asset, debt_cap); } /// Sets a parameter for a given interest rate configuration for an asset in a pool diff --git a/src/test/setup.cairo b/src/test/setup.cairo index 0904eef..ede5558 100644 --- a/src/test/setup.cairo +++ b/src/test/setup.cairo @@ -6,7 +6,7 @@ use starknet::{ContractAddress, contract_address_const, get_block_timestamp}; use vesu::{ units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS, INFLATION_FEE}, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, - data_model::{Amount, AmountDenomination, AmountType, ModifyPositionParams, AssetParams, LTVParams}, + data_model::{Amount, AmountDenomination, AmountType, ModifyPositionParams, AssetParams, LTVParams, DebtCapParams}, extension::interface::{IExtensionDispatcher, IExtensionDispatcherTrait}, extension::default_extension_po::{ IDefaultExtensionDispatcher, IDefaultExtensionDispatcherTrait, InterestRateConfig, PragmaOracleParams, @@ -336,6 +336,11 @@ fn create_pool( collateral_asset_index: 2, debt_asset_index: 1, liquidation_factor: 0 }; + let debt_cap_params_0 = DebtCapParams { collateral_asset_index: 0, debt_asset_index: 1, debt_cap: 0 }; + let debt_cap_params_1 = DebtCapParams { collateral_asset_index: 1, debt_asset_index: 0, debt_cap: 0 }; + let debt_cap_params_2 = DebtCapParams { collateral_asset_index: 0, debt_asset_index: 2, debt_cap: 0 }; + let debt_cap_params_3 = DebtCapParams { collateral_asset_index: 2, debt_asset_index: 1, debt_cap: 0 }; + let shutdown_ltv_params_0 = LTVParams { collateral_asset_index: 1, debt_asset_index: 0, max_ltv: (75 * PERCENT).try_into().unwrap() }; @@ -367,6 +372,7 @@ fn create_pool( liquidation_params_0, liquidation_params_1, liquidation_params_2, liquidation_params_3 ] .span(); + let debt_caps = array![debt_cap_params_0, debt_cap_params_1, debt_cap_params_2, debt_cap_params_3].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; @@ -381,6 +387,7 @@ fn create_pool( interest_rate_configs, oracle_params, liquidation_params, + debt_caps, shutdown_params, FeeParams { fee_recipient: creator }, creator @@ -487,6 +494,11 @@ fn create_pool_v2( collateral_asset_index: 2, debt_asset_index: 1, liquidation_factor: 0 }; + let debt_cap_params_0 = DebtCapParams { collateral_asset_index: 0, debt_asset_index: 1, debt_cap: 0 }; + let debt_cap_params_1 = DebtCapParams { collateral_asset_index: 1, debt_asset_index: 0, debt_cap: 0 }; + let debt_cap_params_2 = DebtCapParams { collateral_asset_index: 0, debt_asset_index: 2, debt_cap: 0 }; + let debt_cap_params_3 = DebtCapParams { collateral_asset_index: 2, debt_asset_index: 1, debt_cap: 0 }; + let shutdown_ltv_params_0 = LTVParams { collateral_asset_index: 1, debt_asset_index: 0, max_ltv: (75 * PERCENT).try_into().unwrap() }; @@ -520,6 +532,7 @@ fn create_pool_v2( liquidation_params_0, liquidation_params_1, liquidation_params_2, liquidation_params_3 ] .span(); + let debt_caps = array![debt_cap_params_0, debt_cap_params_1, debt_cap_params_2, debt_cap_params_3].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; @@ -534,6 +547,7 @@ fn create_pool_v2( interest_rate_configs, chainlink_oracle_params, liquidation_params, + debt_caps, shutdown_params, FeeParams { fee_recipient: creator }, creator diff --git a/src/test/test_default_extension_cl.cairo b/src/test/test_default_extension_cl.cairo index 30195f6..955291a 100644 --- a/src/test/test_default_extension_cl.cairo +++ b/src/test/test_default_extension_cl.cairo @@ -9,7 +9,7 @@ mod TestDefaultExtensionCL { singleton::{ISingletonDispatcherTrait}, data_model::{AssetParams, LTVParams, LTVConfig, ModifyPositionParams}, extension::default_extension_po::{ InterestRateConfig, LiquidationParams, ShutdownParams, FeeParams, VTokenParams, LiquidationConfig, - ShutdownConfig, FeeConfig + ShutdownConfig, FeeConfig, DebtCapParams }, extension::default_extension_cl::{ChainlinkOracleParams, IDefaultExtensionCLDispatcherTrait}, test::setup::{COLL_PRAGMA_KEY, deploy_asset_with_decimals, test_interest_rate_config}, @@ -68,6 +68,7 @@ mod TestDefaultExtensionCL { let interest_rate_configs = array![].span(); let oracle_params = array![].span(); let liquidation_params = array![].span(); + let debt_caps_params = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params @@ -83,6 +84,7 @@ mod TestDefaultExtensionCL { interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -115,6 +117,7 @@ mod TestDefaultExtensionCL { let interest_rate_configs = array![].span(); let oracle_params = array![].span(); let liquidation_params = array![].span(); + let debt_caps_params = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params @@ -134,6 +137,7 @@ mod TestDefaultExtensionCL { interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -166,6 +170,7 @@ mod TestDefaultExtensionCL { let interest_rate_configs = array![test_interest_rate_config()].span(); let oracle_params = array![].span(); let liquidation_params = array![].span(); + let debt_caps_params = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params @@ -185,6 +190,7 @@ mod TestDefaultExtensionCL { interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -217,6 +223,7 @@ mod TestDefaultExtensionCL { let interest_rate_configs = array![test_interest_rate_config()].span(); let oracle_params = array![collateral_asset_oracle_params].span(); let liquidation_params = array![].span(); + let debt_caps_params = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params @@ -236,6 +243,7 @@ mod TestDefaultExtensionCL { interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -282,9 +290,7 @@ mod TestDefaultExtensionCL { let chainlink_oracle_params = ChainlinkOracleParams { aggregator: Zeroable::zero(), timeout: 1 }; extension_v2 - .add_asset( - config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params, 0 - ); + .add_asset(config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params); } #[test] @@ -327,9 +333,7 @@ mod TestDefaultExtensionCL { prank(CheatTarget::One(extension_v2.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v2 - .add_asset( - config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params, 0 - ); + .add_asset(config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params); stop_prank(CheatTarget::One(extension_v2.contract_address)); } @@ -377,9 +381,7 @@ mod TestDefaultExtensionCL { prank(CheatTarget::One(extension_v2.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v2 - .add_asset( - config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params, 0 - ); + .add_asset(config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params); stop_prank(CheatTarget::One(extension_v2.contract_address)); } @@ -430,9 +432,7 @@ mod TestDefaultExtensionCL { prank(CheatTarget::One(extension_v2.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v2 - .add_asset( - config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params, 0 - ); + .add_asset(config.pool_id_v2, asset_params, v_token_params, interest_rate_config, chainlink_oracle_params); stop_prank(CheatTarget::One(extension_v2.contract_address)); let (asset_config, _) = singleton.asset_config(config.pool_id_v2, config.collateral_asset.contract_address); @@ -1035,10 +1035,18 @@ mod TestDefaultExtensionCL { create_pool_v2(extension_v2, config, users.creator, Option::None); start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); - extension_v2.set_debt_cap(config.pool_id_v2, config.collateral_asset.contract_address, 1000); + extension_v2 + .set_debt_cap( + config.pool_id_v2, config.collateral_asset.contract_address, config.debt_asset.contract_address, 1000 + ); stop_prank(CheatTarget::One(extension_v2.contract_address)); - assert!(extension_v2.debt_caps(config.pool_id_v2, config.collateral_asset.contract_address) == 1000); + assert!( + extension_v2 + .debt_caps( + config.pool_id_v2, config.collateral_asset.contract_address, config.debt_asset.contract_address + ) == 1000 + ); } #[test] @@ -1050,8 +1058,16 @@ mod TestDefaultExtensionCL { create_pool_v2(extension_v2, config, users.creator, Option::None); - extension_v2.set_debt_cap(config.pool_id_v2, config.collateral_asset.contract_address, 1000); + extension_v2 + .set_debt_cap( + config.pool_id_v2, config.collateral_asset.contract_address, config.debt_asset.contract_address, 1000 + ); - assert!(extension_v2.debt_caps(config.pool_id_v2, config.collateral_asset.contract_address) == 1000); + assert!( + extension_v2 + .debt_caps( + config.pool_id_v2, config.collateral_asset.contract_address, config.debt_asset.contract_address + ) == 1000 + ); } } diff --git a/src/test/test_default_extension_po.cairo b/src/test/test_default_extension_po.cairo index 96ade94..84bfa3f 100644 --- a/src/test/test_default_extension_po.cairo +++ b/src/test/test_default_extension_po.cairo @@ -58,6 +58,7 @@ mod TestDefaultExtensionPO { let interest_rate_configs = array![].span(); let oracle_params = array![].span(); let liquidation_params = array![].span(); + let debt_caps = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params @@ -73,6 +74,7 @@ mod TestDefaultExtensionPO { interest_rate_configs, oracle_params, liquidation_params, + debt_caps, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -105,6 +107,7 @@ mod TestDefaultExtensionPO { let interest_rate_configs = array![].span(); let oracle_params = array![].span(); let liquidation_params = array![].span(); + let debt_caps = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params @@ -124,6 +127,7 @@ mod TestDefaultExtensionPO { interest_rate_configs, oracle_params, liquidation_params, + debt_caps, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -156,6 +160,7 @@ mod TestDefaultExtensionPO { let interest_rate_configs = array![test_interest_rate_config()].span(); let oracle_params = array![].span(); let liquidation_params = array![].span(); + let debt_caps = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params @@ -175,6 +180,7 @@ mod TestDefaultExtensionPO { interest_rate_configs, oracle_params, liquidation_params, + debt_caps, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -214,6 +220,7 @@ mod TestDefaultExtensionPO { let interest_rate_configs = array![test_interest_rate_config()].span(); let oracle_params = array![collateral_asset_oracle_params].span(); let liquidation_params = array![].span(); + let debt_caps = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params @@ -233,6 +240,7 @@ mod TestDefaultExtensionPO { interest_rate_configs, oracle_params, liquidation_params, + debt_caps, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -285,8 +293,7 @@ mod TestDefaultExtensionPO { aggregation_mode: AggregationMode::Median(()) }; - extension - .add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params, 0); + extension.add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params); } #[test] @@ -335,8 +342,7 @@ mod TestDefaultExtensionPO { stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); prank(CheatTarget::One(extension.contract_address), users.creator, CheatSpan::TargetCalls(1)); - extension - .add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params, 0); + extension.add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params); stop_prank(CheatTarget::One(extension.contract_address)); } @@ -390,8 +396,7 @@ mod TestDefaultExtensionPO { stop_prank(CheatTarget::One(asset.contract_address)); prank(CheatTarget::One(extension.contract_address), users.creator, CheatSpan::TargetCalls(1)); - extension - .add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params, 0); + extension.add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params); stop_prank(CheatTarget::One(extension.contract_address)); } @@ -444,8 +449,7 @@ mod TestDefaultExtensionPO { stop_prank(CheatTarget::One(asset.contract_address)); prank(CheatTarget::One(extension.contract_address), users.creator, CheatSpan::TargetCalls(1)); - extension - .add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params, 0); + extension.add_asset(config.pool_id, asset_params, v_token_params, interest_rate_config, pragma_oracle_params); stop_prank(CheatTarget::One(extension.contract_address)); let (asset_config, _) = singleton.asset_config(config.pool_id, config.collateral_asset.contract_address); @@ -985,10 +989,18 @@ mod TestDefaultExtensionPO { create_pool(extension, config, users.creator, Option::None); start_prank(CheatTarget::One(extension.contract_address), users.creator); - extension.set_debt_cap(config.pool_id, config.collateral_asset.contract_address, 1000); + extension + .set_debt_cap( + config.pool_id, config.collateral_asset.contract_address, config.debt_asset.contract_address, 1000 + ); stop_prank(CheatTarget::One(extension.contract_address)); - assert!(extension.debt_caps(config.pool_id, config.collateral_asset.contract_address) == 1000); + assert!( + extension + .debt_caps( + config.pool_id, config.collateral_asset.contract_address, config.debt_asset.contract_address + ) == 1000 + ); } #[test] @@ -1000,8 +1012,16 @@ mod TestDefaultExtensionPO { create_pool(extension, config, users.creator, Option::None); - extension.set_debt_cap(config.pool_id, config.collateral_asset.contract_address, 1000); + extension + .set_debt_cap( + config.pool_id, config.collateral_asset.contract_address, config.debt_asset.contract_address, 1000 + ); - assert!(extension.debt_caps(config.pool_id, config.collateral_asset.contract_address) == 1000); + assert!( + extension + .debt_caps( + config.pool_id, config.collateral_asset.contract_address, config.debt_asset.contract_address + ) == 1000 + ); } } diff --git a/src/test/test_forking.cairo b/src/test/test_forking.cairo index ecedf3b..80a185e 100644 --- a/src/test/test_forking.cairo +++ b/src/test/test_forking.cairo @@ -43,7 +43,10 @@ mod TestForking { components::position_hooks::LiquidationData }, units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS, INFLATION_FEE}, - data_model::{AssetParams, LTVParams, ModifyPositionParams, Amount, AmountType, AmountDenomination, AssetPrice}, + data_model::{ + AssetParams, LTVParams, ModifyPositionParams, Amount, AmountType, AmountDenomination, AssetPrice, + DebtCapParams + }, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait, LiquidatePositionParams}, }; @@ -180,6 +183,45 @@ mod TestForking { liquidation_params.span() } + fn generate_debt_caps_for_pairs( + all_asset_params: Span, default_debt_cap: u256 + ) -> Span { + let mut pair_debt_caps: Array = array![]; + + let mut i = 0; + loop { + match all_asset_params.get(i) { + Option::Some(boxed_asset_params) => { + let mut asset_params = *boxed_asset_params.unbox(); + let mut j = 0; + loop { + match all_asset_params.get(j) { + Option::Some(boxed_paired_asset_params) => { + let mut paired_asset_params = *boxed_paired_asset_params.unbox(); + if asset_params.asset != paired_asset_params.asset { + pair_debt_caps + .append( + DebtCapParams { + collateral_asset_index: i, + debt_asset_index: j, + debt_cap: default_debt_cap + } + ); + } + }, + Option::None(_) => { break; } + }; + j += 1; + }; + }, + Option::None(_) => { break; } + }; + i += 1; + }; + + pair_debt_caps.span() + } + fn generate_shutdown_params(all_asset_params: Span) -> ShutdownParams { let mut shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS * 30, @@ -467,6 +509,7 @@ mod TestForking { let interest_rate_configs = generate_interest_rate_configs(asset_params); let liquidation_params = generate_liquidation_params(asset_params, ((9 * SCALE) / 10).try_into().unwrap()); + let debt_caps_params = generate_debt_caps_for_pairs(asset_params, 0); let shutdown_params = generate_shutdown_params(asset_params); let singleton = ISingletonDispatcher { contract_address: deploy_contract("Singleton") }; @@ -593,6 +636,7 @@ mod TestForking { interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: creator }, creator @@ -817,6 +861,7 @@ mod TestForking { let interest_rate_configs = generate_interest_rate_configs(asset_params); let liquidation_params = generate_liquidation_params(asset_params, ((9 * SCALE) / 10).try_into().unwrap()); + let debt_caps_params = generate_debt_caps_for_pairs(asset_params, 0); let shutdown_params = generate_shutdown_params(asset_params); // let singleton = ISingletonDispatcher { contract_address: deploy_contract("Singleton") }; @@ -845,6 +890,7 @@ mod TestForking { interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: creator }, creator diff --git a/src/test/test_pragma_oracle.cairo b/src/test/test_pragma_oracle.cairo index 8a24afc..e9acbfe 100644 --- a/src/test/test_pragma_oracle.cairo +++ b/src/test/test_pragma_oracle.cairo @@ -7,7 +7,7 @@ mod TestPragmaOracle { use starknet::{ContractAddress, get_block_timestamp}; use vesu::{ units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS}, - data_model::{Amount, AmountType, AmountDenomination, ModifyPositionParams}, + data_model::{Amount, AmountType, AmountDenomination, ModifyPositionParams, DebtCapParams}, singleton::{ISingletonDispatcherTrait, ISingletonDispatcher}, test::{ setup::{setup, setup_env, TestConfig, LendingTerms, COLL_PRAGMA_KEY, DEBT_PRAGMA_KEY, Env}, @@ -106,6 +106,11 @@ mod TestPragmaOracle { collateral_asset_index: 1, debt_asset_index: 0, liquidation_factor: 0 }; + let collateral_asset_debt_cap_params = DebtCapParams { + collateral_asset_index: 0, debt_asset_index: 1, debt_cap: 0 + }; + let debt_asset_debt_cap_params = DebtCapParams { collateral_asset_index: 1, debt_asset_index: 0, debt_cap: 0 }; + let shutdown_ltv_params_0 = LTVParams { collateral_asset_index: 1, debt_asset_index: 0, max_ltv: (75 * PERCENT).try_into().unwrap() }; @@ -121,6 +126,7 @@ mod TestPragmaOracle { let models = array![interest_rate_config, interest_rate_config].span(); let oracle_params = array![collateral_asset_oracle_params, debt_asset_oracle_params].span(); let liquidation_params = array![collateral_asset_liquidation_params, debt_asset_liquidation_params].span(); + let debt_caps = array![collateral_asset_debt_cap_params, debt_asset_debt_cap_params].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; @@ -136,6 +142,7 @@ mod TestPragmaOracle { models, oracle_params, liquidation_params, + debt_caps, shutdown_params, fee_params, creator diff --git a/yarn.lock b/yarn.lock index 0a71a92..4d51937 100644 --- a/yarn.lock +++ b/yarn.lock @@ -429,9 +429,9 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -"vesu_changelog@https://github.com/vesuxyz/changelog.git#921891b7e9afa7b66fefc386ba29bb2f4de08bc5": +"vesu_changelog@https://github.com/vesuxyz/changelog.git#d4de336513547448de52c949ea8fe09cd9e5848a": version "0.0.0" - resolved "https://github.com/vesuxyz/changelog.git#921891b7e9afa7b66fefc386ba29bb2f4de08bc5" + resolved "https://github.com/vesuxyz/changelog.git#d4de336513547448de52c949ea8fe09cd9e5848a" webidl-conversions@^3.0.0: version "3.0.1" From 8084ed997bfd8bb20dde4dac0112a42a01d38b6f Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:17:23 +0000 Subject: [PATCH 17/32] Update deployment scripts --- Scarb.toml | 1 + gas-report.txt | 4 ++-- lib/deployer.protocol.ts | 40 ++++++++++++++++++++++++------------- scripts/deployExtensions.ts | 9 +++++++++ 4 files changed, 38 insertions(+), 16 deletions(-) create mode 100644 scripts/deployExtensions.ts diff --git a/Scarb.toml b/Scarb.toml index d7619b0..0422764 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -38,6 +38,7 @@ deployDevnet = "scarb --profile release build && node --loader ts-node/esm ./scr deployMainnet = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployMainnet.ts" deploySepolia = "scarb --profile release build && node --loader ts-node/esm ./scripts/deploySepolia.ts" deployTimelock = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployTimelock.ts" +deployExtensions = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployExtensions.ts" checkGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --check" updateGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --write" test = "snforge test --max-n-steps 10000000" diff --git a/gas-report.txt b/gas-report.txt index 9263265..2efca3a 100644 --- a/gas-report.txt +++ b/gas-report.txt @@ -5,7 +5,7 @@ Summary: │ Create pool │ '1.914.968.000.000.000' │ 7.6598 │ 58968000000000 │ 1638 │ 1558 │ 310 │ 80 │ 'range_check' │ 273 │ 1856000000000000 │ 'BLOB' │ │ Lend │ '106.160.000.000.000' │ 0.4246 │ 16560000000000 │ 460 │ 458 │ 12 │ 2 │ 'range_check' │ 11 │ 89600000000000 │ 'BLOB' │ │ Transfer │ '102.792.000.000.000' │ 0.4111 │ 25992000000000 │ 722 │ 720 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ -│ Borrow │ '141.472.000.000.000' │ 0.5658 │ 19872000000000 │ 552 │ 550 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ +│ Borrow │ '141.220.000.000.000' │ 0.5648 │ 19620000000000 │ 545 │ 543 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ │ Liquidate │ '143.416.000.000.000' │ 0.5736 │ 21816000000000 │ 606 │ 604 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ └─────────────┴─────────────────────────┴─────────┴────────────────┴────────────────┴─────────────────┴───────────┴──────────────┴──────────────────────────────┴───────────────┴──────────────────┴─────────┘ Resources: @@ -15,6 +15,6 @@ Resources: │ Create pool │ 138 │ 3 │ 0 │ 0 │ 1772 │ 1 │ 38948 │ 580724 │ │ Lend │ 26 │ 3 │ 0 │ 0 │ 130 │ 0 │ 11439 │ 97265 │ │ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17988 │ 144867 │ -│ Borrow │ 33 │ 3 │ 0 │ 0 │ 143 │ 0 │ 13748 │ 110679 │ +│ Borrow │ 33 │ 3 │ 0 │ 0 │ 143 │ 0 │ 13568 │ 110475 │ │ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15088 │ 118968 │ └─────────────┴─────────┴───────┴───────┴────────┴──────────┴──────────┴─────────────┴────────┘ diff --git a/lib/deployer.protocol.ts b/lib/deployer.protocol.ts index 01f3525..bb2caea 100644 --- a/lib/deployer.protocol.ts +++ b/lib/deployer.protocol.ts @@ -77,22 +77,17 @@ export class Deployer extends BaseDeployer { return [contracts, response] as const; } + async deployExtensions(singleton: string, pragma: PragmaConfig) { + const [extensionPO, extensionCL, extensionCalls] = await this.deferExtensions(singleton, pragma); + const response = await this.execute([...extensionCalls]); + await this.waitForTransaction(response.transaction_hash); + return [extensionPO, extensionCL, response] as const; + } + async deferProtocol(pragma: PragmaConfig) { const [singleton, calls1] = await this.deferContract("Singleton"); - const v_token_class_hash = await this.declareCached("VToken"); - const calldataPO = CallData.compile({ - singleton: singleton.address, - oracle_address: pragma.oracle!, - summary_stats_address: pragma.summary_stats!, - v_token_class_hash: v_token_class_hash, - }); - const [extensionPO, calls2] = await this.deferContract("DefaultExtensionPO", calldataPO); - const calldataCL = CallData.compile({ - singleton: singleton.address, - v_token_class_hash: v_token_class_hash, - }); - const [extensionCL, calls3] = await this.deferContract("DefaultExtensionCL", calldataCL); - return [{ singleton, extensionPO, extensionCL }, [...calls1, ...calls2, ...calls3]] as const; + const [extensionPO, extensionCL, extensionCalls] = await this.deferExtensions(singleton.address, pragma); + return [{ singleton, extensionPO, extensionCL }, [...calls1, ...extensionCalls]] as const; } async deployEnv() { @@ -133,6 +128,23 @@ export class Deployer extends BaseDeployer { return [oracle, summary_stats, [...oracleCalls, ...summaryStatsCalls, ...setupCalls]] as const; } + async deferExtensions(singleton: string, pragma: PragmaConfig) { + const v_token_class_hash = await this.declareCached("VToken"); + const calldataPO = CallData.compile({ + singleton: singleton, + oracle_address: pragma.oracle!, + summary_stats_address: pragma.summary_stats!, + v_token_class_hash: v_token_class_hash, + }); + const [extensionPO, calls2] = await this.deferContract("DefaultExtensionPO", calldataPO); + const calldataCL = CallData.compile({ + singleton: singleton, + v_token_class_hash: v_token_class_hash, + }); + const [extensionCL, calls3] = await this.deferContract("DefaultExtensionCL", calldataCL); + return [extensionPO, extensionCL, [...calls2, ...calls3]] as const; + } + async setApprovals(contract: Contract, assets: Contract[]) { const approvalCalls = assets.map((asset, index) => { const { initial_supply } = this.config.env![index].erc20Params(); diff --git a/scripts/deployExtensions.ts b/scripts/deployExtensions.ts new file mode 100644 index 0000000..93fd3a8 --- /dev/null +++ b/scripts/deployExtensions.ts @@ -0,0 +1,9 @@ +import { setup } from "../lib"; + +const deployer = await setup("mainnet"); + +const [extensionPO, extensionCL,] = await deployer.deployExtensions(deployer.config.protocol.singleton!, deployer.config.protocol.pragma); + +console.log("ExtensionPO: ", extensionPO.address); +console.log("ExtensionCL: ", extensionCL.address); + From 54ba4ad665d31b0b0b6d206d6493157a81201150 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:20:18 +0000 Subject: [PATCH 18/32] Fmt --- scripts/deployExtensions.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/deployExtensions.ts b/scripts/deployExtensions.ts index 93fd3a8..0a691af 100644 --- a/scripts/deployExtensions.ts +++ b/scripts/deployExtensions.ts @@ -2,8 +2,10 @@ import { setup } from "../lib"; const deployer = await setup("mainnet"); -const [extensionPO, extensionCL,] = await deployer.deployExtensions(deployer.config.protocol.singleton!, deployer.config.protocol.pragma); +const [extensionPO, extensionCL] = await deployer.deployExtensions( + deployer.config.protocol.singleton!, + deployer.config.protocol.pragma, +); console.log("ExtensionPO: ", extensionPO.address); console.log("ExtensionCL: ", extensionCL.address); - From 5bce18aac61d786fff8f46a60236c5072e1084af Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:58:59 +0000 Subject: [PATCH 19/32] Assert return values of ERC20 calls --- src/extension/default_extension_cl.cairo | 17 +++++++++++------ src/extension/default_extension_po.cairo | 17 +++++++++++------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/extension/default_extension_cl.cairo b/src/extension/default_extension_cl.cairo index d8ab7cf..e3a76dd 100644 --- a/src/extension/default_extension_cl.cairo +++ b/src/extension/default_extension_cl.cairo @@ -542,8 +542,11 @@ mod DefaultExtensionCL { // burn inflation fee let asset = IERC20Dispatcher { contract_address: asset }; - asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE); - asset.approve(singleton.contract_address, INFLATION_FEE); + assert!( + asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE), + "transfer-from-failed" + ); + assert!(asset.approve(singleton.contract_address, INFLATION_FEE), "approve-failed"); singleton .modify_position( ModifyPositionParams { @@ -651,13 +654,15 @@ mod DefaultExtensionCL { let VTokenParams { v_token_name, v_token_symbol } = v_token_params; self.tokenization.create_v_token(pool_id, asset, v_token_name, v_token_symbol); - ISingletonDispatcher { contract_address: self.singleton.read() }.set_asset_config(pool_id, asset_params); + let singleton = ISingletonDispatcher { contract_address: self.singleton.read() }; + singleton.set_asset_config(pool_id, asset_params); // burn inflation fee - let singleton = ISingletonDispatcher { contract_address: self.singleton.read() }; let asset = IERC20Dispatcher { contract_address: asset }; - asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE); - asset.approve(singleton.contract_address, INFLATION_FEE); + assert!( + asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE), "transfer-from-failed" + ); + assert!(asset.approve(singleton.contract_address, INFLATION_FEE), "approve-failed"); singleton .modify_position( ModifyPositionParams { diff --git a/src/extension/default_extension_po.cairo b/src/extension/default_extension_po.cairo index 96f116e..1b21186 100644 --- a/src/extension/default_extension_po.cairo +++ b/src/extension/default_extension_po.cairo @@ -629,8 +629,11 @@ mod DefaultExtensionPO { // burn inflation fee let asset = IERC20Dispatcher { contract_address: asset }; - asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE); - asset.approve(singleton.contract_address, INFLATION_FEE); + assert!( + asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE), + "transfer-from-failed" + ); + assert!(asset.approve(singleton.contract_address, INFLATION_FEE), "approve-failed"); singleton .modify_position( ModifyPositionParams { @@ -743,13 +746,15 @@ mod DefaultExtensionPO { let VTokenParams { v_token_name, v_token_symbol } = v_token_params; self.tokenization.create_v_token(pool_id, asset, v_token_name, v_token_symbol); - ISingletonDispatcher { contract_address: self.singleton.read() }.set_asset_config(pool_id, asset_params); + let singleton = ISingletonDispatcher { contract_address: self.singleton.read() }; + singleton.set_asset_config(pool_id, asset_params); // burn inflation fee - let singleton = ISingletonDispatcher { contract_address: self.singleton.read() }; let asset = IERC20Dispatcher { contract_address: asset }; - asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE); - asset.approve(singleton.contract_address, INFLATION_FEE); + assert!( + asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE), "transfer-from-failed" + ); + assert!(asset.approve(singleton.contract_address, INFLATION_FEE), "approve-failed"); singleton .modify_position( ModifyPositionParams { From 14944acc7a5edf5780b2a53897c4834e9213f9e7 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 27 Nov 2024 13:58:21 +0000 Subject: [PATCH 20/32] Fix summary_stats address in deployment scripts --- lib/config.mainnet.ts | 2 +- lib/config.sepolia.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index 5b1e390..fbc862c 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -33,7 +33,7 @@ export const config: Config = { extensionCL: DEPLOYMENT.extensionCL || "0x0", pragma: { oracle: DEPLOYMENT.oracle || CONFIG.asset_parameters[0].pragma.oracle, - summary_stats: DEPLOYMENT.summary_stats || CONFIG.asset_parameters[0].pragma.oracle, + summary_stats: DEPLOYMENT.summary_stats || CONFIG.asset_parameters[0].pragma.summary_stats, }, }, env, diff --git a/lib/config.sepolia.ts b/lib/config.sepolia.ts index fa87f84..8c1f55d 100644 --- a/lib/config.sepolia.ts +++ b/lib/config.sepolia.ts @@ -52,7 +52,7 @@ export const config: Config = { extensionCL: DEPLOYMENT.extensionCL || "0x0", pragma: { oracle: DEPLOYMENT.oracle || CONFIG.asset_parameters[0].pragma.oracle || "0x0", - summary_stats: DEPLOYMENT.summary_stats || CONFIG.asset_parameters[0].pragma.oracle || "0x0", + summary_stats: DEPLOYMENT.summary_stats || CONFIG.asset_parameters[0].pragma.summary_stats || "0x0", }, }, env, From 3951841eefd80ff93693e0e4a8e1f60585fa031f Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 27 Nov 2024 15:50:19 +0000 Subject: [PATCH 21/32] Fix deployExtensions script --- lib/config.mainnet.ts | 9 +++------ lib/config.sepolia.ts | 12 ++++-------- lib/deployer.protocol.ts | 1 + package.json | 2 +- yarn.lock | 4 ++-- 5 files changed, 11 insertions(+), 17 deletions(-) diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index fbc862c..bdf1f94 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -3,10 +3,7 @@ import { CairoCustomEnum } from "starknet"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; -let DEPLOYMENT: any = {}; -try { - DEPLOYMENT = JSON.parse(fs.readFileSync(`deployment-....json`, "utf-8")); -} catch (error) {} +import DEPLOYMENT from "vesu_changelog/deployments/deployment_sn_main.json" assert { type: "json" }; const env = CONFIG.asset_parameters.map( (asset: any) => @@ -32,8 +29,8 @@ export const config: Config = { extensionPO: DEPLOYMENT.extensionPO || "0x0", extensionCL: DEPLOYMENT.extensionCL || "0x0", pragma: { - oracle: DEPLOYMENT.oracle || CONFIG.asset_parameters[0].pragma.oracle, - summary_stats: DEPLOYMENT.summary_stats || CONFIG.asset_parameters[0].pragma.summary_stats, + oracle: DEPLOYMENT.pragma.oracle || CONFIG.asset_parameters[0].pragma.oracle || "0x0", + summary_stats: DEPLOYMENT.pragma.summary_stats || CONFIG.asset_parameters[0].pragma.summary_stats || "0x0", }, }, env, diff --git a/lib/config.sepolia.ts b/lib/config.sepolia.ts index 8c1f55d..5a45ae5 100644 --- a/lib/config.sepolia.ts +++ b/lib/config.sepolia.ts @@ -1,12 +1,8 @@ import fs from "fs"; import { CairoCustomEnum } from "starknet"; -import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; +import CONFIG from "vesu_changelog/configurations/config_genesis_sn_sepolia.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; - -let DEPLOYMENT: any = {}; -try { - DEPLOYMENT = JSON.parse(fs.readFileSync(`deployment-0x534e5f5345504f4c4941.json`, "utf-8")); -} catch (error) {} +import DEPLOYMENT from "vesu_changelog/deployments/deployment_sn_sepolia.json" assert { type: "json" }; function price(symbol: string) { switch (symbol) { @@ -51,8 +47,8 @@ export const config: Config = { extensionPO: DEPLOYMENT.extensionPO || "0x0", extensionCL: DEPLOYMENT.extensionCL || "0x0", pragma: { - oracle: DEPLOYMENT.oracle || CONFIG.asset_parameters[0].pragma.oracle || "0x0", - summary_stats: DEPLOYMENT.summary_stats || CONFIG.asset_parameters[0].pragma.summary_stats || "0x0", + oracle: DEPLOYMENT.pragma.oracle || CONFIG.asset_parameters[0].pragma.oracle || "0x0", + summary_stats: DEPLOYMENT.pragma.summary_stats || CONFIG.asset_parameters[0].pragma.summary_stats || "0x0", }, }, env, diff --git a/lib/deployer.protocol.ts b/lib/deployer.protocol.ts index bb2caea..ae7a662 100644 --- a/lib/deployer.protocol.ts +++ b/lib/deployer.protocol.ts @@ -56,6 +56,7 @@ export class Deployer extends BaseDeployer { const addresses = Object.values(pools) .flatMap(({ params }) => params.asset_params.map(({ asset }) => asset)) .map(this.loadContract.bind(this)); + console.log(protocol); const contracts = { singleton: await this.loadContract(protocol.singleton!), extensionPO: await this.loadContract(protocol.extensionPO!), diff --git a/package.json b/package.json index 0128e5f..0f23cc2 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@types/lodash-es": "^4.17.12", "@types/node": "^20.10.5", "bignumber.js": "9.1.2", - "vesu_changelog": "https://github.com/vesuxyz/changelog.git#d4de336513547448de52c949ea8fe09cd9e5848a", + "vesu_changelog": "https://github.com/vesuxyz/changelog.git#74cb1d1ace529f861dd8b1a6644f90eea49e9dcc", "dotenv": "^16.3.1", "lodash-es": "^4.17.21", "prettier": "^3.1.1", diff --git a/yarn.lock b/yarn.lock index 4d51937..de83122 100644 --- a/yarn.lock +++ b/yarn.lock @@ -429,9 +429,9 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -"vesu_changelog@https://github.com/vesuxyz/changelog.git#d4de336513547448de52c949ea8fe09cd9e5848a": +"vesu_changelog@https://github.com/vesuxyz/changelog.git#74cb1d1ace529f861dd8b1a6644f90eea49e9dcc": version "0.0.0" - resolved "https://github.com/vesuxyz/changelog.git#d4de336513547448de52c949ea8fe09cd9e5848a" + resolved "https://github.com/vesuxyz/changelog.git#74cb1d1ace529f861dd8b1a6644f90eea49e9dcc" webidl-conversions@^3.0.0: version "3.0.1" From bd94a632d4fb7c22dac7e964b46c741a84521e3d Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Fri, 29 Nov 2024 14:23:12 +0000 Subject: [PATCH 22/32] Skip pair collateralization check if max_ltv == 0 --- src/extension/components/position_hooks.cairo | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/extension/components/position_hooks.cairo b/src/extension/components/position_hooks.cairo index 5d6ca22..cdd7938 100644 --- a/src/extension/components/position_hooks.cairo +++ b/src/extension/components/position_hooks.cairo @@ -200,7 +200,11 @@ mod position_hooks_component { let LTVConfig { max_ltv } = self .shutdown_ltv_configs .read((context.pool_id, context.collateral_asset, context.debt_asset)); - is_collateralized(collateral_value, debt_value, max_ltv.into()) + if max_ltv != 0 { + is_collateralized(collateral_value, debt_value, max_ltv.into()) + } else { + true + } } /// Sets the debt cap for an asset in a pool. From 830ab6c468c1f3e39bdfe623d7f93abf464f635d Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Fri, 29 Nov 2024 15:03:51 +0000 Subject: [PATCH 23/32] Fmt --- lib/config.mainnet.ts | 1 - lib/config.sepolia.ts | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index bdf1f94..50606ba 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -1,4 +1,3 @@ -import fs from "fs"; import { CairoCustomEnum } from "starknet"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; diff --git a/lib/config.sepolia.ts b/lib/config.sepolia.ts index 5a45ae5..b1b8b22 100644 --- a/lib/config.sepolia.ts +++ b/lib/config.sepolia.ts @@ -1,8 +1,7 @@ -import fs from "fs"; import { CairoCustomEnum } from "starknet"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_sepolia.json" assert { type: "json" }; -import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; import DEPLOYMENT from "vesu_changelog/deployments/deployment_sn_sepolia.json" assert { type: "json" }; +import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; function price(symbol: string) { switch (symbol) { From f44e4efb3b22a33f8109a4dff6c86fa9b4638683 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Sat, 30 Nov 2024 14:58:23 +0000 Subject: [PATCH 24/32] Add ability to update twap params and cl aggregator address --- lib/config.mainnet.ts | 1 - lib/config.sepolia.ts | 3 +- .../components/chainlink_oracle.cairo | 10 ++++--- src/extension/components/pragma_oracle.cairo | 22 +++++++++++--- src/extension/default_extension_cl.cairo | 4 +-- src/extension/default_extension_po.cairo | 4 +-- src/test/test_default_extension_cl.cairo | 29 ++++++++++++++----- src/test/test_default_extension_po.cairo | 12 ++++---- 8 files changed, 57 insertions(+), 28 deletions(-) diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index bdf1f94..50606ba 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -1,4 +1,3 @@ -import fs from "fs"; import { CairoCustomEnum } from "starknet"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; diff --git a/lib/config.sepolia.ts b/lib/config.sepolia.ts index 5a45ae5..b1b8b22 100644 --- a/lib/config.sepolia.ts +++ b/lib/config.sepolia.ts @@ -1,8 +1,7 @@ -import fs from "fs"; import { CairoCustomEnum } from "starknet"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_sepolia.json" assert { type: "json" }; -import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; import DEPLOYMENT from "vesu_changelog/deployments/deployment_sn_sepolia.json" assert { type: "json" }; +import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; function price(symbol: string) { switch (symbol) { diff --git a/src/extension/components/chainlink_oracle.cairo b/src/extension/components/chainlink_oracle.cairo index 2e223c8..7e6a814 100644 --- a/src/extension/components/chainlink_oracle.cairo +++ b/src/extension/components/chainlink_oracle.cairo @@ -37,7 +37,7 @@ mod chainlink_oracle_component { pool_id: felt252, asset: ContractAddress, parameter: felt252, - value: u64, + value: felt252, } #[event] @@ -104,15 +104,17 @@ mod chainlink_oracle_component { pool_id: felt252, asset: ContractAddress, parameter: felt252, - value: u64 + value: felt252 ) { let mut chainlink_oracle_config: ChainlinkOracleConfig = self .chainlink_oracle_configs .read((pool_id, asset)); assert!(chainlink_oracle_config.aggregator != Zeroable::zero(), "chainlink-oracle-config-not-set"); - if parameter == 'timeout' { - chainlink_oracle_config.timeout = value; + if parameter == 'aggregator' { + chainlink_oracle_config.aggregator = value.try_into().unwrap(); + } else if parameter == 'timeout' { + chainlink_oracle_config.timeout = value.try_into().unwrap(); } else { assert!(false, "invalid-chainlink-oracle-parameter"); } diff --git a/src/extension/components/pragma_oracle.cairo b/src/extension/components/pragma_oracle.cairo index 6728a2a..93f6f76 100644 --- a/src/extension/components/pragma_oracle.cairo +++ b/src/extension/components/pragma_oracle.cairo @@ -51,7 +51,7 @@ mod pragma_oracle_component { pool_id: felt252, asset: ContractAddress, parameter: felt252, - value: u64, + value: felt252, } #[event] @@ -172,15 +172,29 @@ mod pragma_oracle_component { pool_id: felt252, asset: ContractAddress, parameter: felt252, - value: u64 + value: felt252 ) { let mut oracle_config: OracleConfig = self.oracle_configs.read((pool_id, asset)); assert!(oracle_config.pragma_key != 0, "oracle-config-not-set"); - if parameter == 'timeout' { - oracle_config.timeout = value; + if parameter == 'pragma_key' { + oracle_config.pragma_key = value; + } else if parameter == 'timeout' { + oracle_config.timeout = value.try_into().unwrap(); } else if parameter == 'number_of_sources' { oracle_config.number_of_sources = value.try_into().unwrap(); + } else if parameter == 'start_time_offset' { + oracle_config.start_time_offset = value.try_into().unwrap(); + } else if parameter == 'time_window' { + oracle_config.time_window = value.try_into().unwrap(); + } else if parameter == 'aggregation_mode' { + if value == 'Median' { + oracle_config.aggregation_mode = AggregationMode::Median; + } else if value == 'Mean' { + oracle_config.aggregation_mode = AggregationMode::Mean; + } else { + assert!(false, "invalid-aggregation-mode"); + } } else { assert!(false, "invalid-oracle-parameter"); } diff --git a/src/extension/default_extension_cl.cairo b/src/extension/default_extension_cl.cairo index e3a76dd..9e05cbf 100644 --- a/src/extension/default_extension_cl.cairo +++ b/src/extension/default_extension_cl.cairo @@ -91,7 +91,7 @@ trait IDefaultExtensionCL { ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u256 ); fn set_chainlink_oracle_parameter( - ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u64 + ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: felt252 ); fn set_liquidation_config( ref self: TContractState, @@ -718,7 +718,7 @@ mod DefaultExtensionCL { /// * `parameter` - parameter name /// * `value` - value of the parameter fn set_chainlink_oracle_parameter( - ref self: ContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u64 + ref self: ContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: felt252 ) { assert!(get_caller_address() == self.owner.read(pool_id), "caller-not-owner"); self.chainlink_oracle.set_chainlink_oracle_parameter(pool_id, asset, parameter, value); diff --git a/src/extension/default_extension_po.cairo b/src/extension/default_extension_po.cairo index 1b21186..51fbd2e 100644 --- a/src/extension/default_extension_po.cairo +++ b/src/extension/default_extension_po.cairo @@ -148,7 +148,7 @@ trait IDefaultExtension { ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u256 ); fn set_oracle_parameter( - ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u64 + ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: felt252 ); fn set_liquidation_config( ref self: TContractState, @@ -810,7 +810,7 @@ mod DefaultExtensionPO { /// * `parameter` - parameter name /// * `value` - value of the parameter fn set_oracle_parameter( - ref self: ContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u64 + ref self: ContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: felt252 ) { assert!(get_caller_address() == self.owner.read(pool_id), "caller-not-owner"); self.pragma_oracle.set_oracle_parameter(pool_id, asset, parameter, value); diff --git a/src/test/test_default_extension_cl.cairo b/src/test/test_default_extension_cl.cairo index 955291a..303790f 100644 --- a/src/test/test_default_extension_cl.cairo +++ b/src/test/test_default_extension_cl.cairo @@ -803,7 +803,7 @@ mod TestDefaultExtensionCL { } #[test] - fn test_extension_set_oracle_parameter() { + fn test_extension_set_chainlink_oracle_parameter() { let Env { extension_v2, config, users, .. } = setup_env( Zeroable::zero(), Zeroable::zero(), Zeroable::zero(), Zeroable::zero() ); @@ -813,18 +813,29 @@ mod TestDefaultExtensionCL { start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); extension_v2 .set_chainlink_oracle_parameter( - config.pool_id_v2, config.collateral_asset.contract_address, 'timeout', 5_u64 + config.pool_id_v2, config.collateral_asset.contract_address, 'timeout', 5_u64.into() ); stop_prank(CheatTarget::One(extension_v2.contract_address)); let oracle_config = extension_v2 .chainlink_oracle_config(config.pool_id_v2, config.collateral_asset.contract_address); assert(oracle_config.timeout == 5_u64, 'Oracle parameter not set'); + + start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); + extension_v2 + .set_chainlink_oracle_parameter( + config.pool_id_v2, config.collateral_asset.contract_address, 'aggregator', users.creator.into() + ); + stop_prank(CheatTarget::One(extension_v2.contract_address)); + + let oracle_config = extension_v2 + .chainlink_oracle_config(config.pool_id_v2, config.collateral_asset.contract_address); + assert(oracle_config.aggregator == users.creator, 'Oracle parameter not set'); } #[test] #[should_panic(expected: "caller-not-owner")] - fn test_extension_set_oracle_parameter_caller_not_owner() { + fn test_extension_set_chainlink_oracle_parameter_caller_not_owner() { let Env { extension_v2, config, users, .. } = setup_env( Zeroable::zero(), Zeroable::zero(), Zeroable::zero(), Zeroable::zero() ); @@ -833,13 +844,13 @@ mod TestDefaultExtensionCL { extension_v2 .set_chainlink_oracle_parameter( - config.pool_id_v2, config.collateral_asset.contract_address, 'timeout', 5_u64 + config.pool_id_v2, config.collateral_asset.contract_address, 'timeout', 5_u64.into() ); } #[test] #[should_panic(expected: "invalid-chainlink-oracle-parameter")] - fn test_extension_set_oracle_parameter_invalid_oracle_parameter() { + fn test_extension_set_chainlink_oracle_parameter_invalid_chainlink_oracle_parameter() { let Env { extension_v2, config, users, .. } = setup_env( Zeroable::zero(), Zeroable::zero(), Zeroable::zero(), Zeroable::zero() ); @@ -848,13 +859,15 @@ mod TestDefaultExtensionCL { start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); extension_v2 - .set_chainlink_oracle_parameter(config.pool_id_v2, config.collateral_asset.contract_address, 'a', 5_u64); + .set_chainlink_oracle_parameter( + config.pool_id_v2, config.collateral_asset.contract_address, 'a', 5_u64.into() + ); stop_prank(CheatTarget::One(extension_v2.contract_address)); } #[test] #[should_panic(expected: "chainlink-oracle-config-not-set")] - fn test_extension_set_oracle_parameter_oracle_config_not_set() { + fn test_extension_set_chainlink_oracle_parameter_chainlink_oracle_config_not_set() { let Env { extension_v2, config, users, .. } = setup_env( Zeroable::zero(), Zeroable::zero(), Zeroable::zero(), Zeroable::zero() ); @@ -862,7 +875,7 @@ mod TestDefaultExtensionCL { create_pool_v2(extension_v2, config, users.creator, Option::None); start_prank(CheatTarget::One(extension_v2.contract_address), users.creator); - extension_v2.set_chainlink_oracle_parameter(config.pool_id_v2, Zeroable::zero(), 'timeout', 5_u64); + extension_v2.set_chainlink_oracle_parameter(config.pool_id_v2, Zeroable::zero(), 'timeout', 5_u64.into()); stop_prank(CheatTarget::One(extension_v2.contract_address)); } diff --git a/src/test/test_default_extension_po.cairo b/src/test/test_default_extension_po.cairo index 84bfa3f..af1da20 100644 --- a/src/test/test_default_extension_po.cairo +++ b/src/test/test_default_extension_po.cairo @@ -765,7 +765,8 @@ mod TestDefaultExtensionPO { create_pool(extension, config, users.creator, Option::None); start_prank(CheatTarget::One(extension.contract_address), users.creator); - extension.set_oracle_parameter(config.pool_id, config.collateral_asset.contract_address, 'timeout', 5_u64); + extension + .set_oracle_parameter(config.pool_id, config.collateral_asset.contract_address, 'timeout', 5_u64.into()); stop_prank(CheatTarget::One(extension.contract_address)); let oracle_config = extension.oracle_config(config.pool_id, config.collateral_asset.contract_address); @@ -774,7 +775,7 @@ mod TestDefaultExtensionPO { start_prank(CheatTarget::One(extension.contract_address), users.creator); extension .set_oracle_parameter( - config.pool_id, config.collateral_asset.contract_address, 'number_of_sources', 11_u64 + config.pool_id, config.collateral_asset.contract_address, 'number_of_sources', 11_u64.into() ); stop_prank(CheatTarget::One(extension.contract_address)); @@ -791,7 +792,8 @@ mod TestDefaultExtensionPO { create_pool(extension, config, users.creator, Option::None); - extension.set_oracle_parameter(config.pool_id, config.collateral_asset.contract_address, 'timeout', 5_u64); + extension + .set_oracle_parameter(config.pool_id, config.collateral_asset.contract_address, 'timeout', 5_u64.into()); } #[test] @@ -804,7 +806,7 @@ mod TestDefaultExtensionPO { create_pool(extension, config, users.creator, Option::None); start_prank(CheatTarget::One(extension.contract_address), users.creator); - extension.set_oracle_parameter(config.pool_id, config.collateral_asset.contract_address, 'a', 5_u64); + extension.set_oracle_parameter(config.pool_id, config.collateral_asset.contract_address, 'a', 5_u64.into()); stop_prank(CheatTarget::One(extension.contract_address)); } @@ -818,7 +820,7 @@ mod TestDefaultExtensionPO { create_pool(extension, config, users.creator, Option::None); start_prank(CheatTarget::One(extension.contract_address), users.creator); - extension.set_oracle_parameter(config.pool_id, Zeroable::zero(), 'timeout', 5_u64); + extension.set_oracle_parameter(config.pool_id, Zeroable::zero(), 'timeout', 5_u64.into()); stop_prank(CheatTarget::One(extension.contract_address)); } From 4a2bdbf18aefe0e571d583ae7c41f90f52d26c3e Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:35:58 +0000 Subject: [PATCH 25/32] Update oracle_config assertion and add tests --- gas-report.txt | 18 +++--- src/extension/components/pragma_oracle.cairo | 4 +- src/test/test_default_extension_po.cairo | 59 +++++++++++++++++++- 3 files changed, 67 insertions(+), 14 deletions(-) diff --git a/gas-report.txt b/gas-report.txt index 2efca3a..8962929 100644 --- a/gas-report.txt +++ b/gas-report.txt @@ -2,19 +2,19 @@ Summary: ┌─────────────┬─────────────────────────┬─────────┬────────────────┬────────────────┬─────────────────┬───────────┬──────────────┬──────────────────────────────┬───────────────┬──────────────────┬─────────┐ │ (index) │ Actual fee │ Fee usd │ Fee without DA │ Gas without DA │ Computation gas │ Event gas │ Calldata gas │ Max computation per Category │ Storage diffs │ DA fee │ DA mode │ ├─────────────┼─────────────────────────┼─────────┼────────────────┼────────────────┼─────────────────┼───────────┼──────────────┼──────────────────────────────┼───────────────┼──────────────────┼─────────┤ -│ Create pool │ '1.914.968.000.000.000' │ 7.6598 │ 58968000000000 │ 1638 │ 1558 │ 310 │ 80 │ 'range_check' │ 273 │ 1856000000000000 │ 'BLOB' │ -│ Lend │ '106.160.000.000.000' │ 0.4246 │ 16560000000000 │ 460 │ 458 │ 12 │ 2 │ 'range_check' │ 11 │ 89600000000000 │ 'BLOB' │ -│ Transfer │ '102.792.000.000.000' │ 0.4111 │ 25992000000000 │ 722 │ 720 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ +│ Create pool │ '1.914.464.000.000.000' │ 7.6578 │ 58464000000000 │ 1624 │ 1544 │ 310 │ 80 │ 'range_check' │ 273 │ 1856000000000000 │ 'BLOB' │ +│ Lend │ '106.412.000.000.000' │ 0.4256 │ 16812000000000 │ 467 │ 465 │ 12 │ 2 │ 'range_check' │ 11 │ 89600000000000 │ 'BLOB' │ +│ Transfer │ '102.720.000.000.000' │ 0.4108 │ 25920000000000 │ 720 │ 718 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ │ Borrow │ '141.220.000.000.000' │ 0.5648 │ 19620000000000 │ 545 │ 543 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ -│ Liquidate │ '143.416.000.000.000' │ 0.5736 │ 21816000000000 │ 606 │ 604 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ +│ Liquidate │ '143.668.000.000.000' │ 0.5746 │ 22068000000000 │ 613 │ 611 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ └─────────────┴─────────────────────────┴─────────┴────────────────┴────────────────┴─────────────────┴───────────┴──────────────┴──────────────────────────────┴───────────────┴──────────────────┴─────────┘ Resources: ┌─────────────┬─────────┬───────┬───────┬────────┬──────────┬──────────┬─────────────┬────────┐ │ (index) │ bitwise │ ec_op │ ecdsa │ keccak │ pedersen │ poseidon │ range_check │ steps │ ├─────────────┼─────────┼───────┼───────┼────────┼──────────┼──────────┼─────────────┼────────┤ -│ Create pool │ 138 │ 3 │ 0 │ 0 │ 1772 │ 1 │ 38948 │ 580724 │ -│ Lend │ 26 │ 3 │ 0 │ 0 │ 130 │ 0 │ 11439 │ 97265 │ -│ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17988 │ 144867 │ -│ Borrow │ 33 │ 3 │ 0 │ 0 │ 143 │ 0 │ 13568 │ 110475 │ -│ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15088 │ 118968 │ +│ Create pool │ 138 │ 3 │ 0 │ 0 │ 1772 │ 1 │ 38582 │ 580349 │ +│ Lend │ 26 │ 3 │ 0 │ 0 │ 130 │ 0 │ 11619 │ 97475 │ +│ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17926 │ 144801 │ +│ Borrow │ 33 │ 3 │ 0 │ 0 │ 143 │ 0 │ 13568 │ 110481 │ +│ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15268 │ 119184 │ └─────────────┴─────────┴───────┴───────┴────────┴──────────┴──────────┴─────────────┴────────┘ diff --git a/src/extension/components/pragma_oracle.cairo b/src/extension/components/pragma_oracle.cairo index 93f6f76..8fba3cf 100644 --- a/src/extension/components/pragma_oracle.cairo +++ b/src/extension/components/pragma_oracle.cairo @@ -13,9 +13,7 @@ struct OracleConfig { fn assert_oracle_config(oracle_config: OracleConfig) { assert!(oracle_config.pragma_key != 0, "pragma-key-must-be-set"); assert!( - (oracle_config.start_time_offset == 0 && oracle_config.time_window == 0) - || (oracle_config.start_time_offset != 0 && oracle_config.time_window != 0), - "pragma-start-time-and-time-window-must-be-set-together" + oracle_config.time_window <= oracle_config.start_time_offset, "time-window-must-be-less-than-start-time-offset" ); } diff --git a/src/test/test_default_extension_po.cairo b/src/test/test_default_extension_po.cairo index af1da20..b99bbc1 100644 --- a/src/test/test_default_extension_po.cairo +++ b/src/test/test_default_extension_po.cairo @@ -770,7 +770,7 @@ mod TestDefaultExtensionPO { stop_prank(CheatTarget::One(extension.contract_address)); let oracle_config = extension.oracle_config(config.pool_id, config.collateral_asset.contract_address); - assert(oracle_config.timeout == 5_u64, 'Oracle parameter not set'); + assert(oracle_config.timeout == 5_u64, 'timeout not set'); start_prank(CheatTarget::One(extension.contract_address), users.creator); extension @@ -780,7 +780,45 @@ mod TestDefaultExtensionPO { stop_prank(CheatTarget::One(extension.contract_address)); let oracle_config = extension.oracle_config(config.pool_id, config.collateral_asset.contract_address); - assert(oracle_config.number_of_sources == 11, 'Oracle parameter not set'); + assert(oracle_config.number_of_sources == 11, 'number_of_sources not set'); + + start_prank(CheatTarget::One(extension.contract_address), users.creator); + extension + .set_oracle_parameter( + config.pool_id, config.collateral_asset.contract_address, 'start_time_offset', 10_u64.into() + ); + stop_prank(CheatTarget::One(extension.contract_address)); + + let oracle_config = extension.oracle_config(config.pool_id, config.collateral_asset.contract_address); + assert(oracle_config.start_time_offset == 10, 'start_time_offset not set'); + + start_prank(CheatTarget::One(extension.contract_address), users.creator); + extension + .set_oracle_parameter( + config.pool_id, config.collateral_asset.contract_address, 'time_window', 10_u64.into() + ); + stop_prank(CheatTarget::One(extension.contract_address)); + + let oracle_config = extension.oracle_config(config.pool_id, config.collateral_asset.contract_address); + assert(oracle_config.time_window == 10, 'time_window not set'); + + start_prank(CheatTarget::One(extension.contract_address), users.creator); + extension + .set_oracle_parameter( + config.pool_id, config.collateral_asset.contract_address, 'aggregation_mode', 'Mean'.into() + ); + stop_prank(CheatTarget::One(extension.contract_address)); + + let oracle_config = extension.oracle_config(config.pool_id, config.collateral_asset.contract_address); + assert(oracle_config.aggregation_mode == AggregationMode::Mean, 'aggregation_mode not set'); + + start_prank(CheatTarget::One(extension.contract_address), users.creator); + extension + .set_oracle_parameter(config.pool_id, config.collateral_asset.contract_address, 'pragma_key', '123'.into()); + stop_prank(CheatTarget::One(extension.contract_address)); + + let oracle_config = extension.oracle_config(config.pool_id, config.collateral_asset.contract_address); + assert(oracle_config.pragma_key == '123', 'pragma_key not set'); } #[test] @@ -824,6 +862,23 @@ mod TestDefaultExtensionPO { stop_prank(CheatTarget::One(extension.contract_address)); } + #[test] + #[should_panic(expected: "time-window-must-be-less-than-start-time-offset")] + fn test_extension_set_oracle_parameter_time_window_greater_than_start_time_offset() { + let Env { extension, config, users, .. } = setup_env( + Zeroable::zero(), Zeroable::zero(), Zeroable::zero(), Zeroable::zero() + ); + + create_pool(extension, config, users.creator, Option::None); + + start_prank(CheatTarget::One(extension.contract_address), users.creator); + extension + .set_oracle_parameter( + config.pool_id, config.collateral_asset.contract_address, 'time_window', 1_u64.into() + ); + stop_prank(CheatTarget::One(extension.contract_address)); + } + #[test] fn test_extension_set_interest_rate_parameter() { let Env { extension, config, users, .. } = setup_env( From 0f8b1c8a54ad0758c066b648cf6cc7c0e26b300b Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:02:17 +0000 Subject: [PATCH 26/32] Add verifyPool script --- lib/config.mainnet.ts | 8 ++-- lib/config.ts | 2 +- lib/model.ts | 3 ++ scripts/verifyPool.ts | 103 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 scripts/verifyPool.ts diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index 50606ba..fa89391 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -14,7 +14,7 @@ const env = CONFIG.asset_parameters.map( asset.pragma.pragma_key, 0n, asset.token.is_legacy, - BigInt(asset.fee_rate), + toScale(asset.fee_rate), asset.v_token.v_token_name, asset.v_token.v_token_symbol, asset.token.address, @@ -76,9 +76,9 @@ export const config: Config = { pragma_key: asset.pragma.pragma_key, timeout: BigInt(asset.pragma.timeout), number_of_sources: BigInt(asset.pragma.number_of_sources), - start_time_offset: 0n, // BigInt(asset.pragma.start_time_offset), - time_window: 0n, // BigInt(asset.pragma.time_window), - aggregation_mode: new CairoCustomEnum({ Median: {} }), // new CairoCustomEnum({ [(asset.pragma.aggregation_mode == 0) ? "Median" : "Error"]: {} }) + start_time_offset: BigInt(asset.pragma.start_time_offset), + time_window: BigInt(asset.pragma.time_window), + aggregation_mode: new CairoCustomEnum({ Median: {}, Mean: undefined, Error: undefined }), })), liquidation_params: CONFIG.pair_parameters.map((pair: any) => { const collateral_asset_index = CONFIG.asset_parameters.findIndex( diff --git a/lib/config.ts b/lib/config.ts index b8c0b33..ac5dce3 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -78,7 +78,7 @@ function stringifyAddresses(value: any): any { if (isArray(value)) { return value.map(stringifyAddresses); } - return value?.address ? value.address : value; + return value?.address ? value.address : value.oracle.address; } export function mapAssetPairs( diff --git a/lib/model.ts b/lib/model.ts index 6b53a5a..104e169 100644 --- a/lib/model.ts +++ b/lib/model.ts @@ -39,6 +39,9 @@ export interface PragmaOracleParams { pragma_key: BigNumberish; timeout: bigint; number_of_sources: bigint; + start_time_offset: bigint; + time_window: bigint; + aggregation_mode: CairoCustomEnum; } export interface InterestRateConfig { diff --git a/scripts/verifyPool.ts b/scripts/verifyPool.ts new file mode 100644 index 0000000..d915bc2 --- /dev/null +++ b/scripts/verifyPool.ts @@ -0,0 +1,103 @@ +import { assert } from "console"; +import { shortString } from "starknet"; +import { setup, toAddress } from "../lib"; + +const deployer = await setup("mainnet"); + +const protocol = await deployer.loadProtocol(); +const { singleton, assets, extensionPO } = protocol; + +const pool = await protocol.loadPool("pool"); + +assert( + toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), + "pragma_oracle-neq", +); +assert(toAddress(await extensionPO.pool_owner(pool.id)) === pool.params.owner.toLowerCase(), "pool_owner-neq"); +assert( + toAddress((await extensionPO.fee_config(pool.id)).fee_recipient) === + pool.params.fee_params.fee_recipient.toLowerCase(), + "fee_recipient-neq", +); +const shutdown_config = await extensionPO.shutdown_config(pool.id); +assert(shutdown_config.recovery_period === pool.params.shutdown_params.recovery_period, "recovery_period-neq"); +assert( + shutdown_config.subscription_period === pool.params.shutdown_params.subscription_period, + "subscription_period-neq", +); + +for (const [index, asset] of assets.entries()) { + const oracle_config = await extensionPO.oracle_config(pool.id, asset.address); + assert( + shortString.decodeShortString(oracle_config.pragma_key) === pool.params.pragma_oracle_params[index].pragma_key, + "pragma_key-neq", + ); + assert(oracle_config.timeout === pool.params.pragma_oracle_params[index].timeout, "timeout-neq"); + assert( + oracle_config.number_of_sources === pool.params.pragma_oracle_params[index].number_of_sources, + "number_of_sources-neq", + ); + assert( + oracle_config.start_time_offset === pool.params.pragma_oracle_params[index].start_time_offset, + "start_time_offset-neq", + ); + assert(oracle_config.time_window === pool.params.pragma_oracle_params[index].time_window, "time_window-neq"); + assert( + JSON.stringify(oracle_config.aggregation_mode) === + JSON.stringify(pool.params.pragma_oracle_params[index].aggregation_mode), + "aggregation_mode-neq", + ); + + const interest_rate_config = await extensionPO.interest_rate_config(pool.id, asset.address); + assert( + interest_rate_config.min_target_utilization === pool.params.interest_rate_configs[index].min_target_utilization, + "min_target_utilization-neq", + ); + assert( + interest_rate_config.max_target_utilization === pool.params.interest_rate_configs[index].max_target_utilization, + "max_target_utilization-neq", + ); + assert( + interest_rate_config.target_utilization === pool.params.interest_rate_configs[index].target_utilization, + "target_utilization-neq", + ); + assert( + interest_rate_config.min_full_utilization_rate === + pool.params.interest_rate_configs[index].min_full_utilization_rate, + "min_full_utilization_rate-neq", + ); + assert( + interest_rate_config.max_full_utilization_rate === + pool.params.interest_rate_configs[index].max_full_utilization_rate, + "max_full_utilization_rate-neq", + ); + assert( + interest_rate_config.zero_utilization_rate === pool.params.interest_rate_configs[index].zero_utilization_rate, + "zero_utilization_rate-neq", + ); + assert( + interest_rate_config.rate_half_life === pool.params.interest_rate_configs[index].rate_half_life, + "rate_half_life-neq", + ); + assert( + interest_rate_config.target_rate_percent === pool.params.interest_rate_configs[index].target_rate_percent, + "target_rate_percent-neq", + ); + + const { "0": asset_config } = await singleton.asset_config_unsafe(pool.id, asset.address); + assert(asset_config.total_collateral_shares >= 0n, "total_collateral_shares-neq"); + assert(asset_config.total_nominal_debt >= 0n, "total_nominal_debt-neq"); + assert(asset_config.reserve >= 0n, "reserve-neq"); + assert(asset_config.max_utilization === pool.params.asset_params[index].max_utilization, "max_utilization-neq"); + assert(asset_config.floor === pool.params.asset_params[index].floor, "floor-neq"); + assert(asset_config.scale > 0n, "scale-neq"); + assert(asset_config.is_legacy === false, "is_legacy-neq"); + assert(asset_config.last_updated > 0n, "last_updated-neq"); + assert(asset_config.last_rate_accumulator > 0n, "last_rate_accumulator-neq"); + assert(asset_config.last_full_utilization_rate > 0n, "last_full_utilization_rate-neq"); + assert(asset_config.fee_rate === pool.params.asset_params[index].fee_rate, "fee_rate-neq"); + + assert((await extensionPO.price(pool.id, asset.address)).value > 0n, "price-neq"); + assert((await singleton.rate_accumulator_unsafe(pool.id, asset.address)) > 0n, "rate_accumulator-neq"); + assert((await singleton.utilization_unsafe(pool.id, asset.address)) >= 0n, "utilization-neq"); +} From 5136122db77669008fd17c9dd590d17aa164a7d3 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:53:52 +0000 Subject: [PATCH 27/32] Update scripts --- Scarb.toml | 3 ++- gas-report.txt | 4 ++-- lib/config.mainnet.ts | 10 +++++++++- package.json | 2 +- scripts/verifyPool.ts | 8 ++++---- yarn.lock | 4 ++-- 6 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Scarb.toml b/Scarb.toml index 0422764..9d26602 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -39,6 +39,7 @@ deployMainnet = "scarb --profile release build && node --loader ts-node/esm ./sc deploySepolia = "scarb --profile release build && node --loader ts-node/esm ./scripts/deploySepolia.ts" deployTimelock = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployTimelock.ts" deployExtensions = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployExtensions.ts" +verifyPool = "scarb --profile release build && node --loader ts-node/esm ./scripts/verifyPool.ts" checkGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --check" updateGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --write" -test = "snforge test --max-n-steps 10000000" +test = "snforge test --max-n-steps 10000000" \ No newline at end of file diff --git a/gas-report.txt b/gas-report.txt index 8962929..a3d5b72 100644 --- a/gas-report.txt +++ b/gas-report.txt @@ -4,7 +4,7 @@ Summary: ├─────────────┼─────────────────────────┼─────────┼────────────────┼────────────────┼─────────────────┼───────────┼──────────────┼──────────────────────────────┼───────────────┼──────────────────┼─────────┤ │ Create pool │ '1.914.464.000.000.000' │ 7.6578 │ 58464000000000 │ 1624 │ 1544 │ 310 │ 80 │ 'range_check' │ 273 │ 1856000000000000 │ 'BLOB' │ │ Lend │ '106.412.000.000.000' │ 0.4256 │ 16812000000000 │ 467 │ 465 │ 12 │ 2 │ 'range_check' │ 11 │ 89600000000000 │ 'BLOB' │ -│ Transfer │ '102.720.000.000.000' │ 0.4108 │ 25920000000000 │ 720 │ 718 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ +│ Transfer │ '102.900.000.000.000' │ 0.4116 │ 26100000000000 │ 725 │ 723 │ 4 │ 2 │ 'range_check' │ 9 │ 76800000000000 │ 'BLOB' │ │ Borrow │ '141.220.000.000.000' │ 0.5648 │ 19620000000000 │ 545 │ 543 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ │ Liquidate │ '143.668.000.000.000' │ 0.5746 │ 22068000000000 │ 613 │ 611 │ 13 │ 2 │ 'range_check' │ 15 │ 121600000000000 │ 'BLOB' │ └─────────────┴─────────────────────────┴─────────┴────────────────┴────────────────┴─────────────────┴───────────┴──────────────┴──────────────────────────────┴───────────────┴──────────────────┴─────────┘ @@ -14,7 +14,7 @@ Resources: ├─────────────┼─────────┼───────┼───────┼────────┼──────────┼──────────┼─────────────┼────────┤ │ Create pool │ 138 │ 3 │ 0 │ 0 │ 1772 │ 1 │ 38582 │ 580349 │ │ Lend │ 26 │ 3 │ 0 │ 0 │ 130 │ 0 │ 11619 │ 97475 │ -│ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 17926 │ 144801 │ +│ Transfer │ 41 │ 3 │ 0 │ 0 │ 208 │ 0 │ 18061 │ 143356 │ │ Borrow │ 33 │ 3 │ 0 │ 0 │ 143 │ 0 │ 13568 │ 110481 │ │ Liquidate │ 33 │ 3 │ 0 │ 0 │ 175 │ 0 │ 15268 │ 119184 │ └─────────────┴─────────┴───────┴───────┴────────┴──────────┴──────────┴─────────────┴────────┘ diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index fa89391..d9af6a3 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -1,5 +1,7 @@ import { CairoCustomEnum } from "starknet"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; +// import CONFIG from "vesu_changelog/configurations/config_re7_xstrk_sn_main.json" assert { type: "json" }; +// import CONFIG from "vesu_changelog/configurations/config_re7_sstrk_sn_main.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; import DEPLOYMENT from "vesu_changelog/deployments/deployment_sn_main.json" assert { type: "json" }; @@ -36,6 +38,9 @@ export const config: Config = { pools: { "genesis-pool": { id: 1n, + // id: 3592370751539490711610556844458488648008775713878064059760995781404350938653n, // USDC + // id: 2345856225134458665876812536882617294246962319062565703131100435311373119841n, // xSTRK + // id: 1301140954640322725373945719229815062445705809076381949099585786202465661889n, // sSTRK description: "", type: "", params: { @@ -78,7 +83,10 @@ export const config: Config = { number_of_sources: BigInt(asset.pragma.number_of_sources), start_time_offset: BigInt(asset.pragma.start_time_offset), time_window: BigInt(asset.pragma.time_window), - aggregation_mode: new CairoCustomEnum({ Median: {}, Mean: undefined, Error: undefined }), + aggregation_mode: + (asset.pragma.aggregation_mode == "median" || asset.pragma.aggregation_mode == "Median") + ? new CairoCustomEnum({ Median: {}, Mean: undefined, Error: undefined }) + : new CairoCustomEnum({ Median: undefined, Mean: {}, Error: undefined }), })), liquidation_params: CONFIG.pair_parameters.map((pair: any) => { const collateral_asset_index = CONFIG.asset_parameters.findIndex( diff --git a/package.json b/package.json index 0f23cc2..b7b5fad 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@types/lodash-es": "^4.17.12", "@types/node": "^20.10.5", "bignumber.js": "9.1.2", - "vesu_changelog": "https://github.com/vesuxyz/changelog.git#74cb1d1ace529f861dd8b1a6644f90eea49e9dcc", + "vesu_changelog": "https://github.com/vesuxyz/changelog.git#9a91cce7ed3adfee6fd5a9580e4005303a67b57a", "dotenv": "^16.3.1", "lodash-es": "^4.17.21", "prettier": "^3.1.1", diff --git a/scripts/verifyPool.ts b/scripts/verifyPool.ts index d915bc2..bce37e2 100644 --- a/scripts/verifyPool.ts +++ b/scripts/verifyPool.ts @@ -7,16 +7,16 @@ const deployer = await setup("mainnet"); const protocol = await deployer.loadProtocol(); const { singleton, assets, extensionPO } = protocol; -const pool = await protocol.loadPool("pool"); +const pool = await protocol.loadPool("genesis-pool"); assert( toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), "pragma_oracle-neq", ); -assert(toAddress(await extensionPO.pool_owner(pool.id)) === pool.params.owner.toLowerCase(), "pool_owner-neq"); +assert(await extensionPO.pool_owner(pool.id) === BigInt(pool.params.owner.toLowerCase()), "pool_owner-neq"); assert( - toAddress((await extensionPO.fee_config(pool.id)).fee_recipient) === - pool.params.fee_params.fee_recipient.toLowerCase(), + (await extensionPO.fee_config(pool.id)).fee_recipient === + BigInt(pool.params.fee_params.fee_recipient.toLowerCase()), "fee_recipient-neq", ); const shutdown_config = await extensionPO.shutdown_config(pool.id); diff --git a/yarn.lock b/yarn.lock index de83122..6f233a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -429,9 +429,9 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -"vesu_changelog@https://github.com/vesuxyz/changelog.git#74cb1d1ace529f861dd8b1a6644f90eea49e9dcc": +"vesu_changelog@https://github.com/vesuxyz/changelog.git#9a91cce7ed3adfee6fd5a9580e4005303a67b57a": version "0.0.0" - resolved "https://github.com/vesuxyz/changelog.git#74cb1d1ace529f861dd8b1a6644f90eea49e9dcc" + resolved "https://github.com/vesuxyz/changelog.git#9a91cce7ed3adfee6fd5a9580e4005303a67b57a" webidl-conversions@^3.0.0: version "3.0.1" From c2bea1ec964ca32522ea2a9c42024c083dc988af Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:24:16 +0000 Subject: [PATCH 28/32] Update scripts --- lib/config.mainnet.ts | 10 ++++++---- package.json | 2 +- scripts/verifyPool.ts | 30 ++++++++++++++++++++++++++++++ yarn.lock | 4 ++-- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index d9af6a3..18cb96e 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -1,5 +1,6 @@ import { CairoCustomEnum } from "starknet"; import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" assert { type: "json" }; +// import CONFIG from "vesu_changelog/configurations/config_re7_usdc_sn_main.json" assert { type: "json" }; // import CONFIG from "vesu_changelog/configurations/config_re7_xstrk_sn_main.json" assert { type: "json" }; // import CONFIG from "vesu_changelog/configurations/config_re7_sstrk_sn_main.json" assert { type: "json" }; import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; @@ -38,9 +39,10 @@ export const config: Config = { pools: { "genesis-pool": { id: 1n, - // id: 3592370751539490711610556844458488648008775713878064059760995781404350938653n, // USDC - // id: 2345856225134458665876812536882617294246962319062565703131100435311373119841n, // xSTRK - // id: 1301140954640322725373945719229815062445705809076381949099585786202465661889n, // sSTRK + // id: 2198503327643286920898110335698706244522220458610657370981979460625005526824n, // Genesis Pool + // id: 3592370751539490711610556844458488648008775713878064059760995781404350938653n, // Re7 USDC + // id: 2345856225134458665876812536882617294246962319062565703131100435311373119841n, // Re7 xSTRK + // id: 1301140954640322725373945719229815062445705809076381949099585786202465661889n, // Re7 sSTRK description: "", type: "", params: { @@ -116,7 +118,7 @@ export const config: Config = { const debt_asset_index = CONFIG.asset_parameters.findIndex( (asset: any) => asset.asset_name === pair.debt_asset_name, ); - return { collateral_asset_index, debt_asset_index, max_ltv: 90n * PERCENT }; + return { collateral_asset_index, debt_asset_index, max_ltv: toScale(pair.shutdown_ltv) }; }), }, fee_params: { fee_recipient: CONFIG.pool_parameters.fee_recipient }, diff --git a/package.json b/package.json index b7b5fad..ee4a1d2 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@types/lodash-es": "^4.17.12", "@types/node": "^20.10.5", "bignumber.js": "9.1.2", - "vesu_changelog": "https://github.com/vesuxyz/changelog.git#9a91cce7ed3adfee6fd5a9580e4005303a67b57a", + "vesu_changelog": "https://github.com/vesuxyz/changelog.git#8993a2b5f2624201776535f99b5a7b7e00bef2f0", "dotenv": "^16.3.1", "lodash-es": "^4.17.21", "prettier": "^3.1.1", diff --git a/scripts/verifyPool.ts b/scripts/verifyPool.ts index bce37e2..d883118 100644 --- a/scripts/verifyPool.ts +++ b/scripts/verifyPool.ts @@ -101,3 +101,33 @@ for (const [index, asset] of assets.entries()) { assert((await singleton.rate_accumulator_unsafe(pool.id, asset.address)) > 0n, "rate_accumulator-neq"); assert((await singleton.utilization_unsafe(pool.id, asset.address)) >= 0n, "utilization-neq"); } + +for (const [, asset] of pool.params.ltv_params.entries()) { + let collateral_asset = assets[asset.collateral_asset_index]; + let debt_asset = assets[asset.debt_asset_index]; + let ltv_config = await singleton.ltv_config(pool.id, collateral_asset.address, debt_asset.address); + assert(ltv_config.max_ltv === asset.max_ltv, "max_ltv-neq"); +} + +for (const [, asset] of pool.params.liquidation_params.entries()) { + let collateral_asset = assets[asset.collateral_asset_index]; + let debt_asset = assets[asset.debt_asset_index]; + let liquidation_config = await extensionPO.liquidation_config(pool.id, collateral_asset.address, debt_asset.address); + assert(liquidation_config.liquidation_factor === asset.liquidation_factor, "liquidation_factor-neq"); +} + +for (const [, asset] of pool.params.debt_caps_params.entries()) { + let collateral_asset = assets[asset.collateral_asset_index]; + let debt_asset = assets[asset.debt_asset_index]; + assert( + (await extensionPO.debt_caps(pool.id, collateral_asset.address, debt_asset.address)) === asset.debt_cap, + "debt_cap-neq", + ); +} + +for (const [, asset] of pool.params.shutdown_params.ltv_params.entries()) { + let collateral_asset = assets[asset.collateral_asset_index]; + let debt_asset = assets[asset.debt_asset_index]; + let ltv_config = await extensionPO.shutdown_ltv_config(pool.id, collateral_asset.address, debt_asset.address); + assert(ltv_config.max_ltv === asset.max_ltv, "shutdown_max_ltv-neq"); +} diff --git a/yarn.lock b/yarn.lock index 6f233a1..98e48ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -429,9 +429,9 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -"vesu_changelog@https://github.com/vesuxyz/changelog.git#9a91cce7ed3adfee6fd5a9580e4005303a67b57a": +"vesu_changelog@https://github.com/vesuxyz/changelog.git#8993a2b5f2624201776535f99b5a7b7e00bef2f0": version "0.0.0" - resolved "https://github.com/vesuxyz/changelog.git#9a91cce7ed3adfee6fd5a9580e4005303a67b57a" + resolved "https://github.com/vesuxyz/changelog.git#8993a2b5f2624201776535f99b5a7b7e00bef2f0" webidl-conversions@^3.0.0: version "3.0.1" From 4db83c19552483f3b47c59cf9ff42a60bd023990 Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Mon, 9 Dec 2024 17:48:44 +0000 Subject: [PATCH 29/32] Add integration tests --- Scarb.toml | 2 +- package.json | 2 +- src/lib.cairo | 1 + src/test/test_integration.cairo | 501 ++++++++++++++++++++++++++++++++ src/test/test_user.cairo | 83 ++++-- yarn.lock | 4 +- 6 files changed, 559 insertions(+), 34 deletions(-) create mode 100644 src/test/test_integration.cairo diff --git a/Scarb.toml b/Scarb.toml index 9d26602..e4a12f3 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -42,4 +42,4 @@ deployExtensions = "scarb --profile release build && node --loader ts-node/esm . verifyPool = "scarb --profile release build && node --loader ts-node/esm ./scripts/verifyPool.ts" checkGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --check" updateGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --write" -test = "snforge test --max-n-steps 10000000" \ No newline at end of file +test = "snforge test --max-n-steps 100000000" \ No newline at end of file diff --git a/package.json b/package.json index ee4a1d2..5475052 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "@types/lodash-es": "^4.17.12", "@types/node": "^20.10.5", "bignumber.js": "9.1.2", - "vesu_changelog": "https://github.com/vesuxyz/changelog.git#8993a2b5f2624201776535f99b5a7b7e00bef2f0", + "vesu_changelog": "https://github.com/vesuxyz/changelog.git#2c0a107453dc35dbe90a76094d8560f5f7a1b39e", "dotenv": "^16.3.1", "lodash-es": "^4.17.21", "prettier": "^3.1.1", diff --git a/src/lib.cairo b/src/lib.cairo index 0a53233..9aae9a9 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -44,6 +44,7 @@ mod test { mod test_default_extension_po; mod test_flash_loan; mod test_forking; + mod test_integration; mod test_interest_rate_model; mod test_liquidate_position; mod test_map_list; diff --git a/src/test/test_integration.cairo b/src/test/test_integration.cairo new file mode 100644 index 0000000..fe9a61b --- /dev/null +++ b/src/test/test_integration.cairo @@ -0,0 +1,501 @@ +// #[cfg(test)] +// mod TestIntegration { +// use snforge_std::{ +// start_prank, stop_prank, CheatTarget, store, load, map_entry_address, declare, start_warp, prank, CheatSpan, +// replace_bytecode, get_class_hash +// }; +// use starknet::{ContractAddress, contract_address_const, get_contract_address, get_block_timestamp}; +// use vesu::{ +// singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, +// extension::default_extension_po::{IDefaultExtensionDispatcher, IDefaultExtensionDispatcherTrait}, +// data_model::{Amount, AmountType, AmountDenomination, ModifyPositionParams}, units::SCALE, +// test::test_forking::{IStarkgateERC20Dispatcher, IStarkgateERC20DispatcherTrait}, +// vendor::erc20::{ERC20ABIDispatcher, ERC20ABIDispatcherTrait} +// }; + +// fn setup(pool_id: felt252) -> (ISingletonDispatcher, IDefaultExtensionDispatcher) { +// let singleton = ISingletonDispatcher { +// contract_address: contract_address_const::< +// 0x2545b2e5d519fc230e9cd781046d3a64e092114f07e44771e0d719d148725ef +// >() +// }; + +// // replace_bytecode(singleton.contract_address, declare("Singleton").class_hash); + +// let extension = IDefaultExtensionDispatcher { contract_address: singleton.extension(pool_id) }; + +// // replace_bytecode(extension.contract_address, declare("DefaultExtensionPO").class_hash); + +// (singleton, extension) +// } + +// fn setup_starkgate_erc20(token: ContractAddress, recipient: ContractAddress, amount: u256) -> ERC20ABIDispatcher { +// let erc20 = ERC20ABIDispatcher { contract_address: token }; +// let loaded = load(token, selector!("permitted_minter"), 1); +// let minter: ContractAddress = (*loaded[0]).try_into().unwrap(); +// if (amount != 0) { +// start_prank(CheatTarget::One(token), minter); +// IStarkgateERC20Dispatcher { contract_address: token }.permissioned_mint(recipient, amount); +// stop_prank(CheatTarget::One(token)); +// } +// erc20 +// } + +// fn supply( +// singleton: ISingletonDispatcher, +// pool_id: felt252, +// collateral_asset: ERC20ABIDispatcher, +// debt_asset: ERC20ABIDispatcher, +// user: ContractAddress, +// amount: u256 +// ) { +// let params = ModifyPositionParams { +// pool_id, +// collateral_asset: collateral_asset.contract_address, +// debt_asset: debt_asset.contract_address, +// user, +// collateral: Amount { +// amount_type: AmountType::Delta, denomination: AmountDenomination::Assets, value: amount.into() +// }, +// debt: Default::default(), +// data: ArrayTrait::new().span() +// }; + +// start_prank(CheatTarget::One(collateral_asset.contract_address), user); +// collateral_asset.approve(singleton.contract_address, amount); +// stop_prank(CheatTarget::One(collateral_asset.contract_address)); + +// start_prank(CheatTarget::One(singleton.contract_address), user); +// singleton.modify_position(params); +// stop_prank(CheatTarget::One(singleton.contract_address)); +// } + +// fn borrow( +// singleton: ISingletonDispatcher, +// pool_id: felt252, +// collateral_asset: ERC20ABIDispatcher, +// debt_asset: ERC20ABIDispatcher, +// user: ContractAddress, +// amount: u256 +// ) { +// let params = ModifyPositionParams { +// pool_id, +// collateral_asset: collateral_asset.contract_address, +// debt_asset: debt_asset.contract_address, +// user, +// collateral: Default::default(), +// debt: Amount { +// amount_type: AmountType::Delta, denomination: AmountDenomination::Assets, value: amount.into() +// }, +// data: ArrayTrait::new().span() +// }; + +// start_prank(CheatTarget::One(singleton.contract_address), user); +// singleton.modify_position(params); +// stop_prank(CheatTarget::One(singleton.contract_address)); +// } + +// fn repay( +// singleton: ISingletonDispatcher, +// pool_id: felt252, +// collateral_asset: ERC20ABIDispatcher, +// debt_asset: ERC20ABIDispatcher, +// user: ContractAddress +// ) { +// let params = ModifyPositionParams { +// pool_id, +// collateral_asset: collateral_asset.contract_address, +// debt_asset: debt_asset.contract_address, +// user, +// collateral: Default::default(), +// debt: Amount { amount_type: AmountType::Target, denomination: AmountDenomination::Native, value: 0.into() }, +// data: ArrayTrait::new().span() +// }; + +// let (_, _, debt) = singleton +// .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, user); + +// start_prank(CheatTarget::One(debt_asset.contract_address), user); +// debt_asset.approve(singleton.contract_address, debt); +// stop_prank(CheatTarget::One(debt_asset.contract_address)); + +// start_prank(CheatTarget::One(singleton.contract_address), user); +// singleton.modify_position(params); +// stop_prank(CheatTarget::One(singleton.contract_address)); +// } + +// fn withdraw( +// singleton: ISingletonDispatcher, +// pool_id: felt252, +// collateral_asset: ERC20ABIDispatcher, +// debt_asset: ERC20ABIDispatcher, +// user: ContractAddress +// ) { +// let params = ModifyPositionParams { +// pool_id, +// collateral_asset: collateral_asset.contract_address, +// debt_asset: debt_asset.contract_address, +// user, +// collateral: Amount { +// amount_type: AmountType::Target, denomination: AmountDenomination::Native, value: 0.into() +// }, +// debt: Default::default(), +// data: ArrayTrait::new().span() +// }; + +// start_prank(CheatTarget::One(singleton.contract_address), user); +// singleton.modify_position(params); +// stop_prank(CheatTarget::One(singleton.contract_address)); +// } + +// // 957600 +// #[test] +// #[fork("Mainnet")] +// fn test_integration_genesis_pool() { +// let pool_id = 2198503327643286920898110335698706244522220458610657370981979460625005526824; +// let eth = setup_starkgate_erc20( +// contract_address_const::<0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7>(), +// get_contract_address(), +// 1000 * SCALE +// ); +// let wbtc = setup_starkgate_erc20( +// contract_address_const::<0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac>(), +// get_contract_address(), +// 10 * 1_00_000_000 +// ); +// let usdc = setup_starkgate_erc20( +// contract_address_const::<0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8>(), +// get_contract_address(), +// 10000000 * 1_000_000 +// ); +// let usdt = setup_starkgate_erc20( +// contract_address_const::<0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8>(), +// get_contract_address(), +// 10000000 * 1_000_000 +// ); +// let wsteth = setup_starkgate_erc20( +// contract_address_const::<0x042b8f0484674ca266ac5d08e4ac6a3fe65bd3129795def2dca5c34ecc5f96d2>(), +// get_contract_address(), +// 1000 * SCALE +// ); +// let strk = setup_starkgate_erc20( +// contract_address_const::<0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d>(), +// get_contract_address(), +// 10000000 * SCALE +// ); + +// let (singleton, extension) = setup(pool_id); + +// supply(singleton, pool_id, eth, wbtc, get_contract_address(), 100 * SCALE); +// supply(singleton, pool_id, eth, usdc, get_contract_address(), 1 * SCALE); +// supply(singleton, pool_id, eth, usdt, get_contract_address(), 1 * SCALE); +// supply(singleton, pool_id, eth, wsteth, get_contract_address(), 2 * SCALE); +// supply(singleton, pool_id, eth, strk, get_contract_address(), 1 * SCALE); + +// supply(singleton, pool_id, wbtc, eth, get_contract_address(), 1 * 1_00_000_000); +// supply(singleton, pool_id, wbtc, usdc, get_contract_address(), 1 * 1_00_000_000); +// supply(singleton, pool_id, wbtc, usdt, get_contract_address(), 1 * 1_00_000_000); +// supply(singleton, pool_id, wbtc, wsteth, get_contract_address(), 1 * 1_00_000_000); +// supply(singleton, pool_id, wbtc, strk, get_contract_address(), 1 * 1_00_000_000); + +// supply(singleton, pool_id, usdc, eth, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdc, wbtc, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdc, usdt, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdc, wsteth, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdc, strk, get_contract_address(), 200000 * 1_000_000); + +// supply(singleton, pool_id, usdt, eth, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdt, wbtc, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdt, usdc, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdt, wsteth, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdt, strk, get_contract_address(), 200000 * 1_000_000); + +// supply(singleton, pool_id, wsteth, eth, get_contract_address(), 2 * SCALE); +// supply(singleton, pool_id, wsteth, wbtc, get_contract_address(), 100 * SCALE); +// supply(singleton, pool_id, wsteth, usdc, get_contract_address(), 1 * SCALE); +// supply(singleton, pool_id, wsteth, usdt, get_contract_address(), 1 * SCALE); +// supply(singleton, pool_id, wsteth, strk, get_contract_address(), 1 * SCALE); + +// supply(singleton, pool_id, strk, eth, get_contract_address(), 10000 * SCALE); +// supply(singleton, pool_id, strk, wbtc, get_contract_address(), 1000000 * SCALE); +// supply(singleton, pool_id, strk, usdc, get_contract_address(), 1000 * SCALE); +// supply(singleton, pool_id, strk, usdt, get_contract_address(), 1000 * SCALE); +// supply(singleton, pool_id, strk, wsteth, get_contract_address(), 10000 * SCALE); + +// borrow(singleton, pool_id, eth, wbtc, get_contract_address(), 1 * 1_00_000_000); +// borrow(singleton, pool_id, eth, usdc, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, eth, usdt, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, eth, wsteth, get_contract_address(), 1 * SCALE); +// borrow(singleton, pool_id, eth, strk, get_contract_address(), 500 * SCALE); + +// borrow(singleton, pool_id, wbtc, eth, get_contract_address(), 10 * SCALE); +// borrow(singleton, pool_id, wbtc, usdc, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, wbtc, usdt, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, wbtc, wsteth, get_contract_address(), 10 * SCALE); +// borrow(singleton, pool_id, wbtc, strk, get_contract_address(), 500 * SCALE); + +// borrow(singleton, pool_id, usdc, eth, get_contract_address(), 10 * SCALE); +// borrow(singleton, pool_id, usdc, wbtc, get_contract_address(), 1 * 1_00_000_000); +// borrow(singleton, pool_id, usdc, usdt, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, usdc, wsteth, get_contract_address(), 10 * SCALE); +// borrow(singleton, pool_id, usdc, strk, get_contract_address(), 500 * SCALE); + +// borrow(singleton, pool_id, usdt, eth, get_contract_address(), 10 * SCALE); +// borrow(singleton, pool_id, usdt, wbtc, get_contract_address(), 1 * 1_00_000_000); +// borrow(singleton, pool_id, usdt, usdc, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, usdt, wsteth, get_contract_address(), 10 * SCALE); +// borrow(singleton, pool_id, usdt, strk, get_contract_address(), 500 * SCALE); + +// borrow(singleton, pool_id, wsteth, eth, get_contract_address(), 1 * SCALE); +// borrow(singleton, pool_id, wsteth, wbtc, get_contract_address(), 1 * 1_00_000_000); +// borrow(singleton, pool_id, wsteth, usdc, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, wsteth, usdt, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, wsteth, strk, get_contract_address(), 500 * SCALE); + +// borrow(singleton, pool_id, strk, eth, get_contract_address(), 1 * SCALE); +// borrow(singleton, pool_id, strk, wbtc, get_contract_address(), 1 * 1_00_000_000); +// borrow(singleton, pool_id, strk, usdc, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, strk, usdt, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, strk, wsteth, get_contract_address(), 1 * SCALE); + +// start_prank(CheatTarget::One(extension.contract_address), extension.pool_owner(pool_id)); +// extension.set_oracle_parameter(pool_id, eth.contract_address, 'timeout', 0); +// extension.set_oracle_parameter(pool_id, wbtc.contract_address, 'timeout', 0); +// extension.set_oracle_parameter(pool_id, usdc.contract_address, 'timeout', 0); +// extension.set_oracle_parameter(pool_id, usdt.contract_address, 'timeout', 0); +// extension.set_oracle_parameter(pool_id, wsteth.contract_address, 'timeout', 0); +// extension.set_oracle_parameter(pool_id, strk.contract_address, 'timeout', 0); +// stop_prank(CheatTarget::One(extension.contract_address)); + +// // warp +// start_warp(CheatTarget::All, get_block_timestamp() + 94608000); + +// repay(singleton, pool_id, eth, wbtc, get_contract_address()); +// repay(singleton, pool_id, eth, usdc, get_contract_address()); +// repay(singleton, pool_id, eth, usdt, get_contract_address()); +// repay(singleton, pool_id, eth, wsteth, get_contract_address()); +// repay(singleton, pool_id, eth, strk, get_contract_address()); + +// repay(singleton, pool_id, wbtc, eth, get_contract_address()); +// repay(singleton, pool_id, wbtc, usdc, get_contract_address()); +// repay(singleton, pool_id, wbtc, usdt, get_contract_address()); +// repay(singleton, pool_id, wbtc, wsteth, get_contract_address()); +// repay(singleton, pool_id, wbtc, strk, get_contract_address()); + +// repay(singleton, pool_id, usdc, eth, get_contract_address()); +// repay(singleton, pool_id, usdc, wbtc, get_contract_address()); +// repay(singleton, pool_id, usdc, usdt, get_contract_address()); +// repay(singleton, pool_id, usdc, wsteth, get_contract_address()); +// repay(singleton, pool_id, usdc, strk, get_contract_address()); + +// repay(singleton, pool_id, usdt, eth, get_contract_address()); +// repay(singleton, pool_id, usdt, wbtc, get_contract_address()); +// repay(singleton, pool_id, usdt, usdc, get_contract_address()); +// repay(singleton, pool_id, usdt, wsteth, get_contract_address()); +// repay(singleton, pool_id, usdt, strk, get_contract_address()); + +// repay(singleton, pool_id, wsteth, eth, get_contract_address()); +// repay(singleton, pool_id, wsteth, wbtc, get_contract_address()); +// repay(singleton, pool_id, wsteth, usdc, get_contract_address()); +// repay(singleton, pool_id, wsteth, usdt, get_contract_address()); +// repay(singleton, pool_id, wsteth, strk, get_contract_address()); + +// repay(singleton, pool_id, strk, eth, get_contract_address()); +// repay(singleton, pool_id, strk, wbtc, get_contract_address()); +// repay(singleton, pool_id, strk, usdc, get_contract_address()); +// repay(singleton, pool_id, strk, usdt, get_contract_address()); +// repay(singleton, pool_id, strk, wsteth, get_contract_address()); + +// withdraw(singleton, pool_id, eth, wbtc, get_contract_address()); +// withdraw(singleton, pool_id, eth, usdc, get_contract_address()); +// withdraw(singleton, pool_id, eth, usdt, get_contract_address()); +// withdraw(singleton, pool_id, eth, wsteth, get_contract_address()); +// withdraw(singleton, pool_id, eth, strk, get_contract_address()); + +// withdraw(singleton, pool_id, wbtc, eth, get_contract_address()); +// withdraw(singleton, pool_id, wbtc, usdc, get_contract_address()); +// withdraw(singleton, pool_id, wbtc, usdt, get_contract_address()); +// withdraw(singleton, pool_id, wbtc, wsteth, get_contract_address()); +// withdraw(singleton, pool_id, wbtc, strk, get_contract_address()); + +// withdraw(singleton, pool_id, usdc, eth, get_contract_address()); +// withdraw(singleton, pool_id, usdc, wbtc, get_contract_address()); +// withdraw(singleton, pool_id, usdc, usdt, get_contract_address()); +// withdraw(singleton, pool_id, usdc, wsteth, get_contract_address()); +// withdraw(singleton, pool_id, usdc, strk, get_contract_address()); + +// withdraw(singleton, pool_id, usdt, eth, get_contract_address()); +// withdraw(singleton, pool_id, usdt, wbtc, get_contract_address()); +// withdraw(singleton, pool_id, usdt, usdc, get_contract_address()); +// withdraw(singleton, pool_id, usdt, wsteth, get_contract_address()); +// withdraw(singleton, pool_id, usdt, strk, get_contract_address()); + +// withdraw(singleton, pool_id, wsteth, eth, get_contract_address()); +// withdraw(singleton, pool_id, wsteth, wbtc, get_contract_address()); +// withdraw(singleton, pool_id, wsteth, usdc, get_contract_address()); +// withdraw(singleton, pool_id, wsteth, usdt, get_contract_address()); +// withdraw(singleton, pool_id, wsteth, strk, get_contract_address()); + +// withdraw(singleton, pool_id, strk, eth, get_contract_address()); +// withdraw(singleton, pool_id, strk, wbtc, get_contract_address()); +// withdraw(singleton, pool_id, strk, usdc, get_contract_address()); +// withdraw(singleton, pool_id, strk, usdt, get_contract_address()); +// withdraw(singleton, pool_id, strk, wsteth, get_contract_address()); +// } + +// // 968900 +// #[test] +// #[fork("Mainnet")] +// fn test_integration_re7_usdc_pool() { +// let pool_id = 3592370751539490711610556844458488648008775713878064059760995781404350938653; +// let eth = setup_starkgate_erc20( +// contract_address_const::<0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7>(), +// get_contract_address(), +// 1000 * SCALE +// ); +// let wbtc = setup_starkgate_erc20( +// contract_address_const::<0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac>(), +// get_contract_address(), +// 10 * 1_00_000_000 +// ); +// let usdc = setup_starkgate_erc20( +// contract_address_const::<0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8>(), +// get_contract_address(), +// 10000000 * 1_000_000 +// ); +// let wsteth = setup_starkgate_erc20( +// contract_address_const::<0x042b8f0484674ca266ac5d08e4ac6a3fe65bd3129795def2dca5c34ecc5f96d2>(), +// get_contract_address(), +// 1000 * SCALE +// ); +// let strk = setup_starkgate_erc20( +// contract_address_const::<0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d>(), +// get_contract_address(), +// 10000000 * SCALE +// ); + +// let (singleton, _) = setup(pool_id); + +// supply(singleton, pool_id, eth, wbtc, get_contract_address(), 100 * SCALE); +// supply(singleton, pool_id, eth, usdc, get_contract_address(), 1 * SCALE); +// supply(singleton, pool_id, eth, wsteth, get_contract_address(), 2 * SCALE); +// supply(singleton, pool_id, eth, strk, get_contract_address(), 1 * SCALE); + +// supply(singleton, pool_id, wbtc, eth, get_contract_address(), 1 * 1_00_000_000); +// supply(singleton, pool_id, wbtc, usdc, get_contract_address(), 1 * 1_00_000_000); +// supply(singleton, pool_id, wbtc, wsteth, get_contract_address(), 1 * 1_00_000_000); +// supply(singleton, pool_id, wbtc, strk, get_contract_address(), 1 * 1_00_000_000); + +// supply(singleton, pool_id, usdc, eth, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdc, wbtc, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdc, wsteth, get_contract_address(), 200000 * 1_000_000); +// supply(singleton, pool_id, usdc, strk, get_contract_address(), 200000 * 1_000_000); + +// supply(singleton, pool_id, wsteth, eth, get_contract_address(), 2 * SCALE); +// supply(singleton, pool_id, wsteth, wbtc, get_contract_address(), 100 * SCALE); +// supply(singleton, pool_id, wsteth, usdc, get_contract_address(), 1 * SCALE); +// supply(singleton, pool_id, wsteth, strk, get_contract_address(), 1 * SCALE); + +// supply(singleton, pool_id, strk, eth, get_contract_address(), 10000 * SCALE); +// supply(singleton, pool_id, strk, wbtc, get_contract_address(), 1000000 * SCALE); +// supply(singleton, pool_id, strk, usdc, get_contract_address(), 1000 * SCALE); +// supply(singleton, pool_id, strk, wsteth, get_contract_address(), 10000 * SCALE); + +// borrow(singleton, pool_id, eth, usdc, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, wsteth, usdc, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, wbtc, usdc, get_contract_address(), 200 * 1_000_000); +// borrow(singleton, pool_id, strk, usdc, get_contract_address(), 200 * 1_000_000); + +// // warp +// start_warp(CheatTarget::All, get_block_timestamp() + 94608000); + +// repay(singleton, pool_id, eth, usdc, get_contract_address()); +// repay(singleton, pool_id, wsteth, usdc, get_contract_address()); +// repay(singleton, pool_id, wbtc, usdc, get_contract_address()); +// repay(singleton, pool_id, strk, usdc, get_contract_address()); + +// withdraw(singleton, pool_id, eth, usdc, get_contract_address()); +// withdraw(singleton, pool_id, wsteth, usdc, get_contract_address()); +// withdraw(singleton, pool_id, wbtc, usdc, get_contract_address()); +// withdraw(singleton, pool_id, strk, usdc, get_contract_address()); +// } + +// // 968900 +// #[test] +// #[fork("Mainnet")] +// fn test_integration_re7_sstrk_pool() { +// let pool_id = 1301140954640322725373945719229815062445705809076381949099585786202465661889; +// let strk = setup_starkgate_erc20( +// contract_address_const::<0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d>(), +// get_contract_address(), +// 10000000 * SCALE +// ); +// let sstrk = setup_starkgate_erc20( +// contract_address_const::<0x0356f304b154d29d2a8fe22f1cb9107a9b564a733cf6b4cc47fd121ac1af90c9>(), +// get_contract_address(), +// 10000000 * SCALE +// ); + +// let (singleton, extension) = setup(pool_id); + +// start_prank(CheatTarget::One(extension.contract_address), extension.pool_owner(pool_id)); +// extension.set_debt_cap(pool_id, sstrk.contract_address, strk.contract_address, 1000000 * SCALE); +// stop_prank(CheatTarget::One(extension.contract_address)); +// supply(singleton, pool_id, strk, sstrk, get_contract_address(), 100000 * SCALE); +// supply(singleton, pool_id, sstrk, strk, get_contract_address(), 100000 * SCALE); + +// borrow(singleton, pool_id, sstrk, strk, get_contract_address(), 10000 * SCALE); + +// // warp +// start_warp(CheatTarget::All, get_block_timestamp() + 94608000); + +// repay(singleton, pool_id, strk, sstrk, get_contract_address()); +// repay(singleton, pool_id, sstrk, strk, get_contract_address()); + +// withdraw(singleton, pool_id, strk, sstrk, get_contract_address()); +// withdraw(singleton, pool_id, sstrk, strk, get_contract_address()); +// } + +// // 968900 +// #[test] +// #[fork("Mainnet")] +// fn test_integration_re7_xstrk_pool() { +// let pool_id = 2345856225134458665876812536882617294246962319062565703131100435311373119841; +// let strk = setup_starkgate_erc20( +// contract_address_const::<0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d>(), +// get_contract_address(), +// 10000000 * SCALE +// ); +// let xstrk = setup_starkgate_erc20( +// contract_address_const::<0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a>(), +// get_contract_address(), +// 0 +// ); + +// store( +// xstrk.contract_address, +// map_entry_address(selector!("ERC20_balances"), array![get_contract_address().into()].span(),), +// array![(10000000 * SCALE).try_into().unwrap()].span() +// ); + +// let (singleton, extension) = setup(pool_id); + +// start_prank(CheatTarget::One(extension.contract_address), extension.pool_owner(pool_id)); +// extension.set_debt_cap(pool_id, xstrk.contract_address, strk.contract_address, 1000000 * SCALE); +// stop_prank(CheatTarget::One(extension.contract_address)); + +// supply(singleton, pool_id, strk, xstrk, get_contract_address(), 100000 * SCALE); +// supply(singleton, pool_id, xstrk, strk, get_contract_address(), 100000 * SCALE); + +// borrow(singleton, pool_id, xstrk, strk, get_contract_address(), 10000 * SCALE); + +// // warp +// start_warp(CheatTarget::All, get_block_timestamp() + 94608000); + +// repay(singleton, pool_id, strk, xstrk, get_contract_address()); +// repay(singleton, pool_id, xstrk, strk, get_contract_address()); + +// withdraw(singleton, pool_id, strk, xstrk, get_contract_address()); +// withdraw(singleton, pool_id, xstrk, strk, get_contract_address()); +// } +// } diff --git a/src/test/test_user.cairo b/src/test/test_user.cairo index 22f9091..e670eb7 100644 --- a/src/test/test_user.cairo +++ b/src/test/test_user.cairo @@ -14,10 +14,12 @@ fn to_percent(value: u256) -> u64 { mod TestUser { use alexandria_math::i257::{i257, i257_new}; use snforge_std::{ - start_prank, stop_prank, CheatTarget, store, load, map_entry_address, declare, start_warp, replace_bytecode + start_prank, stop_prank, CheatTarget, store, load, map_entry_address, declare, start_warp, replace_bytecode, + get_class_hash }; use starknet::{ - contract_address_const, get_caller_address, get_contract_address, ContractAddress, get_block_timestamp + ClassHash, contract_address_const, get_caller_address, get_contract_address, ContractAddress, + get_block_timestamp }; use super::{IStarkgateERC20Dispatcher, IStarkgateERC20DispatcherTrait, to_percent}; use vesu::{ @@ -42,68 +44,89 @@ mod TestUser { singleton::{ISingletonDispatcher, ISingletonDispatcherTrait, LiquidatePositionParams}, }; + // block number: 952420 #[test] #[available_gas(2000000)] #[fork("Mainnet")] fn test_user() { let singleton = ISingletonDispatcher { contract_address: contract_address_const::< - 0x297ef4c12810695c5d91e28b8ee5c5af430076fa8c40a45d31b48da54de372e + 0x2545b2e5d519fc230e9cd781046d3a64e092114f07e44771e0d719d148725ef >() }; - replace_bytecode(singleton.contract_address, declare("Singleton").class_hash); + replace_bytecode( + singleton.contract_address, // declare("Singleton").class_hash + get_class_hash(singleton.contract_address) + ); let extension = IDefaultExtensionDispatcher { contract_address: contract_address_const::< - 0x1008cf6e9f48c6b23121b340e2e84c5a6df0ab3a46d4886df71bdd6d16fcf69 + 0x2ded44e2c575671dedb6227ba8bfed340252f3cb0476982074567c0670442f7 >() }; - replace_bytecode(extension.contract_address, declare("DefaultExtensionPO").class_hash); + replace_bytecode( + extension.contract_address, + declare("DefaultExtensionPO").class_hash // get_class_hash(extension.contract_address) + ); - let pool_id = 3601893553453722691657585476026095435475878278287859441667450345178654480585; + let pool_id = 3488439889760078773862061392337242708358978534574204613763925972476552399332; let collateral_asset = IERC20Dispatcher { contract_address: contract_address_const::< - 0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8 + 0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7 // eth >() }; let debt_asset = IERC20Dispatcher { contract_address: contract_address_const::< - 0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac + 0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8 // usdc >() }; - let user = contract_address_const::<0x075324D453cF0B57D1242602D349040A6D5E0D8a6b118953afA7C1bf17ba53F8>(); + // let user = contract_address_const::<0x11b6e878cc575025b488b2e7af5f58f9df99b9f9aa03f22f932ae0b69a955f1>(); + let user = contract_address_const::<0x03d92A8137e51eeE44B8Fb450d90f2CdA085B2568562c1B8695cBF11c06f9c8d>(); - let (position, _, _) = singleton - .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, user); + // let (position, _, _) = singleton + // .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, user); + + println!("balance: {}", collateral_asset.balance_of(user)); + + start_prank(CheatTarget::One(collateral_asset.contract_address), user); + collateral_asset.approve(singleton.contract_address, 100 * SCALE); + stop_prank(CheatTarget::One(collateral_asset.contract_address)); start_prank(CheatTarget::One(singleton.contract_address), user); singleton - .transfer_position( - TransferPositionParams { + .modify_position( + ModifyPositionParams { pool_id, - from_collateral_asset: collateral_asset.contract_address, - from_debt_asset: debt_asset.contract_address, - to_collateral_asset: collateral_asset.contract_address, - to_debt_asset: Zeroable::zero(), - from_user: user, - to_user: extension.contract_address, - collateral: UnsignedAmount { + collateral_asset: collateral_asset.contract_address, + debt_asset: debt_asset.contract_address, + user, + collateral: Amount { // 0.04 ETH amount_type: AmountType::Delta, - denomination: AmountDenomination::Native, - value: position.collateral_shares, + denomination: AmountDenomination::Assets, + value: 40000000000000000.into(), }, debt: Default::default(), - from_data: ArrayTrait::new().span(), - to_data: ArrayTrait::new().span(), + data: ArrayTrait::new().span(), + } + ); + singleton + .modify_position( + ModifyPositionParams { + pool_id, + collateral_asset: collateral_asset.contract_address, + debt_asset: debt_asset.contract_address, + user, + collateral: Default::default(), + debt: Amount { // 10 USDC + amount_type: AmountType::Delta, + denomination: AmountDenomination::Assets, + value: 10000000.into(), + }, + data: ArrayTrait::new().span(), } ); stop_prank(CheatTarget::One(singleton.contract_address)); - // let wbtc = contract_address_const::<0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac>(); - - // let collateral_shares = singleton.calculate_collateral_shares( - // pool_id, wbtc, i257_new(270738, false) - // ); } } diff --git a/yarn.lock b/yarn.lock index 98e48ad..e51dccd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -429,9 +429,9 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -"vesu_changelog@https://github.com/vesuxyz/changelog.git#8993a2b5f2624201776535f99b5a7b7e00bef2f0": +"vesu_changelog@https://github.com/vesuxyz/changelog.git#2c0a107453dc35dbe90a76094d8560f5f7a1b39e": version "0.0.0" - resolved "https://github.com/vesuxyz/changelog.git#8993a2b5f2624201776535f99b5a7b7e00bef2f0" + resolved "https://github.com/vesuxyz/changelog.git#2c0a107453dc35dbe90a76094d8560f5f7a1b39e" webidl-conversions@^3.0.0: version "3.0.1" From 78cf26dd88c309a9d267e5968030e927a60cffcb Mon Sep 17 00:00:00 2001 From: vesu-dev <174601598+vesu-dev@users.noreply.github.com> Date: Tue, 10 Dec 2024 13:46:19 +0000 Subject: [PATCH 30/32] Remove Timelock and integration tests --- Scarb.toml | 1 - lib/config.mainnet.ts | 4 +- scripts/deployTimelock.ts | 14 - scripts/verifyPool.ts | 5 +- src/lib.cairo | 4 - src/test/test_integration.cairo | 501 -------------------------------- src/test/test_user.cairo | 132 --------- src/test/timelock_test.cairo | 247 ---------------- src/vendor/timelock.cairo | 313 -------------------- 9 files changed, 4 insertions(+), 1217 deletions(-) delete mode 100644 scripts/deployTimelock.ts delete mode 100644 src/test/test_integration.cairo delete mode 100644 src/test/test_user.cairo delete mode 100644 src/test/timelock_test.cairo delete mode 100644 src/vendor/timelock.cairo diff --git a/Scarb.toml b/Scarb.toml index e4a12f3..ed09fa4 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -37,7 +37,6 @@ createPosition = "scarb --profile release build && node --loader ts-node/esm ./s deployDevnet = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployDevnet.ts" deployMainnet = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployMainnet.ts" deploySepolia = "scarb --profile release build && node --loader ts-node/esm ./scripts/deploySepolia.ts" -deployTimelock = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployTimelock.ts" deployExtensions = "scarb --profile release build && node --loader ts-node/esm ./scripts/deployExtensions.ts" verifyPool = "scarb --profile release build && node --loader ts-node/esm ./scripts/verifyPool.ts" checkGasReport = "scarb --profile release build && node --loader ts-node/esm ./scripts/gasReport.ts --check" diff --git a/lib/config.mainnet.ts b/lib/config.mainnet.ts index 18cb96e..85b51d3 100644 --- a/lib/config.mainnet.ts +++ b/lib/config.mainnet.ts @@ -3,7 +3,7 @@ import CONFIG from "vesu_changelog/configurations/config_genesis_sn_main.json" a // import CONFIG from "vesu_changelog/configurations/config_re7_usdc_sn_main.json" assert { type: "json" }; // import CONFIG from "vesu_changelog/configurations/config_re7_xstrk_sn_main.json" assert { type: "json" }; // import CONFIG from "vesu_changelog/configurations/config_re7_sstrk_sn_main.json" assert { type: "json" }; -import { Config, EnvAssetParams, PERCENT, SCALE, toScale, toUtilizationScale } from "."; +import { Config, EnvAssetParams, SCALE, toScale, toUtilizationScale } from "."; import DEPLOYMENT from "vesu_changelog/deployments/deployment_sn_main.json" assert { type: "json" }; @@ -86,7 +86,7 @@ export const config: Config = { start_time_offset: BigInt(asset.pragma.start_time_offset), time_window: BigInt(asset.pragma.time_window), aggregation_mode: - (asset.pragma.aggregation_mode == "median" || asset.pragma.aggregation_mode == "Median") + asset.pragma.aggregation_mode == "median" || asset.pragma.aggregation_mode == "Median" ? new CairoCustomEnum({ Median: {}, Mean: undefined, Error: undefined }) : new CairoCustomEnum({ Median: undefined, Mean: {}, Error: undefined }), })), diff --git a/scripts/deployTimelock.ts b/scripts/deployTimelock.ts deleted file mode 100644 index c213aad..0000000 --- a/scripts/deployTimelock.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { CallData } from "starknet"; -import { setup } from "../lib"; - -const deployer = await setup(process.env.NETWORK); - -const [timelock, calls] = await deployer.deferContract( - "Timelock", - CallData.compile({ owner: deployer.creator.address, config: { delay: 604800, window: 604800 } }), -); - -let response = await deployer.execute([...calls]); -await deployer.waitForTransaction(response.transaction_hash); - -console.log("Deployed:", { timelock: timelock.address }); diff --git a/scripts/verifyPool.ts b/scripts/verifyPool.ts index d883118..1bf6cf1 100644 --- a/scripts/verifyPool.ts +++ b/scripts/verifyPool.ts @@ -13,10 +13,9 @@ assert( toAddress(await extensionPO.pragma_oracle()) === protocol.pragma.oracle.address.toLowerCase(), "pragma_oracle-neq", ); -assert(await extensionPO.pool_owner(pool.id) === BigInt(pool.params.owner.toLowerCase()), "pool_owner-neq"); +assert((await extensionPO.pool_owner(pool.id)) === BigInt(pool.params.owner.toLowerCase()), "pool_owner-neq"); assert( - (await extensionPO.fee_config(pool.id)).fee_recipient === - BigInt(pool.params.fee_params.fee_recipient.toLowerCase()), + (await extensionPO.fee_config(pool.id)).fee_recipient === BigInt(pool.params.fee_params.fee_recipient.toLowerCase()), "fee_recipient-neq", ); const shutdown_config = await extensionPO.shutdown_config(pool.id); diff --git a/src/lib.cairo b/src/lib.cairo index 9aae9a9..2ff96ac 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -28,7 +28,6 @@ mod vendor { mod erc20; mod erc20_component; mod pragma; - mod timelock; } mod test { @@ -44,7 +43,6 @@ mod test { mod test_default_extension_po; mod test_flash_loan; mod test_forking; - mod test_integration; mod test_interest_rate_model; mod test_liquidate_position; mod test_map_list; @@ -57,7 +55,5 @@ mod test { mod test_shutdown; mod test_singleton; mod test_transfer_position; - mod test_user; mod test_v_token; - mod timelock_test; } diff --git a/src/test/test_integration.cairo b/src/test/test_integration.cairo deleted file mode 100644 index fe9a61b..0000000 --- a/src/test/test_integration.cairo +++ /dev/null @@ -1,501 +0,0 @@ -// #[cfg(test)] -// mod TestIntegration { -// use snforge_std::{ -// start_prank, stop_prank, CheatTarget, store, load, map_entry_address, declare, start_warp, prank, CheatSpan, -// replace_bytecode, get_class_hash -// }; -// use starknet::{ContractAddress, contract_address_const, get_contract_address, get_block_timestamp}; -// use vesu::{ -// singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, -// extension::default_extension_po::{IDefaultExtensionDispatcher, IDefaultExtensionDispatcherTrait}, -// data_model::{Amount, AmountType, AmountDenomination, ModifyPositionParams}, units::SCALE, -// test::test_forking::{IStarkgateERC20Dispatcher, IStarkgateERC20DispatcherTrait}, -// vendor::erc20::{ERC20ABIDispatcher, ERC20ABIDispatcherTrait} -// }; - -// fn setup(pool_id: felt252) -> (ISingletonDispatcher, IDefaultExtensionDispatcher) { -// let singleton = ISingletonDispatcher { -// contract_address: contract_address_const::< -// 0x2545b2e5d519fc230e9cd781046d3a64e092114f07e44771e0d719d148725ef -// >() -// }; - -// // replace_bytecode(singleton.contract_address, declare("Singleton").class_hash); - -// let extension = IDefaultExtensionDispatcher { contract_address: singleton.extension(pool_id) }; - -// // replace_bytecode(extension.contract_address, declare("DefaultExtensionPO").class_hash); - -// (singleton, extension) -// } - -// fn setup_starkgate_erc20(token: ContractAddress, recipient: ContractAddress, amount: u256) -> ERC20ABIDispatcher { -// let erc20 = ERC20ABIDispatcher { contract_address: token }; -// let loaded = load(token, selector!("permitted_minter"), 1); -// let minter: ContractAddress = (*loaded[0]).try_into().unwrap(); -// if (amount != 0) { -// start_prank(CheatTarget::One(token), minter); -// IStarkgateERC20Dispatcher { contract_address: token }.permissioned_mint(recipient, amount); -// stop_prank(CheatTarget::One(token)); -// } -// erc20 -// } - -// fn supply( -// singleton: ISingletonDispatcher, -// pool_id: felt252, -// collateral_asset: ERC20ABIDispatcher, -// debt_asset: ERC20ABIDispatcher, -// user: ContractAddress, -// amount: u256 -// ) { -// let params = ModifyPositionParams { -// pool_id, -// collateral_asset: collateral_asset.contract_address, -// debt_asset: debt_asset.contract_address, -// user, -// collateral: Amount { -// amount_type: AmountType::Delta, denomination: AmountDenomination::Assets, value: amount.into() -// }, -// debt: Default::default(), -// data: ArrayTrait::new().span() -// }; - -// start_prank(CheatTarget::One(collateral_asset.contract_address), user); -// collateral_asset.approve(singleton.contract_address, amount); -// stop_prank(CheatTarget::One(collateral_asset.contract_address)); - -// start_prank(CheatTarget::One(singleton.contract_address), user); -// singleton.modify_position(params); -// stop_prank(CheatTarget::One(singleton.contract_address)); -// } - -// fn borrow( -// singleton: ISingletonDispatcher, -// pool_id: felt252, -// collateral_asset: ERC20ABIDispatcher, -// debt_asset: ERC20ABIDispatcher, -// user: ContractAddress, -// amount: u256 -// ) { -// let params = ModifyPositionParams { -// pool_id, -// collateral_asset: collateral_asset.contract_address, -// debt_asset: debt_asset.contract_address, -// user, -// collateral: Default::default(), -// debt: Amount { -// amount_type: AmountType::Delta, denomination: AmountDenomination::Assets, value: amount.into() -// }, -// data: ArrayTrait::new().span() -// }; - -// start_prank(CheatTarget::One(singleton.contract_address), user); -// singleton.modify_position(params); -// stop_prank(CheatTarget::One(singleton.contract_address)); -// } - -// fn repay( -// singleton: ISingletonDispatcher, -// pool_id: felt252, -// collateral_asset: ERC20ABIDispatcher, -// debt_asset: ERC20ABIDispatcher, -// user: ContractAddress -// ) { -// let params = ModifyPositionParams { -// pool_id, -// collateral_asset: collateral_asset.contract_address, -// debt_asset: debt_asset.contract_address, -// user, -// collateral: Default::default(), -// debt: Amount { amount_type: AmountType::Target, denomination: AmountDenomination::Native, value: 0.into() }, -// data: ArrayTrait::new().span() -// }; - -// let (_, _, debt) = singleton -// .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, user); - -// start_prank(CheatTarget::One(debt_asset.contract_address), user); -// debt_asset.approve(singleton.contract_address, debt); -// stop_prank(CheatTarget::One(debt_asset.contract_address)); - -// start_prank(CheatTarget::One(singleton.contract_address), user); -// singleton.modify_position(params); -// stop_prank(CheatTarget::One(singleton.contract_address)); -// } - -// fn withdraw( -// singleton: ISingletonDispatcher, -// pool_id: felt252, -// collateral_asset: ERC20ABIDispatcher, -// debt_asset: ERC20ABIDispatcher, -// user: ContractAddress -// ) { -// let params = ModifyPositionParams { -// pool_id, -// collateral_asset: collateral_asset.contract_address, -// debt_asset: debt_asset.contract_address, -// user, -// collateral: Amount { -// amount_type: AmountType::Target, denomination: AmountDenomination::Native, value: 0.into() -// }, -// debt: Default::default(), -// data: ArrayTrait::new().span() -// }; - -// start_prank(CheatTarget::One(singleton.contract_address), user); -// singleton.modify_position(params); -// stop_prank(CheatTarget::One(singleton.contract_address)); -// } - -// // 957600 -// #[test] -// #[fork("Mainnet")] -// fn test_integration_genesis_pool() { -// let pool_id = 2198503327643286920898110335698706244522220458610657370981979460625005526824; -// let eth = setup_starkgate_erc20( -// contract_address_const::<0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7>(), -// get_contract_address(), -// 1000 * SCALE -// ); -// let wbtc = setup_starkgate_erc20( -// contract_address_const::<0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac>(), -// get_contract_address(), -// 10 * 1_00_000_000 -// ); -// let usdc = setup_starkgate_erc20( -// contract_address_const::<0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8>(), -// get_contract_address(), -// 10000000 * 1_000_000 -// ); -// let usdt = setup_starkgate_erc20( -// contract_address_const::<0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8>(), -// get_contract_address(), -// 10000000 * 1_000_000 -// ); -// let wsteth = setup_starkgate_erc20( -// contract_address_const::<0x042b8f0484674ca266ac5d08e4ac6a3fe65bd3129795def2dca5c34ecc5f96d2>(), -// get_contract_address(), -// 1000 * SCALE -// ); -// let strk = setup_starkgate_erc20( -// contract_address_const::<0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d>(), -// get_contract_address(), -// 10000000 * SCALE -// ); - -// let (singleton, extension) = setup(pool_id); - -// supply(singleton, pool_id, eth, wbtc, get_contract_address(), 100 * SCALE); -// supply(singleton, pool_id, eth, usdc, get_contract_address(), 1 * SCALE); -// supply(singleton, pool_id, eth, usdt, get_contract_address(), 1 * SCALE); -// supply(singleton, pool_id, eth, wsteth, get_contract_address(), 2 * SCALE); -// supply(singleton, pool_id, eth, strk, get_contract_address(), 1 * SCALE); - -// supply(singleton, pool_id, wbtc, eth, get_contract_address(), 1 * 1_00_000_000); -// supply(singleton, pool_id, wbtc, usdc, get_contract_address(), 1 * 1_00_000_000); -// supply(singleton, pool_id, wbtc, usdt, get_contract_address(), 1 * 1_00_000_000); -// supply(singleton, pool_id, wbtc, wsteth, get_contract_address(), 1 * 1_00_000_000); -// supply(singleton, pool_id, wbtc, strk, get_contract_address(), 1 * 1_00_000_000); - -// supply(singleton, pool_id, usdc, eth, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdc, wbtc, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdc, usdt, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdc, wsteth, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdc, strk, get_contract_address(), 200000 * 1_000_000); - -// supply(singleton, pool_id, usdt, eth, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdt, wbtc, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdt, usdc, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdt, wsteth, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdt, strk, get_contract_address(), 200000 * 1_000_000); - -// supply(singleton, pool_id, wsteth, eth, get_contract_address(), 2 * SCALE); -// supply(singleton, pool_id, wsteth, wbtc, get_contract_address(), 100 * SCALE); -// supply(singleton, pool_id, wsteth, usdc, get_contract_address(), 1 * SCALE); -// supply(singleton, pool_id, wsteth, usdt, get_contract_address(), 1 * SCALE); -// supply(singleton, pool_id, wsteth, strk, get_contract_address(), 1 * SCALE); - -// supply(singleton, pool_id, strk, eth, get_contract_address(), 10000 * SCALE); -// supply(singleton, pool_id, strk, wbtc, get_contract_address(), 1000000 * SCALE); -// supply(singleton, pool_id, strk, usdc, get_contract_address(), 1000 * SCALE); -// supply(singleton, pool_id, strk, usdt, get_contract_address(), 1000 * SCALE); -// supply(singleton, pool_id, strk, wsteth, get_contract_address(), 10000 * SCALE); - -// borrow(singleton, pool_id, eth, wbtc, get_contract_address(), 1 * 1_00_000_000); -// borrow(singleton, pool_id, eth, usdc, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, eth, usdt, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, eth, wsteth, get_contract_address(), 1 * SCALE); -// borrow(singleton, pool_id, eth, strk, get_contract_address(), 500 * SCALE); - -// borrow(singleton, pool_id, wbtc, eth, get_contract_address(), 10 * SCALE); -// borrow(singleton, pool_id, wbtc, usdc, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, wbtc, usdt, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, wbtc, wsteth, get_contract_address(), 10 * SCALE); -// borrow(singleton, pool_id, wbtc, strk, get_contract_address(), 500 * SCALE); - -// borrow(singleton, pool_id, usdc, eth, get_contract_address(), 10 * SCALE); -// borrow(singleton, pool_id, usdc, wbtc, get_contract_address(), 1 * 1_00_000_000); -// borrow(singleton, pool_id, usdc, usdt, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, usdc, wsteth, get_contract_address(), 10 * SCALE); -// borrow(singleton, pool_id, usdc, strk, get_contract_address(), 500 * SCALE); - -// borrow(singleton, pool_id, usdt, eth, get_contract_address(), 10 * SCALE); -// borrow(singleton, pool_id, usdt, wbtc, get_contract_address(), 1 * 1_00_000_000); -// borrow(singleton, pool_id, usdt, usdc, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, usdt, wsteth, get_contract_address(), 10 * SCALE); -// borrow(singleton, pool_id, usdt, strk, get_contract_address(), 500 * SCALE); - -// borrow(singleton, pool_id, wsteth, eth, get_contract_address(), 1 * SCALE); -// borrow(singleton, pool_id, wsteth, wbtc, get_contract_address(), 1 * 1_00_000_000); -// borrow(singleton, pool_id, wsteth, usdc, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, wsteth, usdt, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, wsteth, strk, get_contract_address(), 500 * SCALE); - -// borrow(singleton, pool_id, strk, eth, get_contract_address(), 1 * SCALE); -// borrow(singleton, pool_id, strk, wbtc, get_contract_address(), 1 * 1_00_000_000); -// borrow(singleton, pool_id, strk, usdc, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, strk, usdt, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, strk, wsteth, get_contract_address(), 1 * SCALE); - -// start_prank(CheatTarget::One(extension.contract_address), extension.pool_owner(pool_id)); -// extension.set_oracle_parameter(pool_id, eth.contract_address, 'timeout', 0); -// extension.set_oracle_parameter(pool_id, wbtc.contract_address, 'timeout', 0); -// extension.set_oracle_parameter(pool_id, usdc.contract_address, 'timeout', 0); -// extension.set_oracle_parameter(pool_id, usdt.contract_address, 'timeout', 0); -// extension.set_oracle_parameter(pool_id, wsteth.contract_address, 'timeout', 0); -// extension.set_oracle_parameter(pool_id, strk.contract_address, 'timeout', 0); -// stop_prank(CheatTarget::One(extension.contract_address)); - -// // warp -// start_warp(CheatTarget::All, get_block_timestamp() + 94608000); - -// repay(singleton, pool_id, eth, wbtc, get_contract_address()); -// repay(singleton, pool_id, eth, usdc, get_contract_address()); -// repay(singleton, pool_id, eth, usdt, get_contract_address()); -// repay(singleton, pool_id, eth, wsteth, get_contract_address()); -// repay(singleton, pool_id, eth, strk, get_contract_address()); - -// repay(singleton, pool_id, wbtc, eth, get_contract_address()); -// repay(singleton, pool_id, wbtc, usdc, get_contract_address()); -// repay(singleton, pool_id, wbtc, usdt, get_contract_address()); -// repay(singleton, pool_id, wbtc, wsteth, get_contract_address()); -// repay(singleton, pool_id, wbtc, strk, get_contract_address()); - -// repay(singleton, pool_id, usdc, eth, get_contract_address()); -// repay(singleton, pool_id, usdc, wbtc, get_contract_address()); -// repay(singleton, pool_id, usdc, usdt, get_contract_address()); -// repay(singleton, pool_id, usdc, wsteth, get_contract_address()); -// repay(singleton, pool_id, usdc, strk, get_contract_address()); - -// repay(singleton, pool_id, usdt, eth, get_contract_address()); -// repay(singleton, pool_id, usdt, wbtc, get_contract_address()); -// repay(singleton, pool_id, usdt, usdc, get_contract_address()); -// repay(singleton, pool_id, usdt, wsteth, get_contract_address()); -// repay(singleton, pool_id, usdt, strk, get_contract_address()); - -// repay(singleton, pool_id, wsteth, eth, get_contract_address()); -// repay(singleton, pool_id, wsteth, wbtc, get_contract_address()); -// repay(singleton, pool_id, wsteth, usdc, get_contract_address()); -// repay(singleton, pool_id, wsteth, usdt, get_contract_address()); -// repay(singleton, pool_id, wsteth, strk, get_contract_address()); - -// repay(singleton, pool_id, strk, eth, get_contract_address()); -// repay(singleton, pool_id, strk, wbtc, get_contract_address()); -// repay(singleton, pool_id, strk, usdc, get_contract_address()); -// repay(singleton, pool_id, strk, usdt, get_contract_address()); -// repay(singleton, pool_id, strk, wsteth, get_contract_address()); - -// withdraw(singleton, pool_id, eth, wbtc, get_contract_address()); -// withdraw(singleton, pool_id, eth, usdc, get_contract_address()); -// withdraw(singleton, pool_id, eth, usdt, get_contract_address()); -// withdraw(singleton, pool_id, eth, wsteth, get_contract_address()); -// withdraw(singleton, pool_id, eth, strk, get_contract_address()); - -// withdraw(singleton, pool_id, wbtc, eth, get_contract_address()); -// withdraw(singleton, pool_id, wbtc, usdc, get_contract_address()); -// withdraw(singleton, pool_id, wbtc, usdt, get_contract_address()); -// withdraw(singleton, pool_id, wbtc, wsteth, get_contract_address()); -// withdraw(singleton, pool_id, wbtc, strk, get_contract_address()); - -// withdraw(singleton, pool_id, usdc, eth, get_contract_address()); -// withdraw(singleton, pool_id, usdc, wbtc, get_contract_address()); -// withdraw(singleton, pool_id, usdc, usdt, get_contract_address()); -// withdraw(singleton, pool_id, usdc, wsteth, get_contract_address()); -// withdraw(singleton, pool_id, usdc, strk, get_contract_address()); - -// withdraw(singleton, pool_id, usdt, eth, get_contract_address()); -// withdraw(singleton, pool_id, usdt, wbtc, get_contract_address()); -// withdraw(singleton, pool_id, usdt, usdc, get_contract_address()); -// withdraw(singleton, pool_id, usdt, wsteth, get_contract_address()); -// withdraw(singleton, pool_id, usdt, strk, get_contract_address()); - -// withdraw(singleton, pool_id, wsteth, eth, get_contract_address()); -// withdraw(singleton, pool_id, wsteth, wbtc, get_contract_address()); -// withdraw(singleton, pool_id, wsteth, usdc, get_contract_address()); -// withdraw(singleton, pool_id, wsteth, usdt, get_contract_address()); -// withdraw(singleton, pool_id, wsteth, strk, get_contract_address()); - -// withdraw(singleton, pool_id, strk, eth, get_contract_address()); -// withdraw(singleton, pool_id, strk, wbtc, get_contract_address()); -// withdraw(singleton, pool_id, strk, usdc, get_contract_address()); -// withdraw(singleton, pool_id, strk, usdt, get_contract_address()); -// withdraw(singleton, pool_id, strk, wsteth, get_contract_address()); -// } - -// // 968900 -// #[test] -// #[fork("Mainnet")] -// fn test_integration_re7_usdc_pool() { -// let pool_id = 3592370751539490711610556844458488648008775713878064059760995781404350938653; -// let eth = setup_starkgate_erc20( -// contract_address_const::<0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7>(), -// get_contract_address(), -// 1000 * SCALE -// ); -// let wbtc = setup_starkgate_erc20( -// contract_address_const::<0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac>(), -// get_contract_address(), -// 10 * 1_00_000_000 -// ); -// let usdc = setup_starkgate_erc20( -// contract_address_const::<0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8>(), -// get_contract_address(), -// 10000000 * 1_000_000 -// ); -// let wsteth = setup_starkgate_erc20( -// contract_address_const::<0x042b8f0484674ca266ac5d08e4ac6a3fe65bd3129795def2dca5c34ecc5f96d2>(), -// get_contract_address(), -// 1000 * SCALE -// ); -// let strk = setup_starkgate_erc20( -// contract_address_const::<0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d>(), -// get_contract_address(), -// 10000000 * SCALE -// ); - -// let (singleton, _) = setup(pool_id); - -// supply(singleton, pool_id, eth, wbtc, get_contract_address(), 100 * SCALE); -// supply(singleton, pool_id, eth, usdc, get_contract_address(), 1 * SCALE); -// supply(singleton, pool_id, eth, wsteth, get_contract_address(), 2 * SCALE); -// supply(singleton, pool_id, eth, strk, get_contract_address(), 1 * SCALE); - -// supply(singleton, pool_id, wbtc, eth, get_contract_address(), 1 * 1_00_000_000); -// supply(singleton, pool_id, wbtc, usdc, get_contract_address(), 1 * 1_00_000_000); -// supply(singleton, pool_id, wbtc, wsteth, get_contract_address(), 1 * 1_00_000_000); -// supply(singleton, pool_id, wbtc, strk, get_contract_address(), 1 * 1_00_000_000); - -// supply(singleton, pool_id, usdc, eth, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdc, wbtc, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdc, wsteth, get_contract_address(), 200000 * 1_000_000); -// supply(singleton, pool_id, usdc, strk, get_contract_address(), 200000 * 1_000_000); - -// supply(singleton, pool_id, wsteth, eth, get_contract_address(), 2 * SCALE); -// supply(singleton, pool_id, wsteth, wbtc, get_contract_address(), 100 * SCALE); -// supply(singleton, pool_id, wsteth, usdc, get_contract_address(), 1 * SCALE); -// supply(singleton, pool_id, wsteth, strk, get_contract_address(), 1 * SCALE); - -// supply(singleton, pool_id, strk, eth, get_contract_address(), 10000 * SCALE); -// supply(singleton, pool_id, strk, wbtc, get_contract_address(), 1000000 * SCALE); -// supply(singleton, pool_id, strk, usdc, get_contract_address(), 1000 * SCALE); -// supply(singleton, pool_id, strk, wsteth, get_contract_address(), 10000 * SCALE); - -// borrow(singleton, pool_id, eth, usdc, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, wsteth, usdc, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, wbtc, usdc, get_contract_address(), 200 * 1_000_000); -// borrow(singleton, pool_id, strk, usdc, get_contract_address(), 200 * 1_000_000); - -// // warp -// start_warp(CheatTarget::All, get_block_timestamp() + 94608000); - -// repay(singleton, pool_id, eth, usdc, get_contract_address()); -// repay(singleton, pool_id, wsteth, usdc, get_contract_address()); -// repay(singleton, pool_id, wbtc, usdc, get_contract_address()); -// repay(singleton, pool_id, strk, usdc, get_contract_address()); - -// withdraw(singleton, pool_id, eth, usdc, get_contract_address()); -// withdraw(singleton, pool_id, wsteth, usdc, get_contract_address()); -// withdraw(singleton, pool_id, wbtc, usdc, get_contract_address()); -// withdraw(singleton, pool_id, strk, usdc, get_contract_address()); -// } - -// // 968900 -// #[test] -// #[fork("Mainnet")] -// fn test_integration_re7_sstrk_pool() { -// let pool_id = 1301140954640322725373945719229815062445705809076381949099585786202465661889; -// let strk = setup_starkgate_erc20( -// contract_address_const::<0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d>(), -// get_contract_address(), -// 10000000 * SCALE -// ); -// let sstrk = setup_starkgate_erc20( -// contract_address_const::<0x0356f304b154d29d2a8fe22f1cb9107a9b564a733cf6b4cc47fd121ac1af90c9>(), -// get_contract_address(), -// 10000000 * SCALE -// ); - -// let (singleton, extension) = setup(pool_id); - -// start_prank(CheatTarget::One(extension.contract_address), extension.pool_owner(pool_id)); -// extension.set_debt_cap(pool_id, sstrk.contract_address, strk.contract_address, 1000000 * SCALE); -// stop_prank(CheatTarget::One(extension.contract_address)); -// supply(singleton, pool_id, strk, sstrk, get_contract_address(), 100000 * SCALE); -// supply(singleton, pool_id, sstrk, strk, get_contract_address(), 100000 * SCALE); - -// borrow(singleton, pool_id, sstrk, strk, get_contract_address(), 10000 * SCALE); - -// // warp -// start_warp(CheatTarget::All, get_block_timestamp() + 94608000); - -// repay(singleton, pool_id, strk, sstrk, get_contract_address()); -// repay(singleton, pool_id, sstrk, strk, get_contract_address()); - -// withdraw(singleton, pool_id, strk, sstrk, get_contract_address()); -// withdraw(singleton, pool_id, sstrk, strk, get_contract_address()); -// } - -// // 968900 -// #[test] -// #[fork("Mainnet")] -// fn test_integration_re7_xstrk_pool() { -// let pool_id = 2345856225134458665876812536882617294246962319062565703131100435311373119841; -// let strk = setup_starkgate_erc20( -// contract_address_const::<0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d>(), -// get_contract_address(), -// 10000000 * SCALE -// ); -// let xstrk = setup_starkgate_erc20( -// contract_address_const::<0x028d709c875c0ceac3dce7065bec5328186dc89fe254527084d1689910954b0a>(), -// get_contract_address(), -// 0 -// ); - -// store( -// xstrk.contract_address, -// map_entry_address(selector!("ERC20_balances"), array![get_contract_address().into()].span(),), -// array![(10000000 * SCALE).try_into().unwrap()].span() -// ); - -// let (singleton, extension) = setup(pool_id); - -// start_prank(CheatTarget::One(extension.contract_address), extension.pool_owner(pool_id)); -// extension.set_debt_cap(pool_id, xstrk.contract_address, strk.contract_address, 1000000 * SCALE); -// stop_prank(CheatTarget::One(extension.contract_address)); - -// supply(singleton, pool_id, strk, xstrk, get_contract_address(), 100000 * SCALE); -// supply(singleton, pool_id, xstrk, strk, get_contract_address(), 100000 * SCALE); - -// borrow(singleton, pool_id, xstrk, strk, get_contract_address(), 10000 * SCALE); - -// // warp -// start_warp(CheatTarget::All, get_block_timestamp() + 94608000); - -// repay(singleton, pool_id, strk, xstrk, get_contract_address()); -// repay(singleton, pool_id, xstrk, strk, get_contract_address()); - -// withdraw(singleton, pool_id, strk, xstrk, get_contract_address()); -// withdraw(singleton, pool_id, xstrk, strk, get_contract_address()); -// } -// } diff --git a/src/test/test_user.cairo b/src/test/test_user.cairo deleted file mode 100644 index e670eb7..0000000 --- a/src/test/test_user.cairo +++ /dev/null @@ -1,132 +0,0 @@ -use starknet::{ContractAddress}; -use vesu::units::{PERCENT}; - -#[starknet::interface] -trait IStarkgateERC20 { - fn permissioned_mint(ref self: TContractState, account: ContractAddress, amount: u256); -} - -fn to_percent(value: u256) -> u64 { - (value * PERCENT).try_into().unwrap() -} - -#[cfg(test)] -mod TestUser { - use alexandria_math::i257::{i257, i257_new}; - use snforge_std::{ - start_prank, stop_prank, CheatTarget, store, load, map_entry_address, declare, start_warp, replace_bytecode, - get_class_hash - }; - use starknet::{ - ClassHash, contract_address_const, get_caller_address, get_contract_address, ContractAddress, - get_block_timestamp - }; - use super::{IStarkgateERC20Dispatcher, IStarkgateERC20DispatcherTrait, to_percent}; - use vesu::{ - test::{ - setup::{setup_pool, deploy_contract, deploy_with_args}, - mock_oracle::{IMockPragmaOracleDispatcher, IMockPragmaOracleDispatcherTrait} - }, - vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, - extension::{ - interface::{IExtensionDispatcher, IExtensionDispatcherTrait}, - default_extension_po::{ - IDefaultExtensionDispatcher, IDefaultExtensionDispatcherTrait, PragmaOracleParams, InterestRateConfig, - LiquidationParams, ShutdownParams, FeeParams, VTokenParams, ShutdownMode - }, - components::position_hooks::LiquidationData - }, - units::{SCALE, SCALE_128, PERCENT, DAY_IN_SECONDS}, - data_model::{ - AssetParams, LTVParams, ModifyPositionParams, Amount, AmountType, AmountDenomination, UnsignedAmount, - AssetPrice, TransferPositionParams - }, - singleton::{ISingletonDispatcher, ISingletonDispatcherTrait, LiquidatePositionParams}, - }; - - // block number: 952420 - #[test] - #[available_gas(2000000)] - #[fork("Mainnet")] - fn test_user() { - let singleton = ISingletonDispatcher { - contract_address: contract_address_const::< - 0x2545b2e5d519fc230e9cd781046d3a64e092114f07e44771e0d719d148725ef - >() - }; - - replace_bytecode( - singleton.contract_address, // declare("Singleton").class_hash - get_class_hash(singleton.contract_address) - ); - - let extension = IDefaultExtensionDispatcher { - contract_address: contract_address_const::< - 0x2ded44e2c575671dedb6227ba8bfed340252f3cb0476982074567c0670442f7 - >() - }; - - replace_bytecode( - extension.contract_address, - declare("DefaultExtensionPO").class_hash // get_class_hash(extension.contract_address) - ); - - let pool_id = 3488439889760078773862061392337242708358978534574204613763925972476552399332; - let collateral_asset = IERC20Dispatcher { - contract_address: contract_address_const::< - 0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7 // eth - >() - }; - let debt_asset = IERC20Dispatcher { - contract_address: contract_address_const::< - 0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8 // usdc - >() - }; - // let user = contract_address_const::<0x11b6e878cc575025b488b2e7af5f58f9df99b9f9aa03f22f932ae0b69a955f1>(); - let user = contract_address_const::<0x03d92A8137e51eeE44B8Fb450d90f2CdA085B2568562c1B8695cBF11c06f9c8d>(); - - // let (position, _, _) = singleton - // .position(pool_id, collateral_asset.contract_address, debt_asset.contract_address, user); - - println!("balance: {}", collateral_asset.balance_of(user)); - - start_prank(CheatTarget::One(collateral_asset.contract_address), user); - collateral_asset.approve(singleton.contract_address, 100 * SCALE); - stop_prank(CheatTarget::One(collateral_asset.contract_address)); - - start_prank(CheatTarget::One(singleton.contract_address), user); - singleton - .modify_position( - ModifyPositionParams { - pool_id, - collateral_asset: collateral_asset.contract_address, - debt_asset: debt_asset.contract_address, - user, - collateral: Amount { // 0.04 ETH - amount_type: AmountType::Delta, - denomination: AmountDenomination::Assets, - value: 40000000000000000.into(), - }, - debt: Default::default(), - data: ArrayTrait::new().span(), - } - ); - singleton - .modify_position( - ModifyPositionParams { - pool_id, - collateral_asset: collateral_asset.contract_address, - debt_asset: debt_asset.contract_address, - user, - collateral: Default::default(), - debt: Amount { // 10 USDC - amount_type: AmountType::Delta, - denomination: AmountDenomination::Assets, - value: 10000000.into(), - }, - data: ArrayTrait::new().span(), - } - ); - stop_prank(CheatTarget::One(singleton.contract_address)); - } -} diff --git a/src/test/timelock_test.cairo b/src/test/timelock_test.cairo deleted file mode 100644 index a0f4ede..0000000 --- a/src/test/timelock_test.cairo +++ /dev/null @@ -1,247 +0,0 @@ -use core::array::{Array, ArrayTrait, SpanTrait}; -use starknet::{ - get_contract_address, syscalls::{deploy_syscall}, ClassHash, contract_address_const, ContractAddress, - get_block_timestamp, testing::set_block_timestamp -}; -use vesu::vendor::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; -use vesu::vendor::timelock::{ExecutionState}; -use vesu::vendor::timelock::{ITimelockDispatcher, ITimelockDispatcherTrait, Timelock, Config}; - -#[starknet::contract] -pub(crate) mod TestToken { - use core::num::traits::zero::{Zero}; - use starknet::{ContractAddress, get_caller_address}; - use vesu::vendor::erc20::{IERC20}; - - #[storage] - struct Storage { - balances: LegacyMap, - allowances: LegacyMap<(ContractAddress, ContractAddress), u256>, - } - - #[derive(starknet::Event, PartialEq, Debug, Drop)] - pub(crate) struct Transfer { - pub(crate) from: ContractAddress, - pub(crate) to: ContractAddress, - pub(crate) value: u256, - } - - #[derive(starknet::Event, Drop)] - #[event] - enum Event { - Transfer: Transfer, - } - - #[constructor] - fn constructor(ref self: ContractState, recipient: ContractAddress, amount: u256) { - self.balances.write(recipient, amount); - self.emit(Transfer { from: Zero::zero(), to: recipient, value: amount }) - } - - #[abi(embed_v0)] - impl IERC20Impl of IERC20 { - fn balance_of(self: @ContractState, account: ContractAddress) -> u256 { - self.balances.read(account).into() - } - fn allowance(self: @ContractState, owner: ContractAddress, spender: ContractAddress) -> u256 { - self.allowances.read((owner, spender)).into() - } - fn transfer(ref self: ContractState, recipient: ContractAddress, amount: u256) -> bool { - let balance = self.balances.read(get_caller_address()); - assert(balance >= amount, 'INSUFFICIENT_TRANSFER_BALANCE'); - self.balances.write(recipient, self.balances.read(recipient) + amount); - self.balances.write(get_caller_address(), balance - amount); - self.emit(Transfer { from: get_caller_address(), to: recipient, value: amount }); - true - } - fn transfer_from( - ref self: ContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 - ) -> bool { - let allowance = self.allowances.read((sender, get_caller_address())); - assert(allowance >= amount, 'INSUFFICIENT_ALLOWANCE'); - let balance = self.balances.read(sender); - assert(balance >= amount, 'INSUFFICIENT_TF_BALANCE'); - self.balances.write(recipient, self.balances.read(recipient) + amount); - self.balances.write(sender, balance - amount); - self.allowances.write((sender, get_caller_address()), allowance - amount); - self.emit(Transfer { from: sender, to: recipient, value: amount }); - true - } - fn approve(ref self: ContractState, spender: ContractAddress, amount: u256) -> bool { - self.allowances.write((get_caller_address(), spender), amount.try_into().unwrap()); - true - } - fn total_supply(self: @ContractState) -> u256 { - 0 - } - } -} - -#[cfg(test)] -mod TestTimelock { - use snforge_std::{declare, start_warp, CheatTarget}; - use starknet::account::{Call}; - use starknet::{ - get_contract_address, syscalls::{deploy_syscall}, ClassHash, contract_address_const, ContractAddress, - get_block_timestamp, testing::set_block_timestamp - }; - use vesu::vendor::erc20::{IERC20Dispatcher, IERC20DispatcherTrait}; - use vesu::vendor::timelock::{ExecutionState}; - use vesu::vendor::timelock::{ITimelockDispatcher, ITimelockDispatcherTrait, Timelock, Config}; - - fn deploy_token(owner: ContractAddress, amount: u256) -> IERC20Dispatcher { - let mut constructor_args: Array = ArrayTrait::new(); - Serde::serialize(@(owner, amount), ref constructor_args); - - let (address, _) = deploy_syscall( - declare("TestToken").class_hash.try_into().unwrap(), 0, constructor_args.span(), true - ) - .expect('DEPLOY_TOKEN_FAILED'); - IERC20Dispatcher { contract_address: address } - } - - fn deploy(owner: ContractAddress, delay: u64, window: u64) -> ITimelockDispatcher { - let mut constructor_args: Array = ArrayTrait::new(); - Serde::serialize(@(owner, delay, window), ref constructor_args); - - let (address, _) = deploy_syscall( - declare("Timelock").class_hash.try_into().unwrap(), 0, constructor_args.span(), true - ) - .expect('DEPLOY_FAILED'); - return ITimelockDispatcher { contract_address: address }; - } - - fn transfer_call(token: IERC20Dispatcher, recipient: ContractAddress, amount: u256) -> Call { - let mut calldata: Array = ArrayTrait::new(); - Serde::serialize(@(recipient, amount), ref calldata); - - Call { - to: token.contract_address, - // transfer - selector: 0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e, - calldata: calldata.span() - } - } - - fn single_call(call: Call) -> Span { - return array![call].span(); - } - - #[test] - fn test_deploy() { - let timelock = deploy(contract_address_const::<2300>(), 10239, 3600); - - let configuration = timelock.get_config(); - assert(configuration.delay == 10239, 'delay'); - assert(configuration.window == 3600, 'window'); - let owner = timelock.get_owner(); - assert(owner == contract_address_const::<2300>(), 'owner'); - } - - #[test] - fn test_queue_execute() { - // set_block_timestamp(1); - start_warp(CheatTarget::All, 1); - let timelock = deploy(get_contract_address(), 86400, 3600); - - let token = deploy_token(get_contract_address(), 12345); - token.transfer(timelock.contract_address, 12345); - - let recipient = contract_address_const::<12345>(); - - let id = timelock.queue(single_call(transfer_call(token, recipient, 500_u256))); - - let execution_window = timelock.get_execution_window(id); - assert(execution_window.earliest == 86401, 'earliest'); - assert(execution_window.latest == 90001, 'latest'); - - // set_block_timestamp(86401); - start_warp(CheatTarget::All, 86401); - - timelock.execute(single_call(transfer_call(token, recipient, 500_u256))); - assert(token.balance_of(recipient) == 500_u256, 'balance'); - } - - #[test] - #[should_panic(expected: 'HAS_BEEN_CANCELED')] - fn test_queue_cancel() { - // set_block_timestamp(1); - start_warp(CheatTarget::All, 1); - let timelock = deploy(get_contract_address(), 86400, 3600); - - let token = deploy_token(get_contract_address(), 12345); - token.transfer(timelock.contract_address, 12345); - - let recipient = contract_address_const::<12345>(); - - let id = timelock.queue(single_call(transfer_call(token, recipient, 500_u256))); - - // set_block_timestamp(86401); - start_warp(CheatTarget::All, 86401); - - timelock.cancel(id); - - timelock.execute(single_call(transfer_call(token, recipient, 500_u256))); - } - - #[test] - #[should_panic(expected: 'ALREADY_EXECUTED')] - fn test_queue_execute_twice() { - // set_block_timestamp(1); - start_warp(CheatTarget::All, 1); - let timelock = deploy(get_contract_address(), 86400, 3600); - - let token = deploy_token(get_contract_address(), 12345); - token.transfer(timelock.contract_address, 12345); - - let recipient = contract_address_const::<12345>(); - - timelock.queue(single_call(transfer_call(token, recipient, 500_u256))); - - // set_block_timestamp(86401); - start_warp(CheatTarget::All, 86401); - - timelock.execute(single_call(transfer_call(token, recipient, 500_u256))); - timelock.execute(single_call(transfer_call(token, recipient, 500_u256))); - } - - #[test] - #[should_panic(expected: 'TOO_EARLY')] - fn test_queue_executed_too_early() { - // set_block_timestamp(1); - start_warp(CheatTarget::All, 1); - let timelock = deploy(get_contract_address(), 86400, 3600); - - let token = deploy_token(get_contract_address(), 12345); - token.transfer(timelock.contract_address, 12345); - - let recipient = contract_address_const::<12345>(); - - let id = timelock.queue(single_call(transfer_call(token, recipient, 500_u256))); - - let execution_window = timelock.get_execution_window(id); - // set_block_timestamp(execution_window.earliest - 1); - start_warp(CheatTarget::All, execution_window.earliest - 1); - timelock.execute(single_call(transfer_call(token, recipient, 500_u256))); - } - - #[test] - #[should_panic(expected: 'TOO_LATE')] - fn test_queue_executed_too_late() { - // set_block_timestamp(1); - start_warp(CheatTarget::All, 1); - let timelock = deploy(get_contract_address(), 86400, 3600); - - let token = deploy_token(get_contract_address(), 12345); - token.transfer(timelock.contract_address, 12345); - - let recipient = contract_address_const::<12345>(); - - let id = timelock.queue(single_call(transfer_call(token, recipient, 500_u256))); - - let execution_window = timelock.get_execution_window(id); - // set_block_timestamp(execution_window.latest); - start_warp(CheatTarget::All, execution_window.latest); - timelock.execute(single_call(transfer_call(token, recipient, 500_u256))); - } -} diff --git a/src/vendor/timelock.cairo b/src/vendor/timelock.cairo deleted file mode 100644 index 24dc735..0000000 --- a/src/vendor/timelock.cairo +++ /dev/null @@ -1,313 +0,0 @@ -use core::hash::{LegacyHash, HashStateTrait, HashStateExTrait, Hash}; -use core::option::OptionTrait; -use core::result::ResultTrait; -use core::traits::TryInto; -use starknet::account::{Call}; -use starknet::class_hash::{ClassHash}; -use starknet::contract_address::{ContractAddress}; -use starknet::storage_access::{StorePacking}; -use starknet::{SyscallResult, syscalls::call_contract_syscall}; - -const TWO_POW_64: u128 = 0x10000000000000000; -const TWO_POW_64_DIVISOR: NonZero = 0x10000000000000000; - -pub(crate) impl TwoU64TupleStorePacking of StorePacking<(u64, u64), u128> { - fn pack(value: (u64, u64)) -> u128 { - let (a, b) = value; - a.into() + (b.into() * TWO_POW_64) - } - - fn unpack(value: u128) -> (u64, u64) { - let (q, r) = DivRem::div_rem(value, TWO_POW_64_DIVISOR); - (r.try_into().unwrap(), q.try_into().unwrap()) - } -} - -#[derive(Copy, Drop, Serde, PartialEq, Debug)] -pub struct ExecutionState { - pub created: u64, - pub executed: u64, - pub canceled: u64 -} - -pub(crate) impl ExecutionStateStorePacking of StorePacking { - fn pack(value: ExecutionState) -> felt252 { - u256 { low: TwoU64TupleStorePacking::pack((value.created, value.executed)), high: value.canceled.into() } - .try_into() - .unwrap() - } - - fn unpack(value: felt252) -> ExecutionState { - let u256_value: u256 = value.into(); - let (created, executed) = TwoU64TupleStorePacking::unpack(u256_value.low); - ExecutionState { created, executed, canceled: (u256_value.high).try_into().unwrap() } - } -} - -pub impl HashCall, +Drop, +Copy> of Hash<@Call, S> { - fn update_state(state: S, value: @Call) -> S { - let mut s = state.update_with((*value.to)).update_with(*value.selector); - - let mut data_span: Span = *value.calldata; - while let Option::Some(word) = data_span.pop_front() { - s = s.update(*word); - }; - - s - } -} - -#[generate_trait] -pub impl CallTraitImpl of CallTrait { - fn execute(self: @Call) -> Span { - let result = call_contract_syscall(*self.to, *self.selector, *self.calldata); - - if (result.is_err()) { - panic(result.unwrap_err()); - } - - result.unwrap() - } -} - -#[derive(Copy, Drop, Serde)] -pub struct Config { - pub delay: u64, - pub window: u64, -} - -pub(crate) impl ConfigStorePacking of StorePacking { - fn pack(value: Config) -> u128 { - TwoU64TupleStorePacking::pack((value.delay, value.window)) - } - - fn unpack(value: u128) -> Config { - let (delay, window) = TwoU64TupleStorePacking::unpack(value); - Config { delay, window } - } -} - -#[starknet::interface] -pub trait ITimelock { - // Queue a list of calls to be executed after the delay. Only the owner may call this. - fn queue(ref self: TContractState, calls: Span) -> felt252; - - // Cancel a queued proposal before it is executed. Only the owner may call this. - fn cancel(ref self: TContractState, id: felt252); - - // Execute a list of calls that have previously been queued. Anyone may call this. - fn execute(ref self: TContractState, calls: Span) -> Array>; - - // Return the execution window, i.e. the start and end timestamp in which the call can be executed - fn get_execution_window(self: @TContractState, id: felt252) -> ExecutionWindow; - - // Get the current owner - fn get_owner(self: @TContractState) -> ContractAddress; - - // Returns the delay and the window for call execution - fn get_config(self: @TContractState) -> Config; - - // Transfer ownership, i.e. the address that can queue and cancel calls. This must be self-called via #queue. - fn transfer(ref self: TContractState, to: ContractAddress); - - // Configure the delay and the window for call execution. This must be self-called via #queue. - fn configure(ref self: TContractState, config: Config); - - // Replace the code at this address. This must be self-called via #queue. - fn upgrade(ref self: TContractState, class_hash: ClassHash); -} - -#[derive(Copy, Drop, Serde)] -pub struct ExecutionWindow { - pub earliest: u64, - pub latest: u64 -} - -#[starknet::contract] -pub mod Timelock { - use core::hash::LegacyHash; - use core::result::ResultTrait; - use starknet::{ - get_caller_address, get_contract_address, SyscallResult, - syscalls::{call_contract_syscall, replace_class_syscall}, get_block_timestamp - }; - use super::{ - ClassHash, ITimelock, ContractAddress, Call, Config, ExecutionState, ConfigStorePacking, ExecutionWindow, - CallTrait, HashCall - }; - - - #[derive(starknet::Event, Drop)] - pub struct Queued { - pub id: felt252, - pub calls: Span, - } - - #[derive(starknet::Event, Drop)] - pub struct Canceled { - pub id: felt252, - } - - #[derive(starknet::Event, Drop)] - pub struct Executed { - pub id: felt252, - } - - #[derive(starknet::Event, Drop)] - #[event] - enum Event { - Queued: Queued, - Canceled: Canceled, - Executed: Executed, - } - - #[storage] - struct Storage { - owner: ContractAddress, - config: Config, - execution_state: LegacyMap, - } - - #[constructor] - fn constructor(ref self: ContractState, owner: ContractAddress, config: Config) { - self.owner.write(owner); - self.config.write(config); - } - - // Take a list of calls and convert it to a unique identifier for the execution - // Two lists of calls will always have the same ID if they are equivalent - // A list of calls can only be queued and executed once. To make 2 different calls, add an empty call. - pub(crate) fn to_id(mut calls: Span) -> felt252 { - let mut state = selector!("ekubo::governance::Timelock::to_id"); - while let Option::Some(call) = calls.pop_front() { - state = LegacyHash::hash(state, call); - }; - state - } - - #[generate_trait] - impl TimelockInternal of TimelockInternalTrait { - fn check_owner(self: @ContractState) { - assert(get_caller_address() == self.owner.read(), 'OWNER_ONLY'); - } - - fn check_self_call(self: @ContractState) { - assert(get_caller_address() == get_contract_address(), 'SELF_CALL_ONLY'); - } - } - - #[abi(embed_v0)] - impl TimelockImpl of ITimelock { - fn queue(ref self: ContractState, calls: Span) -> felt252 { - self.check_owner(); - - let id = to_id(calls); - let execution_state = self.execution_state.read(id); - - assert(execution_state.canceled.is_zero(), 'HAS_BEEN_CANCELED'); - assert(execution_state.created.is_zero(), 'ALREADY_QUEUED'); - - self.execution_state.write(id, ExecutionState { created: get_block_timestamp(), executed: 0, canceled: 0 }); - - self.emit(Queued { id, calls }); - - id - } - - fn cancel(ref self: ContractState, id: felt252) { - self.check_owner(); - - let execution_state = self.execution_state.read(id); - assert(execution_state.created.is_non_zero(), 'DOES_NOT_EXIST'); - assert(execution_state.executed.is_zero(), 'ALREADY_EXECUTED'); - - self - .execution_state - .write( - id, - ExecutionState { - created: execution_state.created, - executed: execution_state.executed, - canceled: get_block_timestamp() - } - ); - - self.emit(Canceled { id }); - } - - fn execute(ref self: ContractState, mut calls: Span) -> Array> { - let id = to_id(calls); - - let execution_state = self.execution_state.read(id); - - assert(execution_state.executed.is_zero(), 'ALREADY_EXECUTED'); - assert(execution_state.canceled.is_zero(), 'HAS_BEEN_CANCELED'); - - let execution_window = self.get_execution_window(id); - let time_current = get_block_timestamp(); - - assert(time_current >= execution_window.earliest, 'TOO_EARLY'); - assert(time_current < execution_window.latest, 'TOO_LATE'); - - self - .execution_state - .write( - id, - ExecutionState { - created: execution_state.created, executed: time_current, canceled: execution_state.canceled - } - ); - - let mut results: Array> = ArrayTrait::new(); - - while let Option::Some(call) = calls.pop_front() { - results.append(call.execute()); - }; - - self.emit(Executed { id }); - - results - } - - fn get_execution_window(self: @ContractState, id: felt252) -> ExecutionWindow { - let created = self.execution_state.read(id).created; - - // this prevents the 0 timestamp for created from being considered valid and also executed - assert(created.is_non_zero(), 'DOES_NOT_EXIST'); - - let config = self.get_config(); - - let earliest = created + config.delay; - - let latest = earliest + config.window; - - ExecutionWindow { earliest, latest } - } - - fn get_owner(self: @ContractState) -> ContractAddress { - self.owner.read() - } - - fn get_config(self: @ContractState) -> Config { - self.config.read() - } - - fn transfer(ref self: ContractState, to: ContractAddress) { - self.check_self_call(); - - self.owner.write(to); - } - - fn configure(ref self: ContractState, config: Config) { - self.check_self_call(); - - self.config.write(config); - } - - fn upgrade(ref self: ContractState, class_hash: ClassHash) { - self.check_self_call(); - - replace_class_syscall(class_hash).unwrap(); - } - } -} From a54d9a708164ae57d341314c784042c0a63a3f49 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:03:38 +0800 Subject: [PATCH 31/32] fix ek tests --- src/extension/default_extension_ek.cairo | 149 +++++++++++++++++++---- src/test/test_default_extension_ek.cairo | 101 ++++++++++++--- 2 files changed, 205 insertions(+), 45 deletions(-) diff --git a/src/extension/default_extension_ek.cairo b/src/extension/default_extension_ek.cairo index 8185e0e..4e8febf 100644 --- a/src/extension/default_extension_ek.cairo +++ b/src/extension/default_extension_ek.cairo @@ -1,6 +1,6 @@ use starknet::ContractAddress; use vesu::{ - data_model::{AssetParams, LTVParams, LTVConfig}, + data_model::{AssetParams, LTVParams, LTVConfig, DebtCapParams}, extension::{ components::{ interest_rate_model::InterestRateConfig, @@ -18,10 +18,13 @@ struct EkuboOracleParams { #[starknet::interface] trait IDefaultExtensionEK { + fn pool_name(self: @TContractState, pool_id: felt252) -> felt252; fn pool_owner(self: @TContractState, pool_id: felt252) -> ContractAddress; fn ekubo_oracle(self: @TContractState) -> ContractAddress; fn ekubo_oracle_config(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> EkuboOracleConfig; - fn debt_caps(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> u256; + fn debt_caps( + self: @TContractState, pool_id: felt252, collateral_asset: ContractAddress, debt_asset: ContractAddress + ) -> u256; fn fee_config(self: @TContractState, pool_id: felt252) -> FeeConfig; fn interest_rate_config(self: @TContractState, pool_id: felt252, asset: ContractAddress) -> InterestRateConfig; fn liquidation_config( @@ -51,12 +54,14 @@ trait IDefaultExtensionEK { ) -> ContractAddress; fn create_pool( ref self: TContractState, + name: felt252, asset_params: Span, v_token_params: Span, ltv_params: Span, interest_rate_configs: Span, ekubo_oracle_params: Span, liquidation_params: Span, + debt_caps: Span, shutdown_params: ShutdownParams, fee_params: FeeParams, owner: ContractAddress @@ -68,12 +73,17 @@ trait IDefaultExtensionEK { v_token_params: VTokenParams, interest_rate_config: InterestRateConfig, ekubo_oracle_params: EkuboOracleParams, - debt_cap: u256 ); fn set_asset_parameter( ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u256 ); - fn set_debt_cap(ref self: TContractState, pool_id: felt252, asset: ContractAddress, debt_cap: u256); + fn set_debt_cap( + ref self: TContractState, + pool_id: felt252, + collateral_asset: ContractAddress, + debt_asset: ContractAddress, + debt_cap: u256 + ); fn set_interest_rate_parameter( ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u256 ); @@ -115,15 +125,20 @@ trait IDefaultExtensionEK { #[starknet::contract] mod DefaultExtensionEK { - use alexandria_math::i257::i257; - use starknet::{ContractAddress, get_contract_address, get_caller_address, event::EventEmitter}; + use alexandria_math::i257::{i257, i257_new}; + use starknet::{ + ContractAddress, contract_address_const, get_contract_address, get_caller_address, event::EventEmitter + }; use super::{ IDefaultExtensionEK, IDefaultExtensionEKDispatcher, IDefaultExtensionEKDispatcherTrait, EkuboOracleParams }; use vesu::extension::components::position_hooks::position_hooks_component::Trait; use vesu::{ map_list::{map_list_component, map_list_component::MapListTrait}, - data_model::{Amount, UnsignedAmount, AssetParams, AssetPrice, LTVParams, Context, LTVConfig}, + data_model::{ + Amount, UnsignedAmount, AssetParams, AssetPrice, LTVParams, Context, LTVConfig, ModifyPositionParams, + AmountDenomination, AmountType, DebtCapParams + }, singleton::{ISingletonDispatcher, ISingletonDispatcherTrait}, extension::{ interface::IExtension, @@ -145,7 +160,7 @@ mod DefaultExtensionEK { tokenization::{tokenization_component, tokenization_component::TokenizationTrait} } }, - vendor::erc20::{IERC20MetadataDispatcher, IERC20MetadataDispatcherTrait}, + vendor::erc20::{ERC20ABIDispatcher as IERC20Dispatcher, ERC20ABIDispatcherTrait}, units::INFLATION_FEE, }; component!(path: position_hooks_component, storage: position_hooks, event: PositionHooksEvents); @@ -161,6 +176,8 @@ mod DefaultExtensionEK { singleton: ContractAddress, // tracks the owner for each pool owner: LegacyMap::, + // tracks the name for each pool + pool_names: LegacyMap::, // storage for the position hooks component #[substorage(v0)] position_hooks: position_hooks_component::Storage, @@ -274,6 +291,15 @@ mod DefaultExtensionEK { #[abi(embed_v0)] impl DefaultExtensionEKImpl of IDefaultExtensionEK { + /// Returns the name of a pool + /// # Arguments + /// * `pool_id` - id of the pool + /// # Returns + /// * `name` - name of the pool + fn pool_name(self: @ContractState, pool_id: felt252) -> felt252 { + self.pool_names.read(pool_id) + } + /// Returns the owner of a pool /// # Arguments /// * `pool_id` - id of the pool @@ -312,11 +338,14 @@ mod DefaultExtensionEK { /// Returns the debt cap for a given asset in a pool /// # Arguments /// * `pool_id` - id of the pool - /// * `asset` - address of the asset + /// * `collateral_asset` - address of the collateral asset + /// * `debt_asset` - address of the debt asset /// # Returns /// * `debt_cap` - debt cap - fn debt_caps(self: @ContractState, pool_id: felt252, asset: ContractAddress) -> u256 { - self.position_hooks.debt_caps.read((pool_id, asset)) + fn debt_caps( + self: @ContractState, pool_id: felt252, collateral_asset: ContractAddress, debt_asset: ContractAddress + ) -> u256 { + self.position_hooks.debt_caps.read((pool_id, collateral_asset, debt_asset)) } /// Returns the interest rate configuration for a given pool and asset @@ -448,24 +477,28 @@ mod DefaultExtensionEK { /// Creates a new pool /// # Arguments + /// * `name` - name of the pool /// * `asset_params` - asset parameters /// * `v_token_params` - vToken parameters /// * `ltv_params` - loan-to-value parameters /// * `interest_rate_params` - interest rate model parameters /// * `ekubo_oracle_params` - Ekubo oracle parameters /// * `liquidation_params` - liquidation parameters + /// * `debt_caps` - debt caps /// * `shutdown_params` - shutdown parameters /// * `fee_params` - fee model parameters /// # Returns /// * `pool_id` - id of the pool fn create_pool( ref self: ContractState, + name: felt252, mut asset_params: Span, mut v_token_params: Span, mut ltv_params: Span, mut interest_rate_configs: Span, mut ekubo_oracle_params: Span, mut liquidation_params: Span, + mut debt_caps: Span, shutdown_params: ShutdownParams, fee_params: FeeParams, owner: ContractAddress @@ -477,8 +510,12 @@ mod DefaultExtensionEK { assert!(asset_params.len() == v_token_params.len(), "v-token-params-mismatch"); // create the pool in the singleton - let pool_id = ISingletonDispatcher { contract_address: self.singleton.read() } - .create_pool(asset_params, ltv_params, get_contract_address()); + let singleton = ISingletonDispatcher { contract_address: self.singleton.read() }; + let pool_id = singleton.create_pool(asset_params, ltv_params, get_contract_address()); + + // set the pool name + self.pool_names.write(pool_id, name); + // set the pool owner self.owner.write(pool_id, owner); @@ -488,7 +525,7 @@ mod DefaultExtensionEK { .is_empty() { let asset = *asset_params_copy.pop_front().unwrap().asset; assert!(asset != self.ekubo_oracle.quote_asset(), "add-quote-asset-disallowed"); - let asset_decimals = IERC20MetadataDispatcher { contract_address: asset }.decimals(); + let asset_decimals = IERC20Dispatcher { contract_address: asset }.decimals(); // set the oracle config let params = *ekubo_oracle_params.pop_front().unwrap(); @@ -509,6 +546,32 @@ mod DefaultExtensionEK { // deploy the vToken for the the collateral asset self.tokenization.create_v_token(pool_id, asset, v_token_name, v_token_symbol); + // burn inflation fee + let asset = IERC20Dispatcher { contract_address: asset }; + assert!( + asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE), + "transfer-from-failed" + ); + + assert!(asset.approve(singleton.contract_address, INFLATION_FEE), "approve-failed"); + + singleton + .modify_position( + ModifyPositionParams { + pool_id, + collateral_asset: asset.contract_address, + debt_asset: Zeroable::zero(), + user: contract_address_const::<'ZERO'>(), + collateral: Amount { + amount_type: AmountType::Delta, + denomination: AmountDenomination::Assets, + value: i257_new(INFLATION_FEE, false), + }, + debt: Default::default(), + data: ArrayTrait::new().span() + } + ); + i += 1; }; @@ -529,6 +592,16 @@ mod DefaultExtensionEK { ); }; + // set the debt caps for each pair + let mut debt_caps = debt_caps; + while !debt_caps + .is_empty() { + let params = *debt_caps.pop_front().unwrap(); + let collateral_asset = *asset_params.at(params.collateral_asset_index).asset; + let debt_asset = *asset_params.at(params.debt_asset_index).asset; + self.position_hooks.set_debt_cap(pool_id, collateral_asset, debt_asset, params.debt_cap); + }; + // set the max shutdown LTVs for each asset let mut shutdown_ltv_params = shutdown_params.ltv_params; while !shutdown_ltv_params @@ -560,20 +633,18 @@ mod DefaultExtensionEK { /// * `v_token_params` - vToken parameters /// * `interest_rate_model` - interest rate model /// * `ekubo_oracle_params` - Ekubo oracle parameters - /// * `debt_cap` - debt cap fn add_asset( ref self: ContractState, pool_id: felt252, asset_params: AssetParams, v_token_params: VTokenParams, interest_rate_config: InterestRateConfig, - ekubo_oracle_params: EkuboOracleParams, - debt_cap: u256 + ekubo_oracle_params: EkuboOracleParams ) { assert!(get_caller_address() == self.owner.read(pool_id), "caller-not-owner"); let asset = asset_params.asset; assert!(asset != self.ekubo_oracle.quote_asset(), "add-quote-asset-disallowed"); - let asset_decimals = IERC20MetadataDispatcher { contract_address: asset }.decimals(); + let asset_decimals = IERC20Dispatcher { contract_address: asset }.decimals(); // set the oracle config self @@ -582,9 +653,6 @@ mod DefaultExtensionEK { pool_id, asset, EkuboOracleConfig { decimals: asset_decimals, period: ekubo_oracle_params.period } ); - // set the debt cap - self.position_hooks.set_debt_cap(pool_id, asset, debt_cap); - // set the interest rate model configuration self.interest_rate_model.set_interest_rate_config(pool_id, asset, interest_rate_config); @@ -592,17 +660,48 @@ mod DefaultExtensionEK { let VTokenParams { v_token_name, v_token_symbol } = v_token_params; self.tokenization.create_v_token(pool_id, asset, v_token_name, v_token_symbol); - ISingletonDispatcher { contract_address: self.singleton.read() }.set_asset_config(pool_id, asset_params); + let singleton = ISingletonDispatcher { contract_address: self.singleton.read() }; + singleton.set_asset_config(pool_id, asset_params); + + // burn inflation fee + let asset = IERC20Dispatcher { contract_address: asset }; + assert!( + asset.transferFrom(get_caller_address(), get_contract_address(), INFLATION_FEE), "transfer-from-failed" + ); + assert!(asset.approve(singleton.contract_address, INFLATION_FEE), "approve-failed"); + singleton + .modify_position( + ModifyPositionParams { + pool_id, + collateral_asset: asset.contract_address, + debt_asset: Zeroable::zero(), + user: contract_address_const::<'ZERO'>(), + collateral: Amount { + amount_type: AmountType::Delta, + denomination: AmountDenomination::Assets, + value: i257_new(INFLATION_FEE, false), + }, + debt: Default::default(), + data: ArrayTrait::new().span() + } + ); } /// Sets the debt cap for a given asset in a pool /// # Arguments /// * `pool_id` - id of the pool - /// * `asset` - address of the asset + /// * `collateral_asset` - address of the collateral asset + /// * `debt_asset` - address of the debt asset /// * `debt_cap` - debt cap - fn set_debt_cap(ref self: ContractState, pool_id: felt252, asset: ContractAddress, debt_cap: u256) { + fn set_debt_cap( + ref self: ContractState, + pool_id: felt252, + collateral_asset: ContractAddress, + debt_asset: ContractAddress, + debt_cap: u256 + ) { assert!(get_caller_address() == self.owner.read(pool_id), "caller-not-owner"); - self.position_hooks.set_debt_cap(pool_id, asset, debt_cap); + self.position_hooks.set_debt_cap(pool_id, collateral_asset, debt_asset, debt_cap); } /// Sets a parameter for a given interest rate configuration for an asset in a pool diff --git a/src/test/test_default_extension_ek.cairo b/src/test/test_default_extension_ek.cairo index 8b93f8f..29653c5 100644 --- a/src/test/test_default_extension_ek.cairo +++ b/src/test/test_default_extension_ek.cairo @@ -1,9 +1,9 @@ #[cfg(test)] mod TestDefaultExtensionEK { - use snforge_std::{start_prank, stop_prank, CheatTarget, get_class_hash, ContractClass, declare}; + use snforge_std::{start_prank, stop_prank, CheatTarget, get_class_hash, ContractClass, declare, prank, CheatSpan}; use starknet::get_contract_address; use vesu::{ - units::{SCALE, PERCENT, DAY_IN_SECONDS}, test::mock_ekubo_core::IMockEkuboCoreDispatcherTrait, + units::{SCALE, PERCENT, DAY_IN_SECONDS, INFLATION_FEE}, test::mock_ekubo_core::IMockEkuboCoreDispatcherTrait, test::setup::{ setup_env_v3, create_pool_v3, TestConfigV3, deploy_assets, deploy_asset, EnvV3, EKUBO_TWAP_PERIOD, test_interest_rate_config @@ -76,20 +76,23 @@ mod TestDefaultExtensionEK { let interest_rate_configs = array![].span(); let oracle_params = array![].span(); let liquidation_params = array![].span(); + let debt_caps_params = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); + prank(CheatTarget::One(extension_v3.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v3 .create_pool( + 'DefaultExtensionEK', asset_params, v_token_params, max_position_ltv_params, interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -128,20 +131,27 @@ mod TestDefaultExtensionEK { let interest_rate_configs = array![].span(); let oracle_params = array![].span(); let liquidation_params = array![].span(); + let debt_caps_params = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension_v3.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension_v3.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v3 .create_pool( + 'DefaultExtensionEK', asset_params, v_token_params, max_position_ltv_params, interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -180,20 +190,27 @@ mod TestDefaultExtensionEK { let interest_rate_configs = array![test_interest_rate_config()].span(); let oracle_params = array![].span(); let liquidation_params = array![].span(); + let debt_caps_params = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension_v3.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension_v3.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v3 .create_pool( + 'DefaultExtensionEK', asset_params, v_token_params, max_position_ltv_params, interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -232,20 +249,27 @@ mod TestDefaultExtensionEK { let interest_rate_configs = array![test_interest_rate_config()].span(); let oracle_params = array![collateral_asset_oracle_params].span(); let liquidation_params = array![].span(); + let debt_caps_params = array![].span(); let shutdown_ltv_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; - start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension_v3.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension_v3.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v3 .create_pool( + 'DefaultExtensionEK', asset_params, v_token_params, max_position_ltv_params, interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -287,6 +311,7 @@ mod TestDefaultExtensionEK { let oracle_params = array![quote_asset_oracle_params].span(); let liquidation_params = array![].span(); let shutdown_ltv_params = array![].span(); + let debt_caps_params = array![].span(); let shutdown_params = ShutdownParams { recovery_period: DAY_IN_SECONDS, subscription_period: DAY_IN_SECONDS, ltv_params: shutdown_ltv_params }; @@ -294,12 +319,14 @@ mod TestDefaultExtensionEK { start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); extension_v3 .create_pool( + 'DefaultExtensionEK', asset_params, v_token_params, max_position_ltv_params, interest_rate_configs, oracle_params, liquidation_params, + debt_caps_params, shutdown_params, FeeParams { fee_recipient: users.creator }, users.creator @@ -352,7 +379,7 @@ mod TestDefaultExtensionEK { let ekubo_oracle_params = EkuboOracleParams { period: EKUBO_TWAP_PERIOD }; extension_v3 - .add_asset(config.pool_id_v3, asset_params, v_token_params, interest_rate_config, ekubo_oracle_params, 0); + .add_asset(config.pool_id_v3, asset_params, v_token_params, interest_rate_config, ekubo_oracle_params); } #[test] @@ -394,9 +421,14 @@ mod TestDefaultExtensionEK { }; let ekubo_oracle_params = EkuboOracleParams { period: EKUBO_TWAP_PERIOD }; - start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); + + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension_v3.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension_v3.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v3 - .add_asset(config.pool_id_v3, asset_params, v_token_params, interest_rate_config, ekubo_oracle_params, 0); + .add_asset(config.pool_id_v3, asset_params, v_token_params, interest_rate_config, ekubo_oracle_params); stop_prank(CheatTarget::One(extension_v3.contract_address)); } @@ -439,9 +471,14 @@ mod TestDefaultExtensionEK { }; let ekubo_oracle_params = EkuboOracleParams { period: Zeroable::zero() }; - start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); + + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension_v3.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension_v3.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v3 - .add_asset(config.pool_id_v3, asset_params, v_token_params, interest_rate_config, ekubo_oracle_params, 0); + .add_asset(config.pool_id_v3, asset_params, v_token_params, interest_rate_config, ekubo_oracle_params); stop_prank(CheatTarget::One(extension_v3.contract_address)); } @@ -494,14 +531,18 @@ mod TestDefaultExtensionEK { ); ekubo_core.set_pool_liquidity(asset_pool_key, Zeroable::zero()); - start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); + start_prank(CheatTarget::One(config.collateral_asset.contract_address), users.creator); + config.collateral_asset.approve(extension_v3.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(config.collateral_asset.contract_address)); + + prank(CheatTarget::One(extension_v3.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v3 - .add_asset(config.pool_id_v3, asset_params, v_token_params, interest_rate_config, ekubo_oracle_params, 0); + .add_asset(config.pool_id_v3, asset_params, v_token_params, interest_rate_config, ekubo_oracle_params); stop_prank(CheatTarget::One(extension_v3.contract_address)); } #[test] - fn test_add_asset() { + fn test_add_asset_ek() { let EnvV3 { singleton, extension_v3, ekubo_core, ekubo_oracle, config, users, .. } = setup_env_v3( Zeroable::zero(), Zeroable::zero(), @@ -543,14 +584,18 @@ mod TestDefaultExtensionEK { let ekubo_oracle_params = EkuboOracleParams { period: EKUBO_TWAP_PERIOD }; + start_prank(CheatTarget::One(asset.contract_address), users.creator); + asset.approve(extension_v3.contract_address, INFLATION_FEE); + stop_prank(CheatTarget::One(asset.contract_address)); + let asset_pool_key = construct_oracle_pool_key( asset.contract_address, config.quote_asset.contract_address, ekubo_oracle.contract_address ); ekubo_core.set_pool_liquidity(asset_pool_key, integer::BoundedInt::max()); - start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); + prank(CheatTarget::One(extension_v3.contract_address), users.creator, CheatSpan::TargetCalls(1)); extension_v3 - .add_asset(config.pool_id_v3, asset_params, v_token_params, interest_rate_config, ekubo_oracle_params, 0); + .add_asset(config.pool_id_v3, asset_params, v_token_params, interest_rate_config, ekubo_oracle_params); stop_prank(CheatTarget::One(extension_v3.contract_address)); let (asset_config, _) = singleton.asset_config(config.pool_id_v3, config.collateral_asset.contract_address); @@ -1256,10 +1301,18 @@ mod TestDefaultExtensionEK { create_pool_v3(extension_v3, config, users.creator, Option::None); start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); - extension_v3.set_debt_cap(config.pool_id_v3, config.collateral_asset.contract_address, 1000); + extension_v3 + .set_debt_cap( + config.pool_id_v3, config.collateral_asset.contract_address, config.debt_asset.contract_address, 1000 + ); stop_prank(CheatTarget::One(extension_v3.contract_address)); - assert!(extension_v3.debt_caps(config.pool_id_v3, config.collateral_asset.contract_address) == 1000); + assert!( + extension_v3 + .debt_caps( + config.pool_id_v3, config.collateral_asset.contract_address, config.debt_asset.contract_address + ) == 1000 + ); } #[test] @@ -1277,8 +1330,16 @@ mod TestDefaultExtensionEK { create_pool_v3(extension_v3, config, users.creator, Option::None); - extension_v3.set_debt_cap(config.pool_id_v3, config.collateral_asset.contract_address, 1000); + extension_v3 + .set_debt_cap( + config.pool_id_v3, config.collateral_asset.contract_address, config.debt_asset.contract_address, 1000 + ); - assert!(extension_v3.debt_caps(config.pool_id_v3, config.collateral_asset.contract_address) == 1000); + assert!( + extension_v3 + .debt_caps( + config.pool_id_v3, config.collateral_asset.contract_address, config.debt_asset.contract_address + ) == 1000 + ); } } From ec0569f2d3b7552ffba30dc9eb0d96de6fdab7ab Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Fri, 20 Dec 2024 11:20:37 +0800 Subject: [PATCH 32/32] remove todo; make fn sig consistent --- src/extension/components/ekubo_oracle.cairo | 6 +++--- src/extension/default_extension_ek.cairo | 5 ++--- src/test/test_default_extension_ek.cairo | 5 ++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/extension/components/ekubo_oracle.cairo b/src/extension/components/ekubo_oracle.cairo index eff9144..a7bd6c7 100644 --- a/src/extension/components/ekubo_oracle.cairo +++ b/src/extension/components/ekubo_oracle.cairo @@ -44,7 +44,7 @@ mod ekubo_oracle_component { pool_id: felt252, asset: ContractAddress, parameter: felt252, - value: u64, + value: felt252, } #[event] @@ -168,14 +168,14 @@ mod ekubo_oracle_component { pool_id: felt252, asset: ContractAddress, parameter: felt252, - value: u64 + value: felt252 ) { let mut ekubo_oracle_config: EkuboOracleConfig = self.ekubo_oracle_configs.read((pool_id, asset)); assert!(ekubo_oracle_config.period.is_non_zero(), "ekubo-oracle-config-not-set"); if parameter == 'period' { assert!(value != 0, "invalid-ekubo-oracle-period-value"); - ekubo_oracle_config.period = value; + ekubo_oracle_config.period = value.try_into().unwrap(); } else { assert!(false, "invalid-ekubo-oracle-parameter"); } diff --git a/src/extension/default_extension_ek.cairo b/src/extension/default_extension_ek.cairo index 4e8febf..fdee352 100644 --- a/src/extension/default_extension_ek.cairo +++ b/src/extension/default_extension_ek.cairo @@ -87,9 +87,8 @@ trait IDefaultExtensionEK { fn set_interest_rate_parameter( ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u256 ); - // TODO: maybe value can't be u64 because we need to be able to update quote_token which is an address? fn set_ekubo_oracle_parameter( - ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u64 + ref self: TContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: felt252 ); fn set_liquidation_config( ref self: TContractState, @@ -724,7 +723,7 @@ mod DefaultExtensionEK { /// * `parameter` - parameter name /// * `value` - value of the parameter fn set_ekubo_oracle_parameter( - ref self: ContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: u64 + ref self: ContractState, pool_id: felt252, asset: ContractAddress, parameter: felt252, value: felt252 ) { assert!(get_caller_address() == self.owner.read(pool_id), "caller-not-owner"); self.ekubo_oracle.set_ekubo_oracle_parameter(pool_id, asset, parameter, value); diff --git a/src/test/test_default_extension_ek.cairo b/src/test/test_default_extension_ek.cairo index 29653c5..562f679 100644 --- a/src/test/test_default_extension_ek.cairo +++ b/src/test/test_default_extension_ek.cairo @@ -1046,7 +1046,7 @@ mod TestDefaultExtensionEK { create_pool_v3(extension_v3, config, users.creator, Option::None); extension_v3 - .set_ekubo_oracle_parameter(config.pool_id_v3, config.collateral_asset.contract_address, 'timeout', 5_u64); + .set_ekubo_oracle_parameter(config.pool_id_v3, config.collateral_asset.contract_address, 'timeout', 5); } #[test] @@ -1065,8 +1065,7 @@ mod TestDefaultExtensionEK { create_pool_v3(extension_v3, config, users.creator, Option::None); start_prank(CheatTarget::One(extension_v3.contract_address), users.creator); - extension_v3 - .set_ekubo_oracle_parameter(config.pool_id_v3, config.collateral_asset.contract_address, 'a', 5_u64); + extension_v3.set_ekubo_oracle_parameter(config.pool_id_v3, config.collateral_asset.contract_address, 'a', 5); stop_prank(CheatTarget::One(extension_v3.contract_address)); }