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 Sent,
37 Recv,
39}
40
41#[Object]
44impl Address {
45 pub(crate) async fn address(&self) -> IotaAddress {
46 OwnerImpl::from(self).address().await
47 }
48
49 pub(crate) async fn objects(
51 &self,
52 ctx: &Context<'_>,
53 first: Option<u64>,
54 after: Option<object::Cursor>,
55 last: Option<u64>,
56 before: Option<object::Cursor>,
57 filter: Option<ObjectFilter>,
58 ) -> Result<Connection<String, MoveObject>> {
59 OwnerImpl::from(self)
60 .objects(ctx, first, after, last, before, filter)
61 .await
62 }
63
64 pub(crate) async fn balance(
67 &self,
68 ctx: &Context<'_>,
69 type_: Option<ExactTypeFilter>,
70 ) -> Result<Option<Balance>> {
71 OwnerImpl::from(self).balance(ctx, type_).await
72 }
73
74 pub(crate) async fn balances(
76 &self,
77 ctx: &Context<'_>,
78 first: Option<u64>,
79 after: Option<balance::Cursor>,
80 last: Option<u64>,
81 before: Option<balance::Cursor>,
82 ) -> Result<Connection<String, Balance>> {
83 OwnerImpl::from(self)
84 .balances(ctx, first, after, last, before)
85 .await
86 }
87
88 pub(crate) async fn coins(
93 &self,
94 ctx: &Context<'_>,
95 first: Option<u64>,
96 after: Option<object::Cursor>,
97 last: Option<u64>,
98 before: Option<object::Cursor>,
99 type_: Option<ExactTypeFilter>,
100 ) -> Result<Connection<String, Coin>> {
101 OwnerImpl::from(self)
102 .coins(ctx, first, after, last, before, type_)
103 .await
104 }
105
106 pub(crate) async fn staked_iotas(
108 &self,
109 ctx: &Context<'_>,
110 first: Option<u64>,
111 after: Option<object::Cursor>,
112 last: Option<u64>,
113 before: Option<object::Cursor>,
114 ) -> Result<Connection<String, StakedIota>> {
115 OwnerImpl::from(self)
116 .staked_iotas(ctx, first, after, last, before)
117 .await
118 }
119
120 pub(crate) async fn iota_names_default_name(
123 &self,
124 ctx: &Context<'_>,
125 format: Option<NameFormat>,
126 ) -> Result<Option<String>> {
127 OwnerImpl::from(self)
128 .iota_names_default_name(ctx, format)
129 .await
130 }
131
132 pub(crate) async fn iota_names_registrations(
135 &self,
136 ctx: &Context<'_>,
137 first: Option<u64>,
138 after: Option<object::Cursor>,
139 last: Option<u64>,
140 before: Option<object::Cursor>,
141 ) -> Result<Connection<String, NameRegistration>> {
142 OwnerImpl::from(self)
143 .iota_names_registrations(ctx, first, after, last, before)
144 .await
145 }
146
147 #[graphql(
175 complexity = "first.or(last).unwrap_or(DEFAULT_PAGE_SIZE as u64) as usize * child_complexity"
176 )]
177 async fn transaction_blocks(
178 &self,
179 ctx: &Context<'_>,
180 first: Option<u64>,
181 after: Option<transaction_block::Cursor>,
182 last: Option<u64>,
183 before: Option<transaction_block::Cursor>,
184 relation: Option<AddressTransactionBlockRelationship>,
185 filter: Option<TransactionBlockFilter>,
186 scan_limit: Option<u64>,
187 ) -> Result<ScanConnection<String, TransactionBlock>> {
188 use AddressTransactionBlockRelationship as R;
189 let page = Page::from_params(ctx.data_unchecked(), first, after, last, before)?;
190
191 let Some(filter) = filter.unwrap_or_default().intersect(match relation {
192 Some(R::Sent) | None => TransactionBlockFilter {
194 sent_address: Some(self.address),
195 ..Default::default()
196 },
197
198 Some(R::Recv) => TransactionBlockFilter {
199 recv_address: Some(self.address),
200 ..Default::default()
201 },
202 }) else {
203 return Ok(ScanConnection::new(false, false));
204 };
205
206 TransactionBlock::paginate(ctx, page, filter, self.checkpoint_viewed_at, scan_limit)
207 .await
208 .extend()
209 }
210}
211
212impl From<&Address> for OwnerImpl {
213 fn from(address: &Address) -> Self {
214 OwnerImpl {
215 address: address.address,
216 checkpoint_viewed_at: address.checkpoint_viewed_at,
217 }
218 }
219}