diff --git a/Deployment.md b/Deployment.md index e3ea7e1..b450a39 100644 --- a/Deployment.md +++ b/Deployment.md @@ -53,6 +53,9 @@ be triggered by a second transaction that executes the approved proposal. ./deploy.py testnet --deployer "" setup-configure-reserves ./deploy.py testnet --deployer "" setup-configure-interest-rates ./deploy.py testnet --deployer "" setup-configure-price-feeds + +(optional if gho reserve is to be configured too) +./deploy.py testnet --deployer "" setup-gho-reserve ``` ### Transfer Package Ownerships diff --git a/Makefile b/Makefile index 5f0b3dd..4bb883e 100644 --- a/Makefile +++ b/Makefile @@ -836,6 +836,14 @@ configure-price-feeds: --function-id '0x${AAVE_DATA_ADDRESS}::v1_deployment::configure_price_feeds' \ --args string:$(APTOS_NETWORK) +stup-gho-reserve: + aptos multisig create-transaction \ + --assume-yes \ + --multisig-address ${AAVE_POOL_ADMIN_MULTISIG_ADDRESS} \ + --private-key ${AAVE_POOL_ADMIN_PRIVATE_KEY} \ + --function-id '0x${AAVE_DATA_ADDRESS}::v1_deployment::setup_gho_reserve' \ + --args string:$(APTOS_NETWORK) + # ===================== GLOBAL COMMANDS ===================== # ifeq ($(APTOS_NETWORK), local) diff --git a/aave-core/aave-config/tests/is_using_as_collateral_tests.move b/aave-core/aave-config/tests/is_using_as_collateral_tests.move index a01423a..53bb11d 100644 --- a/aave-core/aave-config/tests/is_using_as_collateral_tests.move +++ b/aave-core/aave-config/tests/is_using_as_collateral_tests.move @@ -123,7 +123,7 @@ module aave_config::is_using_as_collateral_tests { j = j + 1; }; - i = i + 1; + i += 1; }; assert!(failed == 0, SUCCESS); diff --git a/aave-core/aave-data/sources/v1.move b/aave-core/aave-data/sources/v1.move index 27d3467..6a018e6 100644 --- a/aave-core/aave-data/sources/v1.move +++ b/aave-core/aave-data/sources/v1.move @@ -9,7 +9,7 @@ module aave_data::v1 { use std::string::{String, utf8}; use std::vector; use aptos_std::smart_table; - use std::option::Option; + use std::option::{Self, Option}; // locals use aave_config::error_config; @@ -194,11 +194,20 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let val = *smart_table::borrow(table, key); vector::push_back(&mut views, val); - i = i + 1; + i += 1; }; (keys, views) } + /// @notice Gets the price feed for a specific asset on testnet + public fun get_price_feeds_testnet_for_asset(asset: String): Option> acquires Data { + let table = &borrow_global(@aave_data).price_feeds_testnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, asset)) + } + /// @notice Gets the price feeds for mainnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset symbols, price feed addresses) public fun get_price_feeds_mainnet_normalized(): (vector, vector>) acquires Data { @@ -211,11 +220,19 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let val = *smart_table::borrow(table, key); vector::push_back(&mut views, val); - i = i + 1; + i += 1; }; (keys, views) } + public fun get_price_feeds_mainnet_for_asset(asset: String): Option> acquires Data { + let table = &borrow_global(@aave_data).price_feeds_mainnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, asset)) + } + /// @notice Gets the underlying assets for testnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset symbols, underlying asset addresses) public fun get_underlying_assets_testnet_normalized(): (vector, vector
) acquires Data { @@ -228,11 +245,19 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let val = *smart_table::borrow(table, key); vector::push_back(&mut views, val); - i = i + 1; + i += 1; }; (keys, views) } + public fun get_underlying_for_asset_testnet(asset: String): Option
acquires Data { + let table = &borrow_global(@aave_data).underlying_assets_testnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, asset)) + } + /// @notice Gets the underlying assets for mainnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset symbols, underlying asset addresses) public fun get_underlying_assets_mainnet_normalized(): (vector, vector
) acquires Data { @@ -245,11 +270,19 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let val = *smart_table::borrow(table, key); vector::push_back(&mut views, val); - i = i + 1; + i += 1; }; (keys, views) } + public fun get_underlying_for_asset_mainnet(asset: String): Option
acquires Data { + let table = &borrow_global(@aave_data).underlying_assets_mainnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, asset)) + } + /// @notice Gets the reserve configurations for testnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset symbols, reserve configurations) public fun get_reserves_config_testnet_normalized(): ( @@ -264,11 +297,21 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let val = *smart_table::borrow(table, key); vector::push_back(&mut views, val); - i = i + 1; + i += 1; }; (keys, views) } + public fun get_reserves_config_for_asset_testnet( + asset: String + ): Option acquires Data { + let table = &borrow_global(@aave_data).reserves_config_testnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, asset)) + } + /// @notice Gets the reserve configurations for mainnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset symbols, reserve configurations) public fun get_reserves_config_mainnet_normalized(): ( @@ -283,11 +326,21 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let val = *smart_table::borrow(table, key); vector::push_back(&mut views, val); - i = i + 1; + i += 1; }; (keys, views) } + public fun get_reserves_config_for_asset_mainnet( + asset: String + ): Option acquires Data { + let table = &borrow_global(@aave_data).reserves_config_mainnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, asset)) + } + /// @notice Gets the interest rate strategies for testnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset symbols, interest rate strategies) public fun get_interest_rate_strategy_testnet_normalized(): ( @@ -302,11 +355,21 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let val = *smart_table::borrow(table, key); vector::push_back(&mut views, val); - i = i + 1; + i += 1; }; (keys, views) } + public fun get_interest_rate_strategy_for_asset_testnet( + asset: String + ): Option acquires Data { + let table = &borrow_global(@aave_data).interest_rate_strategy_testnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, asset)) + } + /// @notice Gets the interest rate strategies for mainnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset symbols, interest rate strategies) public fun get_interest_rate_strategy_mainnet_normalized(): ( @@ -321,11 +384,21 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let val = *smart_table::borrow(table, key); vector::push_back(&mut views, val); - i = i + 1; + i += 1; }; (keys, views) } + public fun get_interest_rate_strategy_for_asset_mainnet( + asset: String + ): Option acquires Data { + let table = &borrow_global(@aave_data).interest_rate_strategy_mainnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, asset)) + } + /// @notice Gets the E-modes for mainnet in normalized format (keys and values as separate vectors) /// @return Tuple of (E-mode IDs, E-mode configurations) public fun get_emodes_mainnet_normalized(): ( @@ -340,11 +413,21 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let config = *smart_table::borrow(emodes, key); vector::push_back(&mut configs, config); - i = i + 1; + i += 1; }; (keys, configs) } + public fun get_emodes_for_asset_mainnet( + emode: u256 + ): Option acquires Data { + let table = &borrow_global(@aave_data).emodes_mainnet; + if (!smart_table::contains(table, emode)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, emode)) + } + /// @notice Gets the E-modes for testnet in normalized format (keys and values as separate vectors) /// @return Tuple of (E-mode IDs, E-mode configurations) public fun get_emode_testnet_normalized(): ( @@ -359,11 +442,21 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let config = *smart_table::borrow(emodes, key); vector::push_back(&mut configs, config); - i = i + 1; + i += 1; }; (keys, configs) } + public fun get_emodes_for_asset_testnet( + emode: u256 + ): Option acquires Data { + let table = &borrow_global(@aave_data).emodes_testnet; + if (!smart_table::contains(table, emode)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, emode)) + } + /// @notice Gets the asset max price ages for testnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset name, max_price_age) public fun get_asset_max_price_ages_testnet_normalized(): (vector, vector) acquires Data { @@ -377,11 +470,19 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let config = *smart_table::borrow(asset_max_price_age, key); vector::push_back(&mut asset_max_price_ages, config); - i = i + 1; + i += 1; }; (keys, asset_max_price_ages) } + public fun get_asset_max_price_ages_for_asset_testnet(asset: String): Option acquires Data { + let table = &borrow_global(@aave_data).asset_max_price_age_testnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, asset)) + } + /// @notice Gets the asset max price ages for mainnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset name, max_price_age) public fun get_asset_max_price_ages_mainnet_normalized(): (vector, vector) acquires Data { @@ -395,11 +496,19 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let config = *smart_table::borrow(asset_max_price_age, key); vector::push_back(&mut asset_max_price_ages, config); - i = i + 1; + i += 1; }; (keys, asset_max_price_ages) } + public fun get_asset_max_price_ages_for_asset_mainnet(asset: String): Option acquires Data { + let table = &borrow_global(@aave_data).asset_max_price_age_mainnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + option::some(*smart_table::borrow(table, asset)) + } + /// @notice Gets the oracle configs for the assets on testnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset symbols, asset oracle configs) public fun get_oracle_configs_testnet_normalized(): ( @@ -414,11 +523,21 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let val = *smart_table::borrow(table, key); vector::push_back(&mut views, val); - i = i + 1; + i += 1; }; (keys, views) } + public fun get_oracle_configs_for_asset_testnet( + asset: String + ): Option acquires Data { + let table = &borrow_global(@aave_data).oracle_configs_testnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + *smart_table::borrow(table, asset) + } + /// @notice Gets the oracle configs for the assets on mainnet in normalized format (keys and values as separate vectors) /// @return Tuple of (asset symbols, asset oracle configs) public fun get_oracle_configs_mainnet_normalized(): ( @@ -433,11 +552,21 @@ module aave_data::v1 { let key = *vector::borrow(&keys, i); let val = *smart_table::borrow(table, key); vector::push_back(&mut views, val); - i = i + 1; + i += 1; }; (keys, views) } + public fun get_oracle_configs_for_asset_mainnet( + asset: String + ): Option acquires Data { + let table = &borrow_global(@aave_data).oracle_configs_mainnet; + if (!smart_table::contains(table, asset)) { + return option::none(); + }; + *smart_table::borrow(table, asset) + } + /// @notice Gets all acl accounts for testnet /// @return Tuple of addresses vectors public fun get_acl_accounts_testnet(): ( diff --git a/aave-core/aave-data/sources/v1_deployment.move b/aave-core/aave-data/sources/v1_deployment.move index 02b1374..fa87c28 100644 --- a/aave-core/aave-data/sources/v1_deployment.move +++ b/aave-core/aave-data/sources/v1_deployment.move @@ -14,6 +14,7 @@ module aave_data::v1_deployment { use aptos_framework::fungible_asset; use aptos_framework::fungible_asset::Metadata; use aptos_framework::object; + use aave_data::v1_values::Self; // locals use aave_acl::acl_manage; @@ -827,4 +828,337 @@ module aave_data::v1_deployment { }; print(&format1(&b"Finished configuring price feeds! {}", 1)); } + + /// @notice Method to set up GHO pool reserve with appropriate tokens and parameters + /// @param account The signer account executing the method (must be an asset listing admin or pool admin) + /// @param network The network identifier ("mainnet" or "testnet") + public entry fun setup_gho_reserve(account: &signer, network: String) { + // Verify the caller has appropriate permissions + assert!( + acl_manage::is_asset_listing_admin(signer::address_of(account)) + || acl_manage::is_pool_admin(signer::address_of(account)), + error_config::get_ecaller_not_asset_listing_or_pool_admin() + ); + + // ============================= INITIALIZE GHO RESERVE ======================================== // + + print(&format1(&b"Initializing {} reserve ... {}", v1_values::get_gho_asset())); + // Get underlying assets based on the specified network + let underlying_asset_address = + if (network == utf8(APTOS_MAINNET)) { + aave_data::v1::get_underlying_for_asset_mainnet( + v1_values::get_gho_asset() + ) + } else if (network == utf8(APTOS_TESTNET)) { + aave_data::v1::get_underlying_for_asset_testnet( + v1_values::get_gho_asset() + ) + } else { + print( + &format1(&b"Unsupported network - {}. Using testnet values", network) + ); + aave_data::v1::get_underlying_for_asset_testnet( + v1_values::get_gho_asset() + ) + }; + let underlying_asset_address = *option::borrow(&underlying_asset_address); + let underlying_asset_metadata = + object::address_to_object(underlying_asset_address); + let underlying_asset_symbol = fungible_asset::symbol(underlying_asset_metadata); + let underlying_asset_decimals = + fungible_asset::decimals(underlying_asset_metadata); + + // atokens + let atoken_name = aave_data::v1::get_atoken_name(underlying_asset_symbol); + let atoken_symbol = aave_data::v1::get_atoken_symbol(underlying_asset_symbol); + + // var tokens + let var_token_name = aave_data::v1::get_vartoken_name(underlying_asset_symbol); + let var_token_symbol = + aave_data::v1::get_vartoken_symbol(underlying_asset_symbol); + + // treasury + let treasury = collector::collector_address(); + + // Get interest rate strategies based on the specified network + let interest_rate_strategy = + if (network == utf8(APTOS_MAINNET)) { + aave_data::v1::get_interest_rate_strategy_for_asset_mainnet( + v1_values::get_gho_asset() + ) + } else if (network == utf8(APTOS_TESTNET)) { + aave_data::v1::get_interest_rate_strategy_for_asset_testnet( + v1_values::get_gho_asset() + ) + } else { + print( + &format1(&b"Unsupported network - {}. Using testnet values", network) + ); + aave_data::v1::get_interest_rate_strategy_for_asset_testnet( + v1_values::get_gho_asset() + ) + }; + let interest_rate_strategy = *option::borrow(&interest_rate_strategy); + let optimal_usage_ratio = + aave_data::v1_values::get_optimal_usage_ratio(&interest_rate_strategy); + let base_variable_borrow_rate = + aave_data::v1_values::get_base_variable_borrow_rate( + &interest_rate_strategy + ); + let variable_rate_slope1 = + aave_data::v1_values::get_variable_rate_slope1(&interest_rate_strategy); + let variable_rate_slope2: u256 = + aave_data::v1_values::get_variable_rate_slope2(&interest_rate_strategy); + + // incentives controller + let incentives_controller = option::none(); + + // Initialize the gho reserve in a single transaction + print(&format1(&b"Initializing GHO reserve ... {}", 1)); + pool_configurator::init_reserves( + account, + vector[underlying_asset_address], + vector[treasury], + vector[atoken_name], + vector[atoken_symbol], + vector[var_token_name], + vector[var_token_symbol], + vector[incentives_controller], + vector[optimal_usage_ratio], + vector[base_variable_borrow_rate], + vector[variable_rate_slope1], + vector[variable_rate_slope2] + ); + print(&format1(&b"Finished initializing GHO reserve! {}", 1)); + + // Verifications + // Verify asset exists in pool + assert!(pool::asset_exists(underlying_asset_address), DEPLOYMENT_SUCCESS); + + // Get reserve data and associated token addresses + let reserve_data = pool::get_reserve_data(underlying_asset_address); + let a_token_address = pool::get_reserve_a_token_address(reserve_data); + let var_token_address = + pool::get_reserve_variable_debt_token_address(reserve_data); + + // Verify no accrued interest to treasury at deployment + assert!( + pool::get_reserve_accrued_to_treasury(reserve_data) == 0, + DEPLOYMENT_SUCCESS + ); + + // Verify token contracts are properly deployed + assert!(a_token_factory::is_atoken(a_token_address), DEPLOYMENT_SUCCESS); + assert!( + variable_debt_token_factory::is_variable_debt_token(var_token_address), + DEPLOYMENT_SUCCESS + ); + + // Verify no collected fees at deployment + assert!(collector::get_collected_fees(a_token_address) == 0, DEPLOYMENT_SUCCESS); + print(&format1(&b"Finished initializing {} reserve!", v1_values::get_gho_asset())); + + // ============================= APPLY GHO RESERVE CONFIGURATION ======================================== // + + print(&format1(&b"Configuring {} reserve ... ", v1_values::get_gho_asset())); + // read the gho reserve config + let reserve_config = + if (network == utf8(APTOS_MAINNET)) { + aave_data::v1::get_reserves_config_for_asset_mainnet( + v1_values::get_gho_asset() + ) + } else if (network == utf8(APTOS_TESTNET)) { + aave_data::v1::get_reserves_config_for_asset_testnet( + v1_values::get_gho_asset() + ) + } else { + print( + &format1(&b"Unsupported network - {}. Using testnet values", network) + ); + aave_data::v1::get_reserves_config_for_asset_testnet( + v1_values::get_gho_asset() + ) + }; + + // Extract configuration parameters for this reserve + let reserve_config = option::borrow(&reserve_config); + let debt_ceiling = aave_data::v1_values::get_debt_ceiling(reserve_config); + let flashLoan_enabled = + aave_data::v1_values::get_flashLoan_enabled(reserve_config); + let borrowable_isolation = + aave_data::v1_values::get_borrowable_isolation(reserve_config); + let supply_cap = aave_data::v1_values::get_supply_cap(reserve_config); + let borrow_cap = aave_data::v1_values::get_borrow_cap(reserve_config); + let ltv = aave_data::v1_values::get_base_ltv_as_collateral(reserve_config); + let borrowing_enabled = + aave_data::v1_values::get_borrowing_enabled(reserve_config); + let reserve_factor = aave_data::v1_values::get_reserve_factor(reserve_config); + let liquidation_threshold = + aave_data::v1_values::get_liquidation_threshold(reserve_config); + let liquidation_bonus = + aave_data::v1_values::get_liquidation_bonus(reserve_config); + let liquidation_protocol_fee = + aave_data::v1_values::get_liquidation_protocol_fee(reserve_config); + let siloed_borrowing = aave_data::v1_values::get_siloed_borrowing(reserve_config); + + // Create and populate new reserve configuration + let reserve_config_new = reserve_config::init(); + + // Set basic parameters + reserve_config::set_decimals( + &mut reserve_config_new, (underlying_asset_decimals as u256) + ); + reserve_config::set_active(&mut reserve_config_new, true); + reserve_config::set_frozen(&mut reserve_config_new, false); + reserve_config::set_paused(&mut reserve_config_new, false); + + // Set liquidation parameters + reserve_config::set_liquidation_threshold( + &mut reserve_config_new, liquidation_threshold + ); + reserve_config::set_liquidation_bonus(&mut reserve_config_new, liquidation_bonus); + reserve_config::set_liquidation_protocol_fee( + &mut reserve_config_new, liquidation_protocol_fee + ); + + // Set financial parameters + reserve_config::set_reserve_factor(&mut reserve_config_new, reserve_factor); + reserve_config::set_ltv(&mut reserve_config_new, ltv); + reserve_config::set_debt_ceiling(&mut reserve_config_new, debt_ceiling); + reserve_config::set_supply_cap(&mut reserve_config_new, supply_cap); + reserve_config::set_borrow_cap(&mut reserve_config_new, borrow_cap); + + // Set feature flags + reserve_config::set_flash_loan_enabled( + &mut reserve_config_new, flashLoan_enabled + ); + reserve_config::set_borrowable_in_isolation( + &mut reserve_config_new, borrowable_isolation + ); + reserve_config::set_siloed_borrowing(&mut reserve_config_new, siloed_borrowing); + reserve_config::set_borrowing_enabled(&mut reserve_config_new, borrowing_enabled); + + // Configure E-Mode category if applicable + let emode_category = aave_data::v1_values::get_emode_category(reserve_config); + if (option::is_some(&emode_category)) { + // Set E-Mode category in the reserve configuration + reserve_config::set_emode_category( + &mut reserve_config_new, *option::borrow(&emode_category) + ); + + // Set the asset's E-Mode category in the pool + pool_configurator::set_asset_emode_category( + account, + underlying_asset_address, + (*option::borrow(&emode_category) as u8) + ); + }; + + // Apply the configuration to the reserve + aave_pool::pool::set_reserve_configuration_with_guard( + account, underlying_asset_address, reserve_config_new + ); + print(&format1(&b"Finished configuring {} reserve!", v1_values::get_gho_asset())); + + // ============================= CONFIGURE INTEREST RATE STRATEGY ======================================== // + + print( + &format1( + &b"Configuring {} interest rate strategies ...", + v1_values::get_gho_asset() + ) + ); + // Update the interest rate strategy for this asset in the pool + pool_configurator::update_interest_rate_strategy( + account, + underlying_asset_address, + optimal_usage_ratio, + base_variable_borrow_rate, + variable_rate_slope1, + variable_rate_slope2 + ); + print( + &format1( + &b"Finished configuring interest rate strategies for {}", + v1_values::get_gho_asset() + ) + ); + + // ============================= CONFIGURE PRICE FEEDS + ORACLE ======================================== // + + print( + &format1( + &b"Configuring {} price and oracle ... {}", v1_values::get_gho_asset() + ) + ); + // Fetch maximum price age for gho based on the specified network + let max_price_age = + if (network == utf8(APTOS_MAINNET)) { + aave_data::v1::get_asset_max_price_ages_for_asset_mainnet( + v1_values::get_gho_asset() + ) + } else if (network == utf8(APTOS_TESTNET)) { + aave_data::v1::get_asset_max_price_ages_for_asset_testnet( + v1_values::get_gho_asset() + ) + } else { + print( + &format1(&b"Unsupported network - {}. Using testnet values", network) + ); + aave_data::v1::get_asset_max_price_ages_for_asset_testnet( + v1_values::get_gho_asset() + ) + }; + let max_price_age = *option::borrow(&max_price_age); + + // fetch gho price configuration + let asset_oracle_config = + if (network == utf8(APTOS_MAINNET)) { + aave_data::v1::get_oracle_configs_for_asset_mainnet( + v1_values::get_gho_asset() + ) + } else if (network == utf8(APTOS_TESTNET)) { + aave_data::v1::get_oracle_configs_for_asset_testnet( + v1_values::get_gho_asset() + ) + } else { + print( + &format1(&b"Unsupported network - {}. Using testnet values", network) + ); + aave_data::v1::get_oracle_configs_for_asset_testnet( + v1_values::get_gho_asset() + ) + }; + + // Set adapter type + assert!(asset_oracle_config.is_some(), DEPLOYMENT_SUCCESS); + let capped_asset_data = option::borrow(&asset_oracle_config); + let stable_price_cap = + *option::borrow( + &aave_data::v1_values::get_stable_price_cap(capped_asset_data) + ); + oracle::set_price_cap_stable_adapter( + account, underlying_asset_address, stable_price_cap + ); + // Verify stable price cap is set + assert!( + option::is_some(&oracle::get_stable_price_cap(underlying_asset_address)), + DEPLOYMENT_SUCCESS + ); + // set max age + oracle::set_max_asset_price_age( + account, underlying_asset_address, max_price_age + ); + // Verify the price is working correctly + assert!( + oracle::get_asset_price(underlying_asset_address) > 0, + DEPLOYMENT_SUCCESS + ); + print( + &format1( + &b"Finished configuring {} price and oracle! {}", + v1_values::get_gho_asset() + ) + ); + } } diff --git a/aave-core/aave-data/sources/v1_values.move b/aave-core/aave-data/sources/v1_values.move index dc8d29e..55d05a3 100644 --- a/aave-core/aave-data/sources/v1_values.move +++ b/aave-core/aave-data/sources/v1_values.move @@ -26,6 +26,8 @@ module aave_data::v1_values { const USDT_ASSET: vector = b"USDT"; /// @notice Asset symbol for sUSDe const SUSDE_ASSET: vector = b"sUSDe"; + /// @notice Asset symbol for GHO + const GHO_ASSET: vector = b"GHO"; // Structs /// @notice Configuration parameters for a reserve @@ -87,7 +89,8 @@ module aave_data::v1_values { /// @notice The type of adapter for retrieving the price enum AdapterType has copy, drop, store { STABLE, - SUSDE + SUSDE, + GHO } /// @notice Main storage for multiple capped asset data @@ -113,6 +116,37 @@ module aave_data::v1_values { } // Public functions - EmodeConfig getters + + /// @notice Get the APT asset symbol + /// @return The APT asset symbol + public fun get_apt_asset(): String { + string::utf8(APT_ASSET) + } + + /// @notice Get the USDC asset symbol + /// @return The USDC asset symbol + public fun get_usdc_asset(): String { + string::utf8(USDC_ASSET) + } + + /// @notice Get the USDT asset symbol + /// @return The USDT asset symbol + public fun get_usdt_asset(): String { + string::utf8(USDT_ASSET) + } + + /// @notice Get the SUSDE asset symbol + /// @return The SUSDE asset symbol + public fun get_susde_asset(): String { + string::utf8(SUSDE_ASSET) + } + + /// @notice Get the GHO asset symbol + /// @return The GHO asset symbol + public fun get_gho_asset(): String { + string::utf8(GHO_ASSET) + } + /// @notice Get the E-Mode category ID /// @param emode_config The E-Mode configuration /// @return The category ID @@ -287,7 +321,8 @@ module aave_data::v1_values { public fun is_stable_adapter(capped_asset_data: &CappedAssetData): bool { match(capped_asset_data.type) { AdapterType::STABLE => true, - AdapterType::SUSDE => false + AdapterType::SUSDE => false, + AdapterType::GHO => false } } @@ -297,7 +332,8 @@ module aave_data::v1_values { public fun is_susde_adapter(capped_asset_data: &CappedAssetData): bool { match(capped_asset_data.type) { AdapterType::STABLE => false, - AdapterType::SUSDE => true + AdapterType::SUSDE => true, + AdapterType::GHO => false } } @@ -627,6 +663,26 @@ module aave_data::v1_values { } ) ); + smart_table::upsert( + &mut oracle_config, + utf8(GHO_ASSET), + option::some( + CappedAssetData { + type: AdapterType::GHO, + stable_price_cap: option::some( + (100 * price_scaling_factor) / 100 + ), // 1.0 USD + ratio_decimals: option::none(), + minimum_snapshot_delay: option::none(), + snapshot_timestamp: option::none(), + max_yearly_ratio_growth_percent: option::none(), + max_ratio_growth_per_second: option::none(), + snapshot_ratio: option::none(), + mapped_asset_ratio_multiplier: option::none
() + } + ) + ); + oracle_config } @@ -703,6 +759,26 @@ module aave_data::v1_values { } ) ); + smart_table::upsert( + &mut oracle_config, + utf8(GHO_ASSET), + option::some( + CappedAssetData { + type: AdapterType::GHO, + stable_price_cap: option::some( + (100 * price_scaling_factor) / 100 + ), // 1.0 USD + ratio_decimals: option::none(), + minimum_snapshot_delay: option::none(), + snapshot_timestamp: option::none(), + max_yearly_ratio_growth_percent: option::none(), + max_ratio_growth_per_second: option::none(), + snapshot_ratio: option::none(), + mapped_asset_ratio_multiplier: option::none
() + } + ) + ); + oracle_config } @@ -784,6 +860,11 @@ module aave_data::v1_values { string::utf8(SUSDE_ASSET), 45 * 60 // 45 minutes ); + smart_table::add( + &mut asset_max_price_ages_testnet, + string::utf8(GHO_ASSET), + 45 * 60 // 45 minutes + ); asset_max_price_ages_testnet } @@ -811,6 +892,11 @@ module aave_data::v1_values { string::utf8(SUSDE_ASSET), 45 * 60 // 45 minutes ); + smart_table::add( + &mut asset_max_price_ages_mainnet, + string::utf8(GHO_ASSET), + 45 * 60 // 45 minutes + ); asset_max_price_ages_mainnet } @@ -837,6 +923,11 @@ module aave_data::v1_values { utf8(SUSDE_ASSET), @0x8e67e42c4ff61e16dca908b737d1260b312143c1f7ba1577309f075a27cb4d90 ); + smart_table::upsert( + &mut underlying_assets_testnet, + utf8(GHO_ASSET), + @0x0 // TODO: fix address + ); underlying_assets_testnet } @@ -863,6 +954,11 @@ module aave_data::v1_values { utf8(SUSDE_ASSET), @0xb30a694a344edee467d9f82330bbe7c3b89f440a1ecd2da1f3bca266560fce69 ); + smart_table::upsert( + &mut underlying_assets_mainnet, + utf8(GHO_ASSET), + @0x0 // TODO: fix address + ); underlying_assets_mainnet } @@ -954,6 +1050,28 @@ module aave_data::v1_values { emode_category: option::some(1) // ok } ); + smart_table::upsert(// TODO: fix it + &mut reserve_config, + utf8(GHO_ASSET), + ReserveConfig { + base_ltv_as_collateral: (75 * math_utils::get_percentage_factor()) / 100, // ok + liquidation_threshold: (78 * math_utils::get_percentage_factor()) / 100, // ok + liquidation_bonus: math_utils::get_percentage_factor() + + (5 * math_utils::get_percentage_factor()) / 100, // ok + liquidation_protocol_fee: (10 * math_utils::get_percentage_factor()) + / 100, // ok + borrowing_enabled: true, // ok + flashLoan_enabled: true, // ok + reserve_factor: (10 * math_utils::get_percentage_factor()) / 100, // ok + supply_cap: 25_000, // ok + borrow_cap: 23_125, // ok + debt_ceiling: 0, // ok + borrowable_isolation: true, // ok + siloed_borrowing: false, // ok + emode_category: option::some(1) // ok + } + ); + reserve_config } @@ -1045,6 +1163,28 @@ module aave_data::v1_values { emode_category: option::some(1) // ok } ); + smart_table::upsert(// TODO: fix it + &mut reserve_config, + utf8(GHO_ASSET), + ReserveConfig { + base_ltv_as_collateral: (75 * math_utils::get_percentage_factor()) / 100, // ok + liquidation_threshold: (78 * math_utils::get_percentage_factor()) / 100, // ok + liquidation_bonus: math_utils::get_percentage_factor() + + (5 * math_utils::get_percentage_factor()) / 100, // ok + liquidation_protocol_fee: (10 * math_utils::get_percentage_factor()) + / 100, // ok + borrowing_enabled: true, // ok + flashLoan_enabled: true, // ok + reserve_factor: (10 * math_utils::get_percentage_factor()) / 100, // ok + supply_cap: 25_000, // ok + borrow_cap: 23_125, // ok + debt_ceiling: 0, // ok + borrowable_isolation: true, // ok + siloed_borrowing: false, // ok + emode_category: option::some(1) // ok + } + ); + reserve_config } @@ -1093,6 +1233,16 @@ module aave_data::v1_values { variable_rate_slope2: ((40 * math_utils::get_percentage_factor()) / 100) } ); + smart_table::upsert(// TODO: fix me + &mut interest_rate_config, + utf8(GHO_ASSET), + InterestRateStrategy { + optimal_usage_ratio: ((90 * math_utils::get_percentage_factor()) / 100), + base_variable_borrow_rate: 0, // ok + variable_rate_slope1: ((6 * math_utils::get_percentage_factor()) / 100), + variable_rate_slope2: ((40 * math_utils::get_percentage_factor()) / 100) + } + ); interest_rate_config } @@ -1141,6 +1291,17 @@ module aave_data::v1_values { variable_rate_slope2: ((40 * math_utils::get_percentage_factor()) / 100) } ); + smart_table::upsert(// TODO: fix me + &mut interest_rate_config, + utf8(GHO_ASSET), + InterestRateStrategy { + optimal_usage_ratio: ((90 * math_utils::get_percentage_factor()) / 100), // ok + base_variable_borrow_rate: 0, // ok + variable_rate_slope1: ((6 * math_utils::get_percentage_factor()) / 100), // ok + variable_rate_slope2: ((40 * math_utils::get_percentage_factor()) / 100) // ok + } + ); + interest_rate_config } } diff --git a/aave-core/aave-large-packages/sources/large_packages.move b/aave-core/aave-large-packages/sources/large_packages.move index 3d42bb8..9689e83 100644 --- a/aave-core/aave-large-packages/sources/large_packages.move +++ b/aave-core/aave-large-packages/sources/large_packages.move @@ -186,7 +186,7 @@ module aave_large_packages::large_packages { staging_area.last_module_idx = idx; } }; - i = i + 1; + i += 1; }; staging_area @@ -244,7 +244,7 @@ module aave_large_packages::large_packages { &mut code, *smart_table::borrow(&staging_area.code, i) ); - i = i + 1; + i += 1; }; code } diff --git a/aave-core/aave-oracle/sources/oracle.move b/aave-core/aave-oracle/sources/oracle.move index 459ad0d..acf7cba 100644 --- a/aave-core/aave-oracle/sources/oracle.move +++ b/aave-core/aave-oracle/sources/oracle.move @@ -52,7 +52,8 @@ module aave_oracle::oracle { /// @notice The type of adapter for retrieving the price enum AdapterType has copy, drop, store { STABLE, - SUSDE + SUSDE, + GHO } // Event definitions @@ -224,7 +225,8 @@ module aave_oracle::oracle { underlying_asset_price, &cap_info ); is_capped - } + }, + AdapterType::GHO => false } } @@ -261,7 +263,8 @@ module aave_oracle::oracle { let cap_info = smart_table::borrow(capped_assets_data, asset); return match(cap_info.type) { AdapterType::SUSDE => { option::none() }, - AdapterType::STABLE => { cap_info.stable_price_cap } + AdapterType::STABLE => { cap_info.stable_price_cap }, + AdapterType::GHO => { option::none() } } } @@ -331,6 +334,12 @@ module aave_oracle::oracle { underlying_asset_price, &cap_info ); (underlying_asset_capped_price, underlying_asset_timestamp) + }, + AdapterType::GHO => { + ( + 1 * math_utils::pow(10, (get_asset_price_decimals() as u256)), + (timestamp::now_seconds() as u256) + ) } } } @@ -591,6 +600,13 @@ module aave_oracle::oracle { custom_price <= max_ratio, error_config::get_ecustom_price_above_price_cap() ); + }, + AdapterType::GHO => { + let (capped_price, _) = get_asset_price_and_timestamp(asset); + assert!( + custom_price <= capped_price, + error_config::get_ecustom_price_above_price_cap() + ); } } } diff --git a/aave-core/sources/aave-logic/generic_logic.move b/aave-core/sources/aave-logic/generic_logic.move index 705dc19..ef75209 100644 --- a/aave-core/sources/aave-logic/generic_logic.move +++ b/aave-core/sources/aave-logic/generic_logic.move @@ -108,14 +108,14 @@ module aave_pool::generic_logic { let i = 0; while (i < reserves_count) { if (!user_config::is_using_as_collateral_or_borrowing(user_config_map, i)) { - i = i + 1; + i += 1; continue }; let current_reserve_address = pool::get_reserve_address_by_id(i); // `get_reserve_address_by_id` returns @0x0 if the id does not exist if (current_reserve_address == @0x0) { - i = i + 1; + i += 1; continue }; @@ -174,7 +174,7 @@ module aave_pool::generic_logic { total_debt_in_base_currency + user_debt_in_base_currency; }; - i = i + 1; + i += 1; }; if (total_collateral_in_base_currency != 0) { diff --git a/aave-core/tests/aave-logic/borrow_logic_tests.move b/aave-core/tests/aave-logic/borrow_logic_tests.move index 848c0a6..1cd77e0 100644 --- a/aave-core/tests/aave-logic/borrow_logic_tests.move +++ b/aave-core/tests/aave-logic/borrow_logic_tests.move @@ -1834,7 +1834,7 @@ module aave_pool::borrow_logic_tests { 0, user2_address ); - i = i + 1; + i += 1; }; // Verify total debt (10 * 0.1 = 1 unit, but each 0.1 rounds up to 1 debt unit) @@ -1861,7 +1861,7 @@ module aave_pool::borrow_logic_tests { 2, user2_address ); - i = i + 1; + i += 1; }; // Verify debt is back to zero (consistent rounding) diff --git a/aave-core/tests/aave-logic/directional_rounding_tests.move b/aave-core/tests/aave-logic/directional_rounding_tests.move index 10240ac..073e505 100644 --- a/aave-core/tests/aave-logic/directional_rounding_tests.move +++ b/aave-core/tests/aave-logic/directional_rounding_tests.move @@ -2166,7 +2166,7 @@ module aave_pool::directional_rounding_tests { 0 ); - i = i + 1; + i += 1; }; let final_treasury = pool::get_reserve_accrued_to_treasury(reserve_data); @@ -3884,7 +3884,7 @@ module aave_pool::directional_rounding_tests { j = j + 1; }; - i = i + 1; + i += 1; }; } @@ -3926,7 +3926,7 @@ module aave_pool::directional_rounding_tests { let down = wad_ray_math::ray_mul_down(val, wad_ray_math::ray()); let up = wad_ray_math::ray_mul_up(val, wad_ray_math::ray()); assert!(down <= up, 10 + i); - i = i + 1; + i += 1; }; } } diff --git a/deploy.py b/deploy.py index 2a5520f..69a1473 100755 --- a/deploy.py +++ b/deploy.py @@ -1204,6 +1204,20 @@ def setup_configure_price_feeds( ) +def setup_gho_reserve( + deployer: str, fullnode: str, multisig_pool_admin: str, network: str +) -> int: + logging.info("Setup: gho reserve") + + aave_data_address = _get_deployed_address("aave_data") + return _create_multisig_transaction( + deployer, + fullnode, + multisig_pool_admin, + f"{aave_data_address}::v1_deployment::setup_gho_reserve", + [f"string:{network}"], + ) + def setup_all_localnet( deployer: str, fullnode: str, multisig_pool_admin: str, network: str ) -> None: @@ -1231,6 +1245,9 @@ def setup_all_localnet( setup_configure_price_feeds(deployer, fullnode, multisig_pool_admin, network) execute_multisig_on_localnet(deployer, fullnode, multisig_pool_admin) + setup_gho_reserve(deployer, fullnode, multisig_pool_admin, network) + execute_multisig_on_localnet(deployer, fullnode, multisig_pool_admin) + # # Utilities on deployment to local testnet @@ -2084,6 +2101,13 @@ def main() -> None: args.multisig_pool_admin, "testnet", ) + elif args.testnet_command == "setup-gho-reserve": + setup_gho_reserve( + args.deployer, + args.fullnode, + args.multisig_pool_admin, + "testnet", + ) # handle ownership commands elif args.testnet_command == "change-owner-config": @@ -2268,6 +2292,13 @@ def main() -> None: args.multisig_pool_admin, "mainnet", ) + elif args.mainnet_command == "setup-gho-reserve": + setup_gho_reserve( + args.deployer, + args.fullnode, + args.multisig_pool_admin, + "mainnet", + ) # handle ownership commands elif args.mainnet_command == "change-owner-config":