Skip to content

Commit

Permalink
feat: use a specific block number for all eth calls in the strategy e…
Browse files Browse the repository at this point in the history
…xecute
  • Loading branch information
EmperorOrokuSaki committed Aug 8, 2024
1 parent 55449eb commit bc85d68
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 19 deletions.
51 changes: 37 additions & 14 deletions ir_manager/src/strategy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
evm_rpc::{RpcService, Service},
state::{MANAGERS, STRATEGY_DATA, TOLERANCE_MARGIN_DOWN, TOLERANCE_MARGIN_UP},
types::*,
utils::{decode_response, eth_call_args, rpc_provider},
utils::{decode_response, eth_call_args, get_block_number, rpc_provider},
};

#[derive(Clone)]
Expand Down Expand Up @@ -124,18 +124,20 @@ impl StrategyData {
// Lock the strategy
self.lock()?;

let time_since_last_update = U256::from(time() - self.last_update); // what unit should this be in? millis? secs?
let block_number = get_block_number(&self.rpc_canister, &self.rpc_url).await?;

let entire_system_debt: U256 = self.fetch_entire_system_debt().await?;
let time_since_last_update = U256::from(time() - self.last_update);

let entire_system_debt: U256 = self.fetch_entire_system_debt(&block_number).await?;
let unbacked_portion_price_and_redeemability = self
.fetch_unbacked_portion_price_and_redeemablity(None)
.fetch_unbacked_portion_price_and_redeemablity(None, &block_number)
.await?;

let mut troves: Vec<CombinedTroveData> = vec![];
let mut troves_index = U256::from(0);
loop {
let fetched_troves = self
.fetch_multiple_sorted_troves(troves_index, U256::from(1500))
.fetch_multiple_sorted_troves(troves_index, U256::from(1500), &block_number)
.await?;
let fetched_troves_count = fetched_troves.len();
troves.extend(fetched_troves);
Expand All @@ -145,10 +147,10 @@ impl StrategyData {
troves_index += U256::from(1500);
}

let redemption_fee = self.fetch_redemption_rate().await?;
let redemption_fee = self.fetch_redemption_rate(&block_number).await?;
let redemption_split = unbacked_portion_price_and_redeemability._0
/ self
.fetch_total_unbacked(unbacked_portion_price_and_redeemability._0)
.fetch_total_unbacked(unbacked_portion_price_and_redeemability._0, &block_number)
.await?;
let target_amount = redemption_split
* entire_system_debt
Expand All @@ -162,6 +164,7 @@ impl StrategyData {
self.upfront_fee_period,
target_amount,
redemption_fee,
&block_number,
)
.await?;

Expand All @@ -176,7 +179,11 @@ impl StrategyData {
Ok(())
}

async fn predict_upfront_fee(&self, new_rate: U256) -> Result<U256, ManagerError> {
async fn predict_upfront_fee(
&self,
new_rate: U256,
block_number: &str,
) -> Result<U256, ManagerError> {
let rpc: RpcService = rpc_provider(&self.rpc_url);

let arguments = predictAdjustBatchInterestRateUpfrontFeeCall {
Expand All @@ -188,6 +195,7 @@ impl StrategyData {
let json_data = eth_call_args(
self.hint_helper.to_string(),
predictAdjustBatchInterestRateUpfrontFeeCall::abi_encode(&arguments),
block_number,
);

let rpc_canister_response = self
Expand All @@ -204,12 +212,13 @@ impl StrategyData {
}

/// Returns the debt of the entire system across all markets if successful.
async fn fetch_entire_system_debt(&self) -> Result<U256, ManagerError> {
async fn fetch_entire_system_debt(&self, block_number: &str) -> Result<U256, ManagerError> {
let rpc: RpcService = rpc_provider(&self.rpc_url);

let json_data = eth_call_args(
self.manager.to_string(),
getEntireSystemDebtCall::SELECTOR.to_vec(),
block_number,
);

let rpc_canister_response = self
Expand All @@ -222,12 +231,13 @@ impl StrategyData {
.unwrap_or_else(|e| Err(e))
}

async fn fetch_redemption_rate(&self) -> Result<U256, ManagerError> {
async fn fetch_redemption_rate(&self, block_number: &str) -> Result<U256, ManagerError> {
let rpc: RpcService = rpc_provider(&self.rpc_url);

let json_data = eth_call_args(
self.collateral_registry.to_string(),
getRedemptionRateWithDecayCall::SELECTOR.to_vec(),
block_number,
);

let rpc_canister_response = self
Expand All @@ -245,6 +255,7 @@ impl StrategyData {
async fn fetch_unbacked_portion_price_and_redeemablity(
&self,
manager: Option<String>,
block_number: &str,
) -> Result<getUnbackedPortionPriceAndRedeemabilityReturn, ManagerError> {
let rpc: RpcService = rpc_provider(&self.rpc_url);

Expand All @@ -256,6 +267,7 @@ impl StrategyData {
let json_data = eth_call_args(
call_manager,
getUnbackedPortionPriceAndRedeemabilityCall::SELECTOR.to_vec(),
block_number,
);

let rpc_canister_response = self
Expand All @@ -273,6 +285,7 @@ impl StrategyData {
&self,
index: U256,
count: U256,
block_number: &str,
) -> Result<Vec<CombinedTroveData>, ManagerError> {
let rpc: RpcService = rpc_provider(&self.rpc_url);

Expand All @@ -284,6 +297,7 @@ impl StrategyData {
let json_data = eth_call_args(
self.multi_trove_getter.to_string(),
getMultipleSortedTrovesCall::abi_encode(&parameters),
block_number,
);

let rpc_canister_response = self
Expand All @@ -299,15 +313,19 @@ impl StrategyData {
}

/// Fetches the total unbacked amount across all collateral markets excluding the ones defined in the parameter.
async fn fetch_total_unbacked(&self, initial_value: U256) -> Result<U256, ManagerError> {
async fn fetch_total_unbacked(
&self,
initial_value: U256,
block_number: &str,
) -> Result<U256, ManagerError> {
let managers: Vec<String> =
MANAGERS.with(|managers_vector| managers_vector.borrow().clone());

let mut total_unbacked = initial_value;

for manager in managers {
total_unbacked += self
.fetch_unbacked_portion_price_and_redeemablity(Some(manager))
.fetch_unbacked_portion_price_and_redeemablity(Some(manager), block_number)
.await?
._0;
}
Expand All @@ -334,18 +352,21 @@ impl StrategyData {
upfront_fee_period: U256,
target_amount: U256,
redemption_fee: U256,
block_number: &str,
) -> Result<Option<U256>, ManagerError> {
if let Some(current_debt_in_front) = self.get_current_debt_in_front(troves.clone()) {
// Check if decrease/increase is valid
let new_rate = self.calculate_new_rate(troves, target_amount).await?;
let new_rate = self
.calculate_new_rate(troves, target_amount, block_number)
.await?;
if self.increase_check(current_debt_in_front, target_amount, redemption_fee) {
return Ok(Some(new_rate));
} else if self.first_decrease_check(
current_debt_in_front,
target_amount,
redemption_fee,
) {
let upfront_fee = self.predict_upfront_fee(new_rate).await?;
let upfront_fee = self.predict_upfront_fee(new_rate, block_number).await?;
if self.second_decrease_check(
time_since_last_update,
upfront_fee_period,
Expand All @@ -364,6 +385,7 @@ impl StrategyData {
&self,
troves: Vec<CombinedTroveData>,
target_amount: U256,
block_number: &str,
) -> Result<U256, ManagerError> {
let mut counted_debt = U256::from(0);
let mut new_rate = U256::from(0);
Expand All @@ -375,6 +397,7 @@ impl StrategyData {
let json_data = eth_call_args(
self.manager.to_string(),
getTroveAnnualInterestRateCall { _troveId: trove.id }.abi_encode(),
block_number,
);

let rpc_canister_response = self
Expand Down
47 changes: 42 additions & 5 deletions ir_manager/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use serde_json::json;

use crate::{
evm_rpc::{
MultiSendRawTransactionResult, RequestResult, RpcApi, RpcService, RpcServices, Service,
EthCallResponse, MultiSendRawTransactionResult, RequestResult, RpcApi, RpcService,
RpcServices, Service,
},
exchange::*,
gas::{estimate_transaction_fees, FeeEstimates},
Expand All @@ -35,11 +36,11 @@ pub fn generate_strategies(
strategies: Vec<StrategyInput>,
rpc_principal: Principal,
rpc_url: String,
upfront_fee_period: Nat
upfront_fee_period: Nat,
) -> HashMap<u32, StrategyData> {
let mut strategies_data: HashMap<u32, StrategyData> = HashMap::new();
let mut strategy_id = 0;

markets.into_iter().for_each(|market| {
strategies.iter().enumerate().for_each(|(index, strategy)| {
let strategy_data = StrategyData::new(
Expand Down Expand Up @@ -214,20 +215,56 @@ pub fn decode_request_response(
}
}

pub fn eth_call_args(to: String, data: Vec<u8>) -> String {
pub fn decode_request_response_encoded(
canister_response: CallResult<(RequestResult,)>,
) -> Result<String, ManagerError> {
match canister_response {
Ok((rpc_response,)) => match rpc_response {
RequestResult::Ok(hex_data) => Ok(hex_data),
RequestResult::Err(e) => Err(ManagerError::RpcResponseError(e)),
},
Err(e) => Err(ManagerError::Custom(e.1)),
}
}

pub fn eth_call_args(to: String, data: Vec<u8>, hex_block_number: &str) -> String {
json!({
"id": 1,
"jsonrpc": "2.0",
"params": [ {
"to": to,
"data": format!("0x{}", hex::encode(data))
}
},
hex_block_number
],
"method": "eth_call"
})
.to_string()
}

pub async fn get_block_number(
rpc_canister: &Service,
rpc_url: &str,
) -> Result<String, ManagerError> {
let rpc: RpcService = rpc_provider(rpc_url);

let args = json!({
"id": 1,
"jsonrpc": "2.0",
"method": "eth_blockNumber"
})
.to_string();

let rpc_canister_response = rpc_canister
.request(rpc, args, 500000, 10_000_000_000)
.await;

let encoded_response = decode_request_response_encoded(rpc_canister_response)?;
let decoded_response: EthCallResponse = serde_json::from_str(&encoded_response)
.map_err(|err| ManagerError::DecodingError(format!("{}", err)))?;
Ok(decoded_response.result)
}

pub async fn set_public_keys() {
let strategies =
STRATEGY_DATA.with(|strategies_hashmap| strategies_hashmap.borrow_mut().clone());
Expand Down

0 comments on commit bc85d68

Please sign in to comment.