o2-tools 0.1.10

Reusable tooling for trade account and order book contract interactions on Fuel
use async_trait::async_trait;
use fuels::{
    prelude::*,
    types::{
        Address,
        AssetId,
        ContractId,
        coin_type_id::CoinTypeId,
        input::Input,
    },
};

use crate::{
    order_book_deploy::OrderBook,
    trade_account_deploy::TradingAccount,
};

#[derive(Clone)]
pub struct NoOpAccount {
    address: Address,
}

impl Default for NoOpAccount {
    fn default() -> Self {
        Self::new()
    }
}

impl NoOpAccount {
    pub fn new() -> Self {
        Self {
            address: Address::zeroed(),
        }
    }
}

#[async_trait]
impl ViewOnlyAccount for NoOpAccount {
    fn address(&self) -> Address {
        self.address
    }

    fn try_provider(&self) -> Result<&Provider> {
        panic!("NoOpAccount does not have a provider")
    }

    async fn get_asset_inputs_for_amount(
        &self,
        _asset_id: AssetId,
        _amount: u128,
        _excluded_coins: Option<Vec<CoinTypeId>>,
    ) -> Result<Vec<Input>> {
        panic!("NoOpAccount cannot get asset inputs")
    }
}
pub trait LogDecoderExt {
    fn decoder_instance(contract_id: ContractId) -> LogDecoder;
    fn decoder_instance_with_contract_ids(contract_ids: &[ContractId]) -> LogDecoder;
}

impl LogDecoderExt for crate::order_book_deploy::OrderBook<NoOpAccount> {
    fn decoder_instance(contract_id: ContractId) -> LogDecoder {
        Self::new(contract_id, NoOpAccount::new()).log_decoder()
    }

    fn decoder_instance_with_contract_ids(contract_ids: &[ContractId]) -> LogDecoder {
        contract_ids
            .iter()
            .map(|&id| Self::decoder_instance(id))
            .collect::<Vec<_>>()
            .into_iter()
            .fold(LogDecoder::default(), |mut acc, decoder| {
                acc.merge(decoder);
                acc
            })
    }
}

impl LogDecoderExt for crate::trade_account_deploy::TradingAccount<NoOpAccount> {
    fn decoder_instance(contract_id: ContractId) -> LogDecoder {
        Self::new(contract_id, NoOpAccount::new()).log_decoder()
    }

    fn decoder_instance_with_contract_ids(contract_ids: &[ContractId]) -> LogDecoder {
        contract_ids
            .iter()
            .map(|&id| Self::decoder_instance(id))
            .collect::<Vec<_>>()
            .into_iter()
            .fold(LogDecoder::default(), |mut acc, decoder| {
                acc.merge(decoder);
                acc
            })
    }
}

#[derive(Default)]
pub struct GetLogDecoder {
    pub trade_accounts: Option<Vec<ContractId>>,
    pub order_books: Option<Vec<ContractId>>,
}

pub fn get_log_decoder(log_decoder_config: GetLogDecoder) -> LogDecoder {
    let mut log_decoder = LogDecoder::default();

    if let Some(trade_accounts) = log_decoder_config.trade_accounts {
        log_decoder.merge(TradingAccount::decoder_instance_with_contract_ids(
            &trade_accounts,
        ));
    }
    if let Some(order_books) = log_decoder_config.order_books {
        log_decoder.merge(OrderBook::decoder_instance_with_contract_ids(&order_books));
    }

    log_decoder
}