1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
use crate::{
    database::{
        database_description::off_chain::OffChain,
        Database,
    },
    fuel_core_graphql_api::storage::coins::{
        owner_coin_id_key,
        OwnedCoins,
    },
};
use fuel_core_chain_config::TableEntry;
use fuel_core_storage::{
    iter::{
        IterDirection,
        IteratorOverTable,
    },
    not_found,
    tables::Coins,
    Result as StorageResult,
    StorageAsRef,
};
use fuel_core_txpool::types::TxId;
use fuel_core_types::{
    entities::coins::coin::CompressedCoin,
    fuel_tx::{
        Address,
        UtxoId,
    },
};
use itertools::Itertools;

impl Database<OffChain> {
    pub fn owned_coins_ids(
        &self,
        owner: &Address,
        start_coin: Option<UtxoId>,
        direction: Option<IterDirection>,
    ) -> impl Iterator<Item = StorageResult<UtxoId>> + '_ {
        let start_coin = start_coin.map(|b| owner_coin_id_key(owner, &b));
        self.iter_all_filtered::<OwnedCoins, _>(
            Some(*owner), start_coin.as_ref(),
            direction,
        )
        // Safety: key is always 64 bytes
        .map(|res| {
            res.map(|(key, _)| {
                UtxoId::new(
                    TxId::try_from(&key[32..64]).expect("The slice has size 32"),
                    u16::from_be_bytes(
                        key[64..].try_into().expect("The slice has size 2"),
                    )
                )
            })
        })
    }
}

impl Database {
    pub fn coin(&self, utxo_id: &UtxoId) -> StorageResult<CompressedCoin> {
        let coin = self
            .storage_as_ref::<Coins>()
            .get(utxo_id)?
            .ok_or(not_found!(Coins))?
            .into_owned();

        Ok(coin)
    }

    pub fn iter_coins(
        &self,
    ) -> impl Iterator<Item = StorageResult<TableEntry<Coins>>> + '_ {
        self.iter_all::<Coins>(None)
            .map_ok(|(key, value)| TableEntry { key, value })
    }
}