fuel-core 0.48.0

Fuel client library is aggregation of all fuels service. It contains the all business logic of the fuel protocol.
Documentation
use crate::{
    fuel_core_graphql_api::{
        IntoApiResult,
        query_costs,
    },
    schema::{
        ReadViewProvider,
        scalars::{
            AssetId,
            ContractId,
            HexString,
            Salt,
            U64,
        },
    },
};
use async_graphql::{
    Context,
    InputObject,
    Object,
    connection::{
        Connection,
        EmptyFields,
    },
};
use fuel_core_storage::{
    not_found,
    tables::ContractsRawCode,
};
use fuel_core_types::{
    fuel_types,
    services::graphql_api,
};
use futures::StreamExt;

pub struct Contract(pub(crate) fuel_types::ContractId);

impl From<fuel_types::ContractId> for Contract {
    fn from(id: fuel_types::ContractId) -> Self {
        Self(id)
    }
}

#[Object]
impl Contract {
    async fn id(&self) -> ContractId {
        self.0.into()
    }

    #[graphql(complexity = "query_costs().bytecode_read")]
    async fn bytecode(&self, ctx: &Context<'_>) -> async_graphql::Result<HexString> {
        let query = ctx.read_view()?;
        query
            .contract_bytecode(self.0)
            .map(HexString)
            .map_err(Into::into)
    }

    #[graphql(complexity = "query_costs().storage_read")]
    async fn salt(&self, ctx: &Context<'_>) -> async_graphql::Result<Salt> {
        let query = ctx.read_view()?;
        query
            .contract_salt(&self.0)
            .map(Into::into)
            .map_err(Into::into)
    }
}

#[derive(Default)]
pub struct ContractQuery;

#[Object]
impl ContractQuery {
    #[graphql(complexity = "query_costs().storage_read + child_complexity")]
    async fn contract(
        &self,
        ctx: &Context<'_>,
        #[graphql(desc = "ID of the Contract")] id: ContractId,
    ) -> async_graphql::Result<Option<Contract>> {
        let query = ctx.read_view()?;
        query
            .contract_exists(id.0)
            .and_then(|contract_exists| {
                if contract_exists {
                    Ok(id.0)
                } else {
                    Err(not_found!(ContractsRawCode))
                }
            })
            .into_api_result()
    }
}

pub struct ContractBalance(graphql_api::ContractBalance);

#[Object]
impl ContractBalance {
    async fn contract(&self) -> ContractId {
        self.0.owner.into()
    }

    async fn amount(&self) -> U64 {
        self.0.amount.into()
    }

    async fn asset_id(&self) -> AssetId {
        self.0.asset_id.into()
    }
}

#[derive(InputObject)]
struct ContractBalanceFilterInput {
    /// Filter assets based on the `contractId` field
    contract: ContractId,
}

#[derive(Default)]
pub struct ContractBalanceQuery;

#[Object]
impl ContractBalanceQuery {
    #[graphql(complexity = "query_costs().storage_read")]
    async fn contract_balance(
        &self,
        ctx: &Context<'_>,
        contract: ContractId,
        asset: AssetId,
    ) -> async_graphql::Result<ContractBalance> {
        let contract_id = contract.into();
        let asset_id = asset.into();
        let query = ctx.read_view()?;
        query
            .contract_balance(contract_id, asset_id)
            .into_api_result()
            .map(|result| {
                result.unwrap_or_else(|| {
                    graphql_api::ContractBalance {
                        owner: contract_id,
                        amount: 0,
                        asset_id,
                    }
                    .into()
                })
            })
    }

    #[graphql(complexity = "{\
        query_costs().storage_iterator\
        + (query_costs().storage_read + first.unwrap_or_default() as usize) * child_complexity \
        + (query_costs().storage_read + last.unwrap_or_default() as usize) * child_complexity\
    }")]
    async fn contract_balances(
        &self,
        ctx: &Context<'_>,
        filter: ContractBalanceFilterInput,
        first: Option<i32>,
        after: Option<String>,
        last: Option<i32>,
        before: Option<String>,
    ) -> async_graphql::Result<
        Connection<AssetId, ContractBalance, EmptyFields, EmptyFields>,
    > {
        let query = ctx.read_view()?;

        crate::schema::query_pagination(after, before, first, last, |start, direction| {
            let balances = query
                .contract_balances(
                    filter.contract.into(),
                    (*start).map(Into::into),
                    direction,
                )
                .map(|balance| {
                    let balance = balance?;
                    let asset_id = balance.asset_id;

                    Ok((asset_id.into(), balance.into()))
                });

            Ok(balances)
        })
        .await
    }
}

impl From<graphql_api::ContractBalance> for ContractBalance {
    fn from(balance: graphql_api::ContractBalance) -> Self {
        ContractBalance(balance)
    }
}