1- use crate :: Result ;
1+ use crate :: {
2+ Result ,
3+ client:: { MiniBFClient , api:: MiniBFApi , minibf:: format_asset_id} ,
4+ } ;
5+ use blockfrost_openapi:: models:: {
6+ tx_content:: TxContent , tx_content_output_amount_inner:: TxContentOutputAmountInner ,
7+ tx_content_utxo:: TxContentUtxo ,
8+ } ;
9+ use cardano_serialization_lib:: PlutusData ;
210use sidechain_domain:: * ;
311use sp_partner_chains_bridge:: {
412 BridgeDataCheckpoint , BridgeTransferV1 , MainChainScripts , TokenBridgeDataSource ,
513} ;
614use std:: marker:: PhantomData ;
715
816pub struct TokenBridgeDataSourceImpl < RecipientAddress > {
17+ client : MiniBFClient ,
918 _phantom : PhantomData < RecipientAddress > ,
1019}
1120
1221impl < RecipientAddress > TokenBridgeDataSourceImpl < RecipientAddress > {
13- pub fn new ( ) -> Self {
14- Self { _phantom : PhantomData :: default ( ) }
22+ pub fn new ( client : MiniBFClient ) -> Self {
23+ Self { client , _phantom : PhantomData :: default ( ) }
1524 }
1625}
1726
@@ -22,10 +31,199 @@ impl<RecipientAddress: Send + Sync> TokenBridgeDataSource<RecipientAddress>
2231 async fn get_transfers (
2332 & self ,
2433 _main_chain_scripts : MainChainScripts ,
25- _data_checkpoint : BridgeDataCheckpoint ,
34+ data_checkpoint : BridgeDataCheckpoint ,
2635 _max_transfers : u32 ,
27- _current_mc_block : McBlockHash ,
36+ current_mc_block_hash : McBlockHash ,
2837 ) -> Result < ( Vec < BridgeTransferV1 < RecipientAddress > > , BridgeDataCheckpoint ) > {
29- Err ( "not implemented" . into ( ) )
38+ let current_mc_block = self . client . blocks_by_id ( current_mc_block_hash) . await ?;
39+
40+ let data_checkpoint = match data_checkpoint {
41+ BridgeDataCheckpoint :: Utxo ( utxo) => {
42+ let TxBlockInfo { block_number, tx_ix } =
43+ get_block_info_for_utxo ( & self . client , utxo. tx_hash . into ( ) ) . await ?. ok_or (
44+ format ! (
45+ "Could not find block info for data checkpoint: {data_checkpoint:?}"
46+ ) ,
47+ ) ?;
48+ ResolvedBridgeDataCheckpoint :: Utxo {
49+ block_number,
50+ tx_ix,
51+ tx_out_ix : utxo. index . into ( ) ,
52+ }
53+ } ,
54+ BridgeDataCheckpoint :: Block ( number) => {
55+ ResolvedBridgeDataCheckpoint :: Block { number : number. into ( ) }
56+ } ,
57+ } ;
58+
59+ let asset = Asset {
60+ policy_id : main_chain_scripts. token_policy_id . into ( ) ,
61+ asset_name : main_chain_scripts. token_asset_name . into ( ) ,
62+ } ;
63+ let utxos = get_bridge_utxos_tx (
64+ & main_chain_scripts. illiquid_circulation_supply_validator_address . into ( ) ,
65+ asset,
66+ data_checkpoint,
67+ current_mc_block. block_no ,
68+ Some ( max_transfers) ,
69+ )
70+ . await ?;
71+
72+ let new_checkpoint = match utxos. last ( ) {
73+ None => BridgeDataCheckpoint :: Block ( current_mc_block. block_no . into ( ) ) ,
74+ Some ( _) if ( utxos. len ( ) as u32 ) < max_transfers => {
75+ BridgeDataCheckpoint :: Block ( current_mc_block. block_no . into ( ) )
76+ } ,
77+ Some ( utxo) => BridgeDataCheckpoint :: Utxo ( utxo. utxo_id ( ) ) ,
78+ } ;
79+
80+ let transfers = utxos. into_iter ( ) . flat_map ( utxo_to_transfer) . collect ( ) ;
81+
82+ Ok ( ( transfers, new_checkpoint) )
83+ }
84+ }
85+
86+ pub ( crate ) struct BridgeUtxo {
87+ pub ( crate ) block_number : McBlockNumber ,
88+ pub ( crate ) tx_ix : McTxIndexInBlock ,
89+ pub ( crate ) tx_hash : McTxHash ,
90+ pub ( crate ) utxo_ix : UtxoIndex ,
91+ pub ( crate ) tokens_out : NativeTokenAmount ,
92+ pub ( crate ) tokens_in : NativeTokenAmount ,
93+ pub ( crate ) datum : Option < cardano_serialization_lib:: PlutusData > ,
94+ }
95+
96+ pub ( crate ) async fn get_block_info_for_utxo (
97+ client : & MiniBFClient ,
98+ tx_hash : McTxHash ,
99+ ) -> Result < Option < TxBlockInfo > > {
100+
101+ // SELECT
102+ // block.block_no AS block_number,
103+ // tx.block_index AS tx_ix
104+ // FROM tx
105+ // JOIN block ON block.id = tx.block_id
106+ // WHERE tx.hash = $tx_hash
107+ }
108+
109+ pub ( crate ) enum ResolvedBridgeDataCheckpoint {
110+ Utxo { block_number : BlockNumber , tx_ix : TxIndexInBlock , tx_out_ix : TxIndex } ,
111+ Block { number : BlockNumber } ,
112+ }
113+
114+ pub ( crate ) async fn get_bridge_utxos_tx (
115+ client : & MiniBFClient ,
116+ icp_address : & MainchainAddress ,
117+ native_token : AssetId ,
118+ checkpoint : ResolvedBridgeDataCheckpoint ,
119+ to_block : McBlockNumber ,
120+ max_utxos : Option < u32 > ,
121+ ) -> Result < Vec < BridgeUtxo > > {
122+ let x = client. assets_transactions ( native_token. clone ( ) ) . await ?;
123+ let y = x. into_iter ( ) . map ( |a| async move {
124+ if a. block_height as u32 >= to_block. 0 {
125+ let tx_hash = McTxHash :: from_hex_unsafe ( & a. tx_hash ) ;
126+ let x = client. transactions_utxos ( tx_hash) . await ?;
127+ let y = client. transaction_by_hash ( tx_hash) . await ?;
128+ Result :: Ok ( Some ( ( x, y) ) )
129+ } else {
130+ Result :: Ok ( None )
131+ }
132+ } ) ;
133+ let mut z = futures:: future:: try_join_all ( y)
134+ . await ?
135+ . iter ( )
136+ . flatten ( )
137+ . flat_map ( |( x, y) : & ( TxContentUtxo , TxContent ) | {
138+ let inputs = x. inputs . iter ( ) . filter ( |i| i. address == icp_address. to_string ( ) ) ;
139+ let outputs = x. outputs . iter ( ) . filter ( |o| o. address == icp_address. to_string ( ) ) ;
140+ let native_token = native_token. clone ( ) ;
141+ outputs. map ( move |output| {
142+ let native_token = native_token. clone ( ) ;
143+ let output_tokens = get_all_tokens ( & output. amount , & native_token. clone ( ) ) ;
144+ let input_tokens = inputs
145+ . clone ( )
146+ . map ( move |input| get_all_tokens ( & input. amount , & native_token. clone ( ) ) )
147+ . sum ( ) ;
148+
149+ BridgeUtxo {
150+ block_number : McBlockNumber ( y. block_height as u32 ) ,
151+ tokens_out : NativeTokenAmount ( output_tokens) ,
152+ tokens_in : NativeTokenAmount ( input_tokens) ,
153+ datum : output
154+ . inline_datum
155+ . clone ( )
156+ . map ( |d| PlutusData :: from_hex ( & d) . expect ( "valid datum" ) ) ,
157+ tx_ix : todo ! ( ) ,
158+ tx_hash : todo ! ( ) ,
159+ utxo_ix : todo ! ( ) ,
160+ }
161+ } )
162+ } )
163+ . collect :: < Vec < _ > > ( ) ;
164+
165+ match checkpoint {
166+ ResolvedBridgeDataCheckpoint :: Block { number } => {
167+ query_builder. push ( & format ! ( "AND block_no > {} " , number. 0 ) ) ;
168+ } ,
169+ ResolvedBridgeDataCheckpoint :: Utxo { block_number, tx_ix, tx_out_ix } => {
170+ query_builder. push ( & format ! (
171+ "AND (block_no, tx.block_index, outputs.index) > ({}, {}, {}) " ,
172+ block_number. 0 , tx_ix. 0 , tx_out_ix. 0
173+ ) ) ;
174+ } ,
30175 }
176+
177+ query_builder. push ( "ORDER BY block.block_no, tx.block_index, outputs.index " ) ;
178+
179+ if let Some ( max_utxos) = max_utxos {
180+ query_builder. push ( & format ! ( "LIMIT {max_utxos}" ) ) ;
181+ }
182+
183+ Err ( "not implemented" . into ( ) )
31184}
185+
186+ fn get_all_tokens ( amount : & Vec < TxContentOutputAmountInner > , asset_id : & AssetId ) -> u128 {
187+ amount
188+ . iter ( )
189+ . map ( |v| {
190+ if v. unit == format_asset_id ( asset_id) {
191+ v. quantity . parse :: < u128 > ( ) . expect ( "valid quantity is u128" )
192+ } else {
193+ 0u128
194+ }
195+ } )
196+ . sum ( )
197+ }
198+
199+ // get_bridge_utxos_tx
200+
201+ /*
202+ * tx block no >= to_block
203+ * input : at icp address && token kind = assetid -> get SUM input token quantity
204+ * output: at icp address
205+
206+ SELECT
207+ block.block_no AS block_number
208+ , tx.block_index AS tx_ix
209+ , tx.hash AS tx_hash
210+ , outputs.index AS utxo_ix
211+ , output_tokens.quantity AS tokens_out
212+ , coalesce(sum(input_tokens.quantity), 0) AS tokens_in
213+ , datum.value AS datum
214+ FROM
215+ tx_out outputs
216+ JOIN tx ON outputs.tx_id = tx.id
217+ JOIN block ON tx.block_id = block.id
218+ JOIN ma_tx_out output_tokens ON output_tokens.tx_out_id = outputs.id
219+ JOIN multi_asset ON multi_asset.id = output_tokens.ident
220+ LEFT JOIN datum ON datum.hash = outputs.data_hash
221+ LEFT JOIN tx_out inputs ON inputs.consumed_by_tx_id = tx.id AND inputs.address = $icp_address
222+ LEFT JOIN ma_tx_out input_tokens ON input_tokens.tx_out_id = inputs.id AND input_tokens.ident = multi_asset.id
223+
224+ WHERE
225+
226+ multi_asset.policy = $native_token.policy_id AND multi_asset.name = $native_token.policy_name
227+ AND outputs.address = $icp_address
228+ AND block_no <= $to_block
229+ */
0 commit comments