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)]
35pub(crate) enum AddressTransactionBlockRelationship {
36 Sent,
38 Recv,
40 Affected,
43}
44
45#[Object]
48impl Address {
49 pub(crate) async fn address(&self) -> IotaAddress {
50 OwnerImpl::from(self).address().await
51 }
52
53 pub(crate) async fn objects(
55 &self,
56 ctx: &Context<'_>,
57 first: Option<u64>,
58 after: Option<object::Cursor>,
59 last: Option<u64>,
60 before: Option<object::Cursor>,
61 filter: Option<ObjectFilter>,
62 ) -> Result<Connection<String, MoveObject>> {
63 OwnerImpl::from(self)
64 .objects(ctx, first, after, last, before, filter)
65 .await
66 }
67
68 pub(crate) async fn balance(
71 &self,
72 ctx: &Context<'_>,
73 type_: Option<ExactTypeFilter>,
74 ) -> Result<Option<Balance>> {
75 OwnerImpl::from(self).balance(ctx, type_).await
76 }
77
78 pub(crate) async fn balances(
80 &self,
81 ctx: &Context<'_>,
82 first: Option<u64>,
83 after: Option<balance::Cursor>,
84 last: Option<u64>,
85 before: Option<balance::Cursor>,
86 ) -> Result<Connection<String, Balance>> {
87 OwnerImpl::from(self)
88 .balances(ctx, first, after, last, before)
89 .await
90 }
91
92 pub(crate) async fn coins(
97 &self,
98 ctx: &Context<'_>,
99 first: Option<u64>,
100 after: Option<object::Cursor>,
101 last: Option<u64>,
102 before: Option<object::Cursor>,
103 type_: Option<ExactTypeFilter>,
104 ) -> Result<Connection<String, Coin>> {
105 OwnerImpl::from(self)
106 .coins(ctx, first, after, last, before, type_)
107 .await
108 }
109
110 pub(crate) async fn staked_iotas(
112 &self,
113 ctx: &Context<'_>,
114 first: Option<u64>,
115 after: Option<object::Cursor>,
116 last: Option<u64>,
117 before: Option<object::Cursor>,
118 ) -> Result<Connection<String, StakedIota>> {
119 OwnerImpl::from(self)
120 .staked_iotas(ctx, first, after, last, before)
121 .await
122 }
123
124 pub(crate) async fn iota_names_default_name(
127 &self,
128 ctx: &Context<'_>,
129 format: Option<NameFormat>,
130 ) -> Result<Option<String>> {
131 OwnerImpl::from(self)
132 .iota_names_default_name(ctx, format)
133 .await
134 }
135
136 pub(crate) async fn iota_names_registrations(
139 &self,
140 ctx: &Context<'_>,
141 first: Option<u64>,
142 after: Option<object::Cursor>,
143 last: Option<u64>,
144 before: Option<object::Cursor>,
145 ) -> Result<Connection<String, NameRegistration>> {
146 OwnerImpl::from(self)
147 .iota_names_registrations(ctx, first, after, last, before)
148 .await
149 }
150
151 #[graphql(
184 complexity = "first.or(last).unwrap_or(DEFAULT_PAGE_SIZE as u64) as usize * child_complexity"
185 )]
186 async fn transaction_blocks(
187 &self,
188 ctx: &Context<'_>,
189 first: Option<u64>,
190 after: Option<transaction_block::Cursor>,
191 last: Option<u64>,
192 before: Option<transaction_block::Cursor>,
193 relation: Option<AddressTransactionBlockRelationship>,
194 filter: Option<TransactionBlockFilter>,
195 #[graphql(
196 deprecation = "`scanLimit` will be removed with v1.38, along with the support for combining complex filters."
197 )]
198 scan_limit: Option<u64>,
199 ) -> Result<ScanConnection<String, TransactionBlock>> {
200 use AddressTransactionBlockRelationship as R;
201 let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?;
202
203 let Some(filter) = filter.unwrap_or_default().intersect(match relation {
204 Some(R::Sent) | None => TransactionBlockFilter {
206 sent_address: Some(self.address),
207 ..Default::default()
208 },
209
210 Some(R::Recv) => TransactionBlockFilter {
211 recv_address: Some(self.address),
212 ..Default::default()
213 },
214
215 Some(R::Affected) => TransactionBlockFilter {
216 affected_address: Some(self.address),
217 ..Default::default()
218 },
219 }) else {
220 return Ok(ScanConnection::new(false, false));
221 };
222
223 TransactionBlock::paginate(ctx, page, filter, self.checkpoint_viewed_at, scan_limit)
224 .await
225 .extend()
226 }
227}
228
229impl From<&Address> for OwnerImpl {
230 fn from(address: &Address) -> Self {
231 OwnerImpl {
232 address: address.address,
233 checkpoint_viewed_at: address.checkpoint_viewed_at,
234 }
235 }
236}