Browse Source

interface

Jayant Krishnamurthy 2 weeks ago
parent
commit
db947f4c3e

+ 65 - 1
apps/fortuna/src/chain/ethereum.rs

@@ -11,12 +11,13 @@ use {
             nonce_manager::NonceManagerMiddleware,
             traced_client::{RpcMetrics, TracedClient},
         },
+        keeper::contract::{KeeperProviderInfo, KeeperTxContract},
     },
     anyhow::{anyhow, Error, Result},
     axum::async_trait,
     ethers::{
         abi::RawLog,
-        contract::{abigen, EthLogDecode, LogMeta},
+        contract::{abigen, ContractCall, EthLogDecode, LogMeta},
         core::types::Address,
         middleware::{gas_oracle::GasOracleMiddleware, SignerMiddleware},
         prelude::JsonRpcClient,
@@ -350,3 +351,66 @@ impl<T: JsonRpcClient + 'static> EntropyReader for PythRandom<Provider<T>> {
         result.map_err(|e| e.into())
     }
 }
+
+#[async_trait]
+impl KeeperTxContract for InstrumentedSignablePythContract {
+    type Middleware = MiddlewaresWrapper<TracedClient>;
+    type ProviderClient = TracedClient;
+
+    fn client(&self) -> Arc<Self::Middleware> {
+        self.client()
+    }
+
+    fn wallet(&self) -> LocalWallet {
+        self.wallet()
+    }
+
+    fn provider(&self) -> Provider<Self::ProviderClient> {
+        self.provider()
+    }
+
+    fn reveal_with_callback(
+        &self,
+        provider_address: Address,
+        sequence_number: u64,
+        user_random_number: [u8; 32],
+        provider_revelation: [u8; 32],
+    ) -> ContractCall<Self::Middleware, ()> {
+        self.reveal_with_callback(
+            provider_address,
+            sequence_number,
+            user_random_number,
+            provider_revelation,
+        )
+    }
+
+    fn withdraw_as_fee_manager(
+        &self,
+        provider_address: Address,
+        amount: u128,
+    ) -> ContractCall<Self::Middleware, ()> {
+        self.withdraw_as_fee_manager(provider_address, amount)
+    }
+
+    fn set_provider_fee_as_fee_manager(
+        &self,
+        provider_address: Address,
+        fee: u128,
+    ) -> ContractCall<Self::Middleware, ()> {
+        self.set_provider_fee_as_fee_manager(provider_address, fee)
+    }
+
+    async fn get_provider_info(&self, provider_address: Address) -> Result<KeeperProviderInfo> {
+        let info = self.get_provider_info_v2(provider_address).call().await?;
+
+        Ok(KeeperProviderInfo {
+            accrued_fees_in_wei: U256::from(info.accrued_fees_in_wei),
+            fee_in_wei: U256::from(info.fee_in_wei),
+            sequence_number: info.sequence_number,
+            end_sequence_number: info.end_sequence_number,
+            current_commitment_sequence_number: info.current_commitment_sequence_number,
+            default_gas_limit: info.default_gas_limit.into(),
+            fee_manager: info.fee_manager,
+        })
+    }
+}

+ 10 - 5
apps/fortuna/src/eth_utils/utils.rs

@@ -1,7 +1,8 @@
 use {
     crate::{
-        chain::ethereum::{InstrumentedSignablePythContract, PythRandomEvents, Revealed2Filter},
+        chain::ethereum::{PythRandomEvents, Revealed2Filter},
         eth_utils::nonce_manager::NonceManaged,
+        keeper::contract::KeeperTxContract,
     },
     anyhow::{anyhow, Result},
     backoff::ExponentialBackoff,
@@ -352,12 +353,16 @@ pub async fn submit_tx<T: Middleware + NonceManaged + 'static>(
 }
 
 /// Transfer funds from the signing wallet to the destination address.
-pub async fn submit_transfer_tx(
-    contract: Arc<InstrumentedSignablePythContract>,
+pub async fn submit_transfer_tx<C>(
+    contract: Arc<C>,
     destination_address: ethers::types::Address,
     transfer_amount: U256,
-) -> Result<ethers::types::H256> {
-    let source_wallet_address = contract.wallet().address();
+) -> Result<ethers::types::H256>
+where
+    C: KeeperTxContract + 'static,
+{
+    let wallet = contract.wallet();
+    let source_wallet_address = wallet.address();
 
     tracing::info!(
         "Transferring {:?} from {:?} to {:?}",

+ 4 - 1
apps/fortuna/src/keeper.rs

@@ -34,6 +34,7 @@ use {
 
 pub(crate) mod block;
 pub(crate) mod commitment;
+pub(crate) mod contract;
 pub(crate) mod fee;
 pub(crate) mod keeper_metrics;
 pub(crate) mod process_event;
@@ -112,7 +113,9 @@ pub async fn run_keeper_threads(
 
     let (tx, rx) = mpsc::channel::<BlockRange>(1000);
     // Spawn a thread to watch for new blocks and send the range of blocks for which events has not been handled to the `tx` channel.
-    spawn(watch_blocks_wrapper(chain_state.clone(), latest_safe_block, tx).in_current_span());
+    spawn(
+        watch_blocks_wrapper(chain_state.clone(), latest_safe_block, tx).in_current_span(),
+    );
 
     // Spawn a thread for block processing with configured delays
     spawn(

+ 18 - 9
apps/fortuna/src/keeper/block.rs

@@ -1,11 +1,12 @@
 use {
     crate::{
         api::BlockchainState,
-        chain::{ethereum::InstrumentedSignablePythContract, reader::BlockNumber},
+        chain::reader::BlockNumber,
         config::ReplicaConfig,
         eth_utils::utils::EscalationPolicy,
         history::History,
         keeper::{
+            contract::KeeperTxContract,
             keeper_metrics::{ChainIdLabel, KeeperMetrics},
             process_event::process_event_with_backoff,
         },
@@ -37,8 +38,8 @@ pub struct BlockRange {
 }
 
 #[derive(Clone)]
-pub struct ProcessParams {
-    pub contract: Arc<InstrumentedSignablePythContract>,
+pub struct ProcessParams<C: KeeperTxContract + 'static> {
+    pub contract: Arc<C>,
     pub escalation_policy: EscalationPolicy,
     pub chain_state: BlockchainState,
     pub replica_config: Option<ReplicaConfig>,
@@ -74,7 +75,10 @@ pub async fn get_latest_safe_block(chain_state: &BlockchainState) -> BlockNumber
 #[tracing::instrument(skip_all, fields(
     range_from_block = block_range.from, range_to_block = block_range.to
 ))]
-pub async fn process_block_range(block_range: BlockRange, process_params: ProcessParams) {
+pub async fn process_block_range<C>(block_range: BlockRange, process_params: ProcessParams<C>)
+where
+    C: KeeperTxContract + 'static,
+{
     let BlockRange {
         from: first_block,
         to: last_block,
@@ -109,7 +113,12 @@ pub async fn process_block_range(block_range: BlockRange, process_params: Proces
     batch_from_block = block_range.from, batch_to_block = block_range.to
 ))]
 
-pub async fn process_single_block_batch(block_range: BlockRange, process_params: ProcessParams) {
+pub async fn process_single_block_batch<C>(
+    block_range: BlockRange,
+    process_params: ProcessParams<C>,
+) where
+    C: KeeperTxContract + 'static,
+{
     let label = ChainIdLabel {
         chain_id: process_params.chain_state.id.clone(),
     };
@@ -267,8 +276,8 @@ pub async fn watch_blocks(
 /// It waits on rx channel to receive block ranges and then calls process_block_range to process them
 /// for each configured block delay.
 #[tracing::instrument(skip_all)]
-pub async fn process_new_blocks(
-    process_params: ProcessParams,
+pub async fn process_new_blocks<C: KeeperTxContract + 'static>(
+    process_params: ProcessParams<C>,
     mut rx: mpsc::Receiver<BlockRange>,
     block_delays: Vec<u64>,
 ) {
@@ -297,8 +306,8 @@ pub async fn process_new_blocks(
 /// Processes the backlog_range for a chain.
 /// It processes the backlog range for each configured block delay.
 #[tracing::instrument(skip_all)]
-pub async fn process_backlog(
-    process_params: ProcessParams,
+pub async fn process_backlog<C: KeeperTxContract + 'static>(
+    process_params: ProcessParams<C>,
     backlog_range: BlockRange,
     block_delays: Vec<u64>,
 ) {

+ 42 - 27
apps/fortuna/src/keeper/fee.rs

@@ -1,9 +1,12 @@
 use {
     crate::{
         api::BlockchainState,
-        chain::ethereum::InstrumentedSignablePythContract,
+        api::ChainId,
         eth_utils::utils::{estimate_tx_cost, send_and_confirm, submit_transfer_tx},
-        keeper::{AccountLabel, ChainId, KeeperMetrics},
+        keeper::{
+            contract::KeeperTxContract,
+            keeper_metrics::{AccountLabel, KeeperMetrics},
+        },
     },
     anyhow::{anyhow, Result},
     ethers::{
@@ -89,20 +92,22 @@ async fn calculate_fair_fee_withdrawal_amount<M: Middleware + 'static>(
 }
 
 #[tracing::instrument(name = "withdraw_fees", skip_all, fields())]
-pub async fn withdraw_fees_wrapper(
-    contract_as_fee_manager: Arc<InstrumentedSignablePythContract>,
+pub async fn withdraw_fees_wrapper<C>(
+    contract_as_fee_manager: Arc<C>,
     provider_address: Address,
     poll_interval: Duration,
     min_balance: U256,
     keeper_address: Address,
     other_keeper_addresses: Vec<Address>,
-) {
-    let fee_manager_wallet = contract_as_fee_manager.wallet().address();
+) where
+    C: KeeperTxContract + 'static,
+{
+    let fee_manager_wallet_address = contract_as_fee_manager.wallet().address();
 
     // Add the fee manager to the list of other keepers so that we can fairly distribute the fees
     // across the fee manager and all the keepers.
     let mut other_keepers_and_fee_mgr = other_keeper_addresses.clone();
-    other_keepers_and_fee_mgr.push(contract_as_fee_manager.wallet().address());
+    other_keepers_and_fee_mgr.push(fee_manager_wallet_address);
 
     loop {
         // Top up the fee manager balance
@@ -111,7 +116,7 @@ pub async fn withdraw_fees_wrapper(
         if let Err(e) = withdraw_fees_if_necessary(
             contract_as_fee_manager.clone(),
             provider_address,
-            fee_manager_wallet,
+            fee_manager_wallet_address,
             other_keepers_and_fee_mgr.clone(),
             min_balance,
         )
@@ -141,7 +146,7 @@ pub async fn withdraw_fees_wrapper(
 
 /// Withdraws accumulated fees in the contract as needed to maintain the balance of the keeper wallet.
 pub async fn withdraw_fees_if_necessary(
-    contract_as_fee_manager: Arc<InstrumentedSignablePythContract>,
+    contract_as_fee_manager: Arc<impl KeeperTxContract + 'static>,
     provider_address: Address,
     keeper_address: Address,
     other_keeper_addresses: Vec<Address>,
@@ -161,12 +166,11 @@ pub async fn withdraw_fees_if_necessary(
     }
 
     let provider_info = contract_as_fee_manager
-        .get_provider_info_v2(provider_address)
-        .call()
+        .get_provider_info(provider_address)
         .await
         .map_err(|e| anyhow!("Error while getting provider info. error: {:?}", e))?;
 
-    let available_fees = U256::from(provider_info.accrued_fees_in_wei);
+    let available_fees = provider_info.accrued_fees_in_wei;
 
     // Determine how much we can fairly withdraw from the contract
     let withdrawal_amount = calculate_fair_fee_withdrawal_amount(
@@ -220,8 +224,8 @@ pub async fn withdraw_fees_if_necessary(
 
 #[tracing::instrument(name = "adjust_fee", skip_all)]
 #[allow(clippy::too_many_arguments)]
-pub async fn adjust_fee_wrapper(
-    contract: Arc<InstrumentedSignablePythContract>,
+pub async fn adjust_fee_wrapper<C>(
+    contract: Arc<C>,
     chain_state: BlockchainState,
     provider_address: Address,
     poll_interval: Duration,
@@ -231,7 +235,9 @@ pub async fn adjust_fee_wrapper(
     max_profit_pct: u64,
     min_fee_wei: u128,
     metrics: Arc<KeeperMetrics>,
-) {
+) where
+    C: KeeperTxContract + 'static,
+{
     // The maximum balance of accrued fees + provider wallet balance. None if we haven't observed a value yet.
     let mut high_water_pnl: Option<U256> = None;
     // The sequence number where the keeper last updated the on-chain fee. None if we haven't observed it yet.
@@ -273,8 +279,8 @@ pub async fn adjust_fee_wrapper(
 /// These conditions are intended to make sure that the keeper is profitable while also minimizing the number of fee
 /// update transactions.
 #[allow(clippy::too_many_arguments)]
-pub async fn adjust_fee_if_necessary(
-    contract: Arc<InstrumentedSignablePythContract>,
+pub async fn adjust_fee_if_necessary<C>(
+    contract: Arc<C>,
     chain_id: ChainId,
     provider_address: Address,
     legacy_tx: bool,
@@ -285,15 +291,24 @@ pub async fn adjust_fee_if_necessary(
     high_water_pnl: &mut Option<U256>,
     sequence_number_of_last_fee_update: &mut Option<u64>,
     metrics: Arc<KeeperMetrics>,
-) -> Result<()> {
+) -> Result<()>
+where
+    C: KeeperTxContract + 'static,
+{
     let provider_info = contract
-        .get_provider_info_v2(provider_address)
-        .call()
+        .get_provider_info(provider_address)
         .await
         .map_err(|e| anyhow!("Error while getting provider info. error: {:?}", e))?;
 
-    if provider_info.fee_manager != contract.wallet().address() {
-        return Err(anyhow!("Fee manager for provider {:?} is not the keeper wallet. Fee manager: {:?} Keeper: {:?}", contract.provider(), provider_info.fee_manager, contract.wallet().address()));
+    let wallet = contract.wallet();
+    let wallet_address = wallet.address();
+    if provider_info.fee_manager != wallet_address {
+        return Err(anyhow!(
+            "Fee manager for provider {:?} is not the keeper wallet. Fee manager: {:?} Keeper: {:?}",
+            contract.provider(),
+            provider_info.fee_manager,
+            wallet_address
+        ));
     }
 
     // Calculate target window for the on-chain fee.
@@ -332,12 +347,12 @@ pub async fn adjust_fee_if_necessary(
     );
 
     // Calculate current P&L to determine if we can reduce fees.
-    let current_keeper_balance = contract
-        .provider()
-        .get_balance(contract.wallet().address(), None)
+    let provider_client = contract.provider();
+    let current_keeper_balance = provider_client
+        .get_balance(wallet_address, None)
         .await
         .map_err(|e| anyhow!("Error while getting balance. error: {:?}", e))?;
-    let current_keeper_fees = U256::from(provider_info.accrued_fees_in_wei);
+    let current_keeper_fees = provider_info.accrued_fees_in_wei;
     let current_pnl = current_keeper_balance + current_keeper_fees;
 
     let can_reduce_fees = match high_water_pnl {
@@ -354,7 +369,7 @@ pub async fn adjust_fee_if_necessary(
         }
     };
 
-    let provider_fee: u128 = provider_info.fee_in_wei;
+    let provider_fee: u128 = provider_info.fee_in_wei.as_u128();
     if is_chain_active
         && ((provider_fee > target_fee_max && can_reduce_fees) || provider_fee < target_fee_min)
     {

+ 7 - 4
apps/fortuna/src/keeper/process_event.rs

@@ -7,7 +7,7 @@ use {
         },
         eth_utils::utils::{submit_tx_with_backoff, SubmitTxError},
         history::{RequestEntryState, RequestStatus},
-        keeper::block::ProcessParams,
+        keeper::{block::ProcessParams, contract::KeeperTxContract},
     },
     anyhow::{anyhow, Result},
     ethers::{abi::AbiDecode, contract::ContractError},
@@ -19,10 +19,13 @@ use {
 #[tracing::instrument(name = "process_event_with_backoff", skip_all, fields(
     sequence_number = event.sequence_number
 ))]
-pub async fn process_event_with_backoff(
+pub async fn process_event_with_backoff<C>(
     event: RequestedV2Event,
-    process_param: ProcessParams,
-) -> Result<()> {
+    process_param: ProcessParams<C>,
+) -> Result<()>
+where
+    C: KeeperTxContract + 'static,
+{
     let ProcessParams {
         chain_state,
         contract,