1use async_graphql::{connection::Connection, *};
6
7use crate::{
8 config::DEFAULT_PAGE_SIZE,
9 connection::ScanConnection,
10 types::{
11 balance::{self, Balance},
12 coin::Coin,
13 cursor::Page,
14 iota_address::IotaAddress,
15 iota_names_registration::{NameFormat, NameRegistration},
16 move_object::MoveObject,
17 object::{self, ObjectFilter},
18 owner::OwnerImpl,
19 stake::StakedIota,
20 transaction_block::{self, TransactionBlock, TransactionBlockFilter},
21 type_filter::ExactTypeFilter,
22 },
23};
24
25#[derive(Clone, Debug, PartialEq, Eq, Copy)]
26pub(crate) struct Address {
27 pub address: IotaAddress,
28 pub checkpoint_viewed_at: u64,
30}
31
32#[derive(Enum, Copy, Clone, Eq, PartialEq)]
34pub(crate) enum AddressTransactionBlockRelationship {
35 #[graphql(
42 deprecation = "Misleading semantics. Use `SENT` instead. This will be removed with the 1.24.0 release."
43 )]
44 Sign,
45 Sent,
47 Recv,
49}
50
51#[Object]
54impl Address {
55 pub(crate) async fn address(&self) -> IotaAddress {
56 OwnerImpl::from(self).address().await
57 }
58
59 pub(crate) async fn objects(
61 &self,
62 ctx: &Context<'_>,
63 first: Option<u64>,
64 after: Option<object::Cursor>,
65 last: Option<u64>,
66 before: Option<object::Cursor>,
67 filter: Option<ObjectFilter>,
68 ) -> Result<Connection<String, MoveObject>> {
69 OwnerImpl::from(self)
70 .objects(ctx, first, after, last, before, filter)
71 .await
72 }
73
74 pub(crate) async fn balance(
77 &self,
78 ctx: &Context<'_>,
79 type_: Option<ExactTypeFilter>,
80 ) -> Result<Option<Balance>> {
81 OwnerImpl::from(self).balance(ctx, type_).await
82 }
83
84 pub(crate) async fn balances(
86 &self,
87 ctx: &Context<'_>,
88 first: Option<u64>,
89 after: Option<balance::Cursor>,
90 last: Option<u64>,
91 before: Option<balance::Cursor>,
92 ) -> Result<Connection<String, Balance>> {
93 OwnerImpl::from(self)
94 .balances(ctx, first, after, last, before)
95 .await
96 }
97
98 pub(crate) async fn coins(
103 &self,
104 ctx: &Context<'_>,
105 first: Option<u64>,
106 after: Option<object::Cursor>,
107 last: Option<u64>,
108 before: Option<object::Cursor>,
109 type_: Option<ExactTypeFilter>,
110 ) -> Result<Connection<String, Coin>> {
111 OwnerImpl::from(self)
112 .coins(ctx, first, after, last, before, type_)
113 .await
114 }
115
116 pub(crate) async fn staked_iotas(
118 &self,
119 ctx: &Context<'_>,
120 first: Option<u64>,
121 after: Option<object::Cursor>,
122 last: Option<u64>,
123 before: Option<object::Cursor>,
124 ) -> Result<Connection<String, StakedIota>> {
125 OwnerImpl::from(self)
126 .staked_iotas(ctx, first, after, last, before)
127 .await
128 }
129
130 pub(crate) async fn iota_names_default_name(
133 &self,
134 ctx: &Context<'_>,
135 format: Option<NameFormat>,
136 ) -> Result<Option<String>> {
137 OwnerImpl::from(self)
138 .iota_names_default_name(ctx, format)
139 .await
140 }
141
142 pub(crate) async fn iota_names_registrations(
145 &self,
146 ctx: &Context<'_>,
147 first: Option<u64>,
148 after: Option<object::Cursor>,
149 last: Option<u64>,
150 before: Option<object::Cursor>,
151 ) -> Result<Connection<String, NameRegistration>> {
152 OwnerImpl::from(self)
153 .iota_names_registrations(ctx, first, after, last, before)
154 .await
155 }
156
157 #[graphql(
185 complexity = "first.or(last).unwrap_or(DEFAULT_PAGE_SIZE as u64) as usize * child_complexity"
186 )]
187 async fn transaction_blocks(
188 &self,
189 ctx: &Context<'_>,
190 first: Option<u64>,
191 after: Option<transaction_block::Cursor>,
192 last: Option<u64>,
193 before: Option<transaction_block::Cursor>,
194 relation: Option<AddressTransactionBlockRelationship>,
195 filter: Option<TransactionBlockFilter>,
196 scan_limit: Option<u64>,
197 ) -> Result<ScanConnection<String, TransactionBlock>> {
198 use AddressTransactionBlockRelationship as R;
199 let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?;
200
201 let Some(filter) = filter.unwrap_or_default().intersect(match relation {
202 Some(R::Sign) | Some(R::Sent) | None => TransactionBlockFilter {
204 sent_address: Some(self.address),
205 ..Default::default()
206 },
207
208 Some(R::Recv) => TransactionBlockFilter {
209 recv_address: Some(self.address),
210 ..Default::default()
211 },
212 }) else {
213 return Ok(ScanConnection::new(false, false));
214 };
215
216 TransactionBlock::paginate(ctx, page, filter, self.checkpoint_viewed_at, scan_limit)
217 .await
218 .extend()
219 }
220}
221
222impl From<&Address> for OwnerImpl {
223 fn from(address: &Address) -> Self {
224 OwnerImpl {
225 address: address.address,
226 checkpoint_viewed_at: address.checkpoint_viewed_at,
227 }
228 }
229}