1use ckb_jsonrpc_types::{
4 BlockNumber, Capacity, CellOutput, JsonBytes, OutPoint, Script, Uint32, Uint64,
5};
6use ckb_types::H256;
7use serde::{Deserialize, Serialize};
8
9use crate::traits::{CellQueryOptions, LiveCell, PrimaryScriptType, ValueRangeOption};
10
11#[derive(Serialize, Deserialize, Clone, Debug)]
12pub struct SearchKey {
13 pub script: Script,
14 pub script_type: ScriptType,
15 pub script_search_mode: Option<SearchMode>,
16 pub filter: Option<SearchKeyFilter>,
17 pub with_data: Option<bool>,
18 pub group_by_transaction: Option<bool>,
19}
20
21#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Hash)]
22#[serde(rename_all = "snake_case")]
23pub enum SearchMode {
24 Prefix,
26 Exact,
28 Partial,
30}
31
32impl Default for SearchMode {
33 fn default() -> Self {
34 Self::Prefix
35 }
36}
37
38#[derive(Serialize, Deserialize, Default, Clone, Debug)]
39pub struct SearchKeyFilter {
40 pub script: Option<Script>,
41 pub script_len_range: Option<[Uint64; 2]>,
42 pub output_data: Option<JsonBytes>,
43 pub output_data_filter_mode: Option<SearchMode>,
44 pub output_data_len_range: Option<[Uint64; 2]>,
45 pub output_capacity_range: Option<[Uint64; 2]>,
46 pub block_range: Option<[BlockNumber; 2]>,
47}
48impl From<CellQueryOptions> for SearchKey {
49 fn from(opts: CellQueryOptions) -> SearchKey {
50 let convert_range =
51 |range: ValueRangeOption| [Uint64::from(range.start), Uint64::from(range.end)];
52 let filter = if opts.secondary_script.is_none()
53 && opts.secondary_script_len_range.is_none()
54 && opts.data_len_range.is_none()
55 && opts.capacity_range.is_none()
56 && opts.block_range.is_none()
57 {
58 None
59 } else {
60 Some(SearchKeyFilter {
61 script: opts.secondary_script.map(|v| v.into()),
62 script_len_range: opts.secondary_script_len_range.map(convert_range),
63 output_data: None,
64 output_data_filter_mode: None,
65 output_data_len_range: opts.data_len_range.map(convert_range),
66 output_capacity_range: opts.capacity_range.map(convert_range),
67 block_range: opts.block_range.map(convert_range),
68 })
69 };
70 SearchKey {
71 script: opts.primary_script.into(),
72 script_type: opts.primary_type.into(),
73 script_search_mode: opts.script_search_mode,
74 filter,
75 with_data: opts.with_data,
76 group_by_transaction: None,
77 }
78 }
79}
80
81#[derive(Serialize, Deserialize, Clone, Debug)]
82#[serde(rename_all = "snake_case")]
83pub enum ScriptType {
84 Lock,
85 Type,
86}
87impl From<PrimaryScriptType> for ScriptType {
88 fn from(t: PrimaryScriptType) -> ScriptType {
89 match t {
90 PrimaryScriptType::Lock => ScriptType::Lock,
91 PrimaryScriptType::Type => ScriptType::Type,
92 }
93 }
94}
95
96#[derive(Serialize, Deserialize, Clone, Debug)]
97#[serde(rename_all = "snake_case")]
98pub enum Order {
99 Desc,
100 Asc,
101}
102
103#[derive(Serialize, Deserialize, Clone, Debug)]
104pub struct Tip {
105 pub block_hash: H256,
106 pub block_number: BlockNumber,
107}
108
109#[derive(Serialize, Deserialize, Clone, Debug)]
110pub struct CellsCapacity {
111 pub capacity: Capacity,
112 pub block_hash: H256,
113 pub block_number: BlockNumber,
114}
115
116#[derive(Serialize, Deserialize, Clone, Debug)]
117pub struct Cell {
118 pub output: CellOutput,
119 pub output_data: Option<JsonBytes>,
120 pub out_point: OutPoint,
121 pub block_number: BlockNumber,
122 pub tx_index: Uint32,
123}
124impl From<Cell> for LiveCell {
125 fn from(cell: Cell) -> LiveCell {
126 LiveCell {
127 output: cell.output.into(),
128 output_data: cell
129 .output_data
130 .map(|data| data.into_bytes())
131 .unwrap_or_default(),
132 out_point: cell.out_point.into(),
133 block_number: cell.block_number.value(),
134 tx_index: cell.tx_index.value(),
135 }
136 }
137}
138
139#[derive(Serialize, Deserialize, Clone, Debug)]
140#[serde(untagged)]
141pub enum Tx {
142 Ungrouped(TxWithCell),
143 Grouped(TxWithCells),
144}
145
146impl Tx {
147 pub fn tx_hash(&self) -> H256 {
148 match self {
149 Tx::Ungrouped(tx) => tx.tx_hash.clone(),
150 Tx::Grouped(tx) => tx.tx_hash.clone(),
151 }
152 }
153}
154
155#[derive(Serialize, Deserialize, Clone, Debug)]
156pub struct TxWithCell {
157 pub tx_hash: H256,
158 pub block_number: BlockNumber,
159 pub tx_index: Uint32,
160 pub io_index: Uint32,
161 pub io_type: CellType,
162}
163
164#[derive(Serialize, Deserialize, Clone, Debug)]
165pub struct TxWithCells {
166 pub tx_hash: H256,
167 pub block_number: BlockNumber,
168 pub tx_index: Uint32,
169 pub cells: Vec<(CellType, Uint32)>,
170}
171
172#[derive(Serialize, Deserialize, Clone, Debug)]
173#[serde(rename_all = "snake_case")]
174pub enum CellType {
175 Input,
176 Output,
177}
178
179#[derive(Serialize, Deserialize, Clone, Debug)]
180#[serde(rename_all = "snake_case")]
181pub enum IOType {
182 Input,
183 Output,
184}
185
186#[derive(Serialize, Deserialize)]
187pub struct Pagination<T> {
188 pub objects: Vec<T>,
189 pub last_cursor: JsonBytes,
190}
191#[cfg(not(target_arch = "wasm32"))]
192crate::jsonrpc!(pub struct IndexerRpcClient {
193 pub fn get_indexer_tip(&self) -> Option<Tip>;
194 pub fn get_cells(&self, search_key: SearchKey, order: Order, limit: Uint32, after: Option<JsonBytes>) -> Pagination<Cell>;
195 pub fn get_transactions(&self, search_key: SearchKey, order: Order, limit: Uint32, after: Option<JsonBytes>) -> Pagination<Tx>;
196 pub fn get_cells_capacity(&self, search_key: SearchKey) -> Option<CellsCapacity>;
197});
198
199crate::jsonrpc_async!(pub struct IndexerRpcAsyncClient {
200 pub fn get_indexer_tip(&self) -> Option<Tip>;
201 pub fn get_cells(&self, search_key: SearchKey, order: Order, limit: Uint32, after: Option<JsonBytes>) -> Pagination<Cell>;
202 pub fn get_transactions(&self, search_key: SearchKey, order: Order, limit: Uint32, after: Option<JsonBytes>) -> Pagination<Tx>;
203 pub fn get_cells_capacity(&self, search_key: SearchKey) -> Option<CellsCapacity>;
204});
205#[cfg(not(target_arch = "wasm32"))]
206impl From<&IndexerRpcClient> for IndexerRpcAsyncClient {
207 fn from(value: &IndexerRpcClient) -> Self {
208 Self {
209 client: value.client.clone(),
210 id: 0.into(),
211 }
212 }
213}