sui_graphql_rpc/types/
address.rs

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