iota_graphql_rpc/types/
address.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use async_graphql::{connection::Connection, *};
6
7use crate::{
8    connection::ScanConnection,
9    types::{
10        balance::{self, Balance},
11        coin::Coin,
12        cursor::Page,
13        iota_address::IotaAddress,
14        iota_names_registration::{NameFormat, NameRegistration},
15        move_object::MoveObject,
16        object::{self, ObjectFilter},
17        owner::OwnerImpl,
18        stake::StakedIota,
19        transaction_block::{self, TransactionBlock, TransactionBlockFilter},
20        type_filter::ExactTypeFilter,
21    },
22};
23
24#[derive(Clone, Debug, PartialEq, Eq, Copy)]
25pub(crate) struct Address {
26    pub address: IotaAddress,
27    /// The checkpoint sequence number at which this was viewed at.
28    pub checkpoint_viewed_at: u64,
29}
30
31/// The possible relationship types for a transaction block: sent or received.
32#[derive(Enum, Copy, Clone, Eq, PartialEq)]
33pub(crate) enum AddressTransactionBlockRelationship {
34    /// Transactions this address has sent. NOTE: this input filter has been
35    /// deprecated in favor of `SENT` which behaves identically but is named
36    /// more clearly. Both filters restrict transactions by their sender,
37    /// only, not signers in general.
38    ///
39    /// This filter will be removed after 6 months with the 1.24.0 release.
40    #[graphql(
41        deprecation = "Misleading semantics. Use `SENT` instead. This will be removed with the 1.24.0 release."
42    )]
43    Sign,
44    /// Transactions this address has sent.
45    Sent,
46    /// Transactions that sent objects to this address.
47    Recv,
48}
49
50/// The 32-byte address that is an account address (corresponding to a public
51/// key).
52#[Object]
53impl Address {
54    pub(crate) async fn address(&self) -> IotaAddress {
55        OwnerImpl::from(self).address().await
56    }
57
58    /// Objects owned by this address, optionally `filter`-ed.
59    pub(crate) async fn objects(
60        &self,
61        ctx: &Context<'_>,
62        first: Option<u64>,
63        after: Option<object::Cursor>,
64        last: Option<u64>,
65        before: Option<object::Cursor>,
66        filter: Option<ObjectFilter>,
67    ) -> Result<Connection<String, MoveObject>> {
68        OwnerImpl::from(self)
69            .objects(ctx, first, after, last, before, filter)
70            .await
71    }
72
73    /// Total balance of all coins with marker type owned by this address. If
74    /// type is not supplied, it defaults to `0x2::iota::IOTA`.
75    pub(crate) async fn balance(
76        &self,
77        ctx: &Context<'_>,
78        type_: Option<ExactTypeFilter>,
79    ) -> Result<Option<Balance>> {
80        OwnerImpl::from(self).balance(ctx, type_).await
81    }
82
83    /// The balances of all coin types owned by this address.
84    pub(crate) async fn balances(
85        &self,
86        ctx: &Context<'_>,
87        first: Option<u64>,
88        after: Option<balance::Cursor>,
89        last: Option<u64>,
90        before: Option<balance::Cursor>,
91    ) -> Result<Connection<String, Balance>> {
92        OwnerImpl::from(self)
93            .balances(ctx, first, after, last, before)
94            .await
95    }
96
97    /// The coin objects for this address.
98    ///
99    /// `type` is a filter on the coin's type parameter, defaulting to
100    /// `0x2::iota::IOTA`.
101    pub(crate) async fn coins(
102        &self,
103        ctx: &Context<'_>,
104        first: Option<u64>,
105        after: Option<object::Cursor>,
106        last: Option<u64>,
107        before: Option<object::Cursor>,
108        type_: Option<ExactTypeFilter>,
109    ) -> Result<Connection<String, Coin>> {
110        OwnerImpl::from(self)
111            .coins(ctx, first, after, last, before, type_)
112            .await
113    }
114
115    /// The `0x3::staking_pool::StakedIota` objects owned by this address.
116    pub(crate) async fn staked_iotas(
117        &self,
118        ctx: &Context<'_>,
119        first: Option<u64>,
120        after: Option<object::Cursor>,
121        last: Option<u64>,
122        before: Option<object::Cursor>,
123    ) -> Result<Connection<String, StakedIota>> {
124        OwnerImpl::from(self)
125            .staked_iotas(ctx, first, after, last, before)
126            .await
127    }
128
129    /// The name explicitly configured as the default name pointing to this
130    /// address.
131    pub(crate) async fn iota_names_default_name(
132        &self,
133        ctx: &Context<'_>,
134        format: Option<NameFormat>,
135    ) -> Result<Option<String>> {
136        OwnerImpl::from(self)
137            .iota_names_default_name(ctx, format)
138            .await
139    }
140
141    /// The NameRegistration NFTs owned by this address. These grant the
142    /// owner the capability to manage the associated name.
143    pub(crate) async fn iota_names_registrations(
144        &self,
145        ctx: &Context<'_>,
146        first: Option<u64>,
147        after: Option<object::Cursor>,
148        last: Option<u64>,
149        before: Option<object::Cursor>,
150    ) -> Result<Connection<String, NameRegistration>> {
151        OwnerImpl::from(self)
152            .iota_names_registrations(ctx, first, after, last, before)
153            .await
154    }
155
156    /// Similar behavior to the `transactionBlocks` in Query but supporting the
157    /// additional `AddressTransactionBlockRelationship` filter, which
158    /// defaults to `SENT`.
159    ///
160    /// `scanLimit` restricts the number of candidate transactions scanned when
161    /// gathering a page of results. It is required for queries that apply
162    /// more than two complex filters (on function, kind, sender, recipient,
163    /// input object, changed object, or ids), and can be at most
164    /// `serviceConfig.maxScanLimit`.
165    ///
166    /// When the scan limit is reached the page will be returned even if it has
167    /// fewer than `first` results when paginating forward (`last` when
168    /// paginating backwards). If there are more transactions to scan,
169    /// `pageInfo.hasNextPage` (or `pageInfo.hasPreviousPage`) will be set to
170    /// `true`, and `PageInfo.endCursor` (or `PageInfo.startCursor`) will be set
171    /// to the last transaction that was scanned as opposed to the last (or
172    /// first) transaction in the page.
173    ///
174    /// Requesting the next (or previous) page after this cursor will resume the
175    /// search, scanning the next `scanLimit` many transactions in the
176    /// direction of pagination, and so on until all transactions in the
177    /// scanning range have been visited.
178    ///
179    /// By default, the scanning range includes all transactions known to
180    /// GraphQL, but it can be restricted by the `after` and `before`
181    /// cursors, and the `beforeCheckpoint`, `afterCheckpoint` and
182    /// `atCheckpoint` filters.
183    async fn transaction_blocks(
184        &self,
185        ctx: &Context<'_>,
186        first: Option<u64>,
187        after: Option<transaction_block::Cursor>,
188        last: Option<u64>,
189        before: Option<transaction_block::Cursor>,
190        relation: Option<AddressTransactionBlockRelationship>,
191        filter: Option<TransactionBlockFilter>,
192        scan_limit: Option<u64>,
193    ) -> Result<ScanConnection<String, TransactionBlock>> {
194        use AddressTransactionBlockRelationship as R;
195        let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?;
196
197        let Some(filter) = filter.unwrap_or_default().intersect(match relation {
198            // Relationship defaults to "signer" if none is supplied.
199            Some(R::Sign) | Some(R::Sent) | None => TransactionBlockFilter {
200                sent_address: Some(self.address),
201                ..Default::default()
202            },
203
204            Some(R::Recv) => TransactionBlockFilter {
205                recv_address: Some(self.address),
206                ..Default::default()
207            },
208        }) else {
209            return Ok(ScanConnection::new(false, false));
210        };
211
212        TransactionBlock::paginate(ctx, page, filter, self.checkpoint_viewed_at, scan_limit)
213            .await
214            .extend()
215    }
216}
217
218impl From<&Address> for OwnerImpl {
219    fn from(address: &Address) -> Self {
220        OwnerImpl {
221            address: address.address,
222            checkpoint_viewed_at: address.checkpoint_viewed_at,
223        }
224    }
225}