partner_chains_cardano_offchain/bridge/
mod.rs1mod create_utxos;
4mod deposit;
5mod init;
6
7use crate::{
8 csl::{OgmiosUtxoExt, OgmiosValueExt, TransactionContext},
9 scripts_data,
10 versioning_system::find_script_utxo,
11};
12use anyhow::anyhow;
13use cardano_serialization_lib::{
14 BigInt, ExUnits, JsError, PlutusData, PlutusScriptSource, PlutusWitness, Redeemer, RedeemerTag,
15 TxInputsBuilder,
16};
17pub use create_utxos::create_validator_utxos;
18pub use deposit::{deposit_with_ics_spend, deposit_without_ics_input};
19pub use init::init_ics_scripts;
20use ogmios_client::{query_ledger_state::QueryLedgerState, types::OgmiosUtxo};
21use sidechain_domain::{AssetId, AssetName, UtxoId, crypto::blake2b};
22
23#[derive(Clone, Debug)]
25pub(crate) struct ICSData {
26 pub(crate) scripts: scripts_data::ICSScripts,
27 pub(crate) auth_policy_version_utxo: OgmiosUtxo,
29 pub(crate) validator_version_utxo: OgmiosUtxo,
30}
31
32impl ICSData {
33 pub(crate) async fn get<T: QueryLedgerState>(
34 genesis_utxo: UtxoId,
35 ctx: &TransactionContext,
36 client: &T,
37 ) -> Result<Self, anyhow::Error> {
38 let version_oracle = scripts_data::version_oracle(genesis_utxo, ctx.network)?;
39 let validator_version_utxo = find_script_utxo(
40 raw_scripts::ScriptId::IlliquidCirculationSupplyValidator,
41 &version_oracle,
42 ctx,
43 client,
44 )
45 .await?
46 .ok_or_else(|| {
47 anyhow!(
48 "Illiquid Circulation Supply Validator Version Utxo not found, is the Bridge initialized?"
49 )
50 })?;
51 let auth_policy_version_utxo = find_script_utxo(
52 raw_scripts::ScriptId::IlliquidCirculationSupplyAuthorityTokenPolicy,
53 &version_oracle,
54 ctx,
55 client,
56 )
57 .await?
58 .ok_or_else(|| {
59 anyhow!("Illiquid Circulation Supply Authority Token Policy Version Utxo not found, is the Bridge initialized?")
60 })?;
61 let scripts = scripts_data::ics_scripts(genesis_utxo, ctx.network)?;
62 Ok(ICSData { scripts, auth_policy_version_utxo, validator_version_utxo })
63 }
64
65 pub(crate) async fn get_validator_utxos_with_auth_token<T: QueryLedgerState>(
66 &self,
67 ctx: &TransactionContext,
68 client: &T,
69 ) -> Result<Vec<OgmiosUtxo>, anyhow::Error> {
70 let validator_address = self.scripts.validator.address(ctx.network).to_bech32(None)?;
71 let validator_utxos = client.query_utxos(&[validator_address]).await?;
72
73 let auth_token_asset_id = AssetId {
74 policy_id: self.scripts.auth_policy.policy_id(),
75 asset_name: AssetName::empty(),
76 };
77
78 Ok(validator_utxos
79 .into_iter()
80 .filter(|utxo| utxo.get_asset_amount(&auth_token_asset_id) == 1u64)
81 .collect())
82 }
83}
84
85pub(crate) fn select_utxo_to_spend(
87 utxos: &[OgmiosUtxo],
88 ctx: &TransactionContext,
89) -> Option<OgmiosUtxo> {
90 utxos
91 .into_iter()
92 .map(|u| {
93 let utxo_id = u.utxo_id();
94 let mut v: Vec<u8> = utxo_id.tx_hash.0.to_vec();
95 v.append(&mut utxo_id.index.0.to_be_bytes().to_vec());
96 v.append(&mut ctx.payment_key_hash().to_bytes());
97 let hash: [u8; 32] = blake2b(&v);
98 (hash, u)
99 })
100 .min_by_key(|k| k.0)
101 .map(|kv| kv.1.clone())
102}
103
104pub(crate) fn add_ics_utxo_input_with_validator_script_reference(
105 inputs: &mut TxInputsBuilder,
106 ics_utxo: &OgmiosUtxo,
107 ics_data: &ICSData,
108 cost: &ExUnits,
109) -> Result<(), JsError> {
110 let input = ics_utxo.to_csl_tx_input();
111 let amount = ics_utxo.value.to_csl()?;
112 let script = &ics_data.scripts.validator;
113 let witness = PlutusWitness::new_with_ref_without_datum(
114 &PlutusScriptSource::new_ref_input(
115 &script.csl_script_hash(),
116 &ics_data.validator_version_utxo.to_csl_tx_input(),
117 &script.language,
118 script.bytes.len(),
119 ),
120 &Redeemer::new(
121 &RedeemerTag::new_spend(),
122 &0u32.into(),
123 &PlutusData::new_integer(&BigInt::zero()),
124 cost,
125 ),
126 );
127 inputs.add_plutus_script_input(&witness, &input, &amount);
128 Ok(())
129}