partner_chains_cardano_offchain/
scripts_data.rs

1use crate::{csl::NetworkTypeExt, plutus_script, plutus_script::PlutusScript};
2use cardano_serialization_lib::NetworkIdKind;
3use ogmios_client::query_network::QueryNetwork;
4use raw_scripts::ScriptId;
5use raw_scripts::{
6	COMMITTEE_CANDIDATE_VALIDATOR, D_PARAMETER_POLICY, D_PARAMETER_VALIDATOR, GOVERNED_MAP_POLICY,
7	GOVERNED_MAP_VALIDATOR, ILLIQUID_CIRCULATION_SUPPLY_AUTHORITY_TOKEN_POLICY,
8	ILLIQUID_CIRCULATION_SUPPLY_VALIDATOR, PERMISSIONED_CANDIDATES_POLICY,
9	PERMISSIONED_CANDIDATES_VALIDATOR, RESERVE_AUTH_POLICY, RESERVE_VALIDATOR,
10	VERSION_ORACLE_POLICY, VERSION_ORACLE_VALIDATOR,
11};
12use serde::Serialize;
13use sidechain_domain::{PolicyId, UtxoId};
14use uplc::PlutusData;
15
16/// Provides convenient access to the addresses and hashes of the partner chain smart contracts.
17/// Data in this struct is derived from the smart contracts, applied parameters and the network.
18#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
19#[serde(rename_all = "camelCase")]
20pub struct ScriptsData {
21	/// Validator scripts addresses.
22	pub addresses: Addresses,
23	/// Policy ids.
24	pub policy_ids: PolicyIds,
25}
26
27/// Bech32 addresses of applied validators in partner-chains smart contracts.
28#[derive(Clone, Debug, Default, Serialize, PartialEq, Eq)]
29#[serde(rename_all = "PascalCase")]
30pub struct Addresses {
31	/// Address of committee candidate validator script
32	pub committee_candidate_validator: String,
33	/// Address of D-parameter validator script
34	pub d_parameter_validator: String,
35	/// Address of illiquid circulation supply validator script
36	pub illiquid_circulation_supply_validator: String,
37	/// Address of permissioned candidates validator script
38	pub permissioned_candidates_validator: String,
39	/// Address of reserve validator script
40	pub reserve_validator: String,
41	/// Address of version oracle validator script
42	pub version_oracle_validator: String,
43	/// Address of governed map validator script
44	pub governed_map_validator: String,
45}
46
47/// Policy IDs of applied scripts in partner-chains smart contracts.
48#[derive(Clone, Debug, Default, Serialize, PartialEq, Eq)]
49#[serde(rename_all = "PascalCase")]
50pub struct PolicyIds {
51	/// PolicyId of D-parameter minting policy
52	pub d_parameter: PolicyId,
53	/// PolicyId of permissioned candidates minting policy
54	pub permissioned_candidates: PolicyId,
55	/// PolicyId of reserve auth minting policy
56	pub reserve_auth: PolicyId,
57	/// PolicyId of version oracle minting policy
58	pub version_oracle: PolicyId,
59	/// PolicyId of governed map minting policy
60	pub governed_map: PolicyId,
61	/// PolicyId of illiquid circulation supply auth token policy
62	pub illiquid_circulation_supply_auth_token: PolicyId,
63}
64
65/// Returns [ScriptsData] of the smart contracts for the partner chain identified by `genesis_utxo`.
66pub fn get_scripts_data(
67	genesis_utxo: UtxoId,
68	network: NetworkIdKind,
69) -> anyhow::Result<ScriptsData> {
70	let version_oracle_data = version_oracle(genesis_utxo, network)?;
71	let committee_candidate_validator =
72		plutus_script![COMMITTEE_CANDIDATE_VALIDATOR, genesis_utxo]?;
73	let d_parameter_data = d_parameter_scripts(genesis_utxo, network)?;
74	let permissioned_candidates_data = permissioned_candidates_scripts(genesis_utxo, network)?;
75	let reserve = reserve_scripts(genesis_utxo, network)?;
76	let ics = ics_scripts(genesis_utxo, network)?;
77	let governed_map_data = governed_map_scripts(genesis_utxo, network)?;
78	Ok(ScriptsData {
79		addresses: Addresses {
80			committee_candidate_validator: committee_candidate_validator.address_bech32(network)?,
81			d_parameter_validator: d_parameter_data.validator_address.clone(),
82			illiquid_circulation_supply_validator: ics.validator.address_bech32(network)?,
83			permissioned_candidates_validator: permissioned_candidates_data
84				.validator_address
85				.clone(),
86			reserve_validator: reserve.validator.address_bech32(network)?,
87			version_oracle_validator: version_oracle_data.validator_address.clone(),
88			governed_map_validator: governed_map_data.validator_address.clone(),
89		},
90		policy_ids: PolicyIds {
91			d_parameter: d_parameter_data.policy_id(),
92			permissioned_candidates: permissioned_candidates_data.policy_id(),
93			reserve_auth: reserve.auth_policy.policy_id(),
94			version_oracle: version_oracle_data.policy_id(),
95			governed_map: governed_map_data.policy_id(),
96			illiquid_circulation_supply_auth_token: ics.auth_policy.policy_id(),
97		},
98	})
99}
100
101/// Returns [ScriptsData] of the smart contracts for the partner chain identified by `genesis_utxo`,
102/// for the network configured in `client`.
103pub async fn get_scripts_data_with_ogmios(
104	genesis_utxo: UtxoId,
105	client: &impl QueryNetwork,
106) -> anyhow::Result<ScriptsData> {
107	let network = client.shelley_genesis_configuration().await?.network.to_csl();
108	get_scripts_data(genesis_utxo, network)
109}
110
111/// Type representing a PlutusScript validator and policy pair.
112pub struct PlutusScriptData {
113	/// Cardano validator script.
114	pub validator: PlutusScript,
115	/// Bech32 address of `validator`.
116	pub validator_address: String,
117	/// Cardano minding policy.
118	pub policy: PlutusScript,
119}
120
121impl PlutusScriptData {
122	/// Returns [PolicyId] of [PlutusScriptData].
123	pub fn policy_id(&self) -> PolicyId {
124		self.policy.policy_id()
125	}
126
127	/// Returns [PolicyId] of [PlutusScriptData] as [PlutusData].
128	pub fn policy_id_as_plutus_data(&self) -> PlutusData {
129		PlutusData::BoundedBytes(self.policy.script_hash().to_vec().into())
130	}
131}
132
133/// Returns version oracle data required by other scripts.
134pub fn version_oracle(
135	genesis_utxo: UtxoId,
136	network: NetworkIdKind,
137) -> Result<PlutusScriptData, anyhow::Error> {
138	let validator = plutus_script![VERSION_ORACLE_VALIDATOR, genesis_utxo]?;
139	let validator_address = validator.address_bech32(network)?;
140	let policy =
141		plutus_script![VERSION_ORACLE_POLICY, genesis_utxo, validator.address_data(network)?]?;
142	Ok(PlutusScriptData { validator, validator_address, policy })
143}
144
145pub(crate) fn governed_map_scripts(
146	genesis_utxo: UtxoId,
147	network: NetworkIdKind,
148) -> Result<PlutusScriptData, anyhow::Error> {
149	let version_oracle_data = version_oracle(genesis_utxo, network)?;
150	let validator = plutus_script![
151		GOVERNED_MAP_VALIDATOR,
152		ScriptId::GovernedMapValidator,
153		genesis_utxo,
154		version_oracle_data.policy_id()
155	]?;
156	let validator_address = validator.address_bech32(network)?;
157	let policy = plutus_script![
158		GOVERNED_MAP_POLICY,
159		ScriptId::GovernedMapPolicy,
160		genesis_utxo,
161		version_oracle_data.policy_id()
162	]?;
163	Ok(PlutusScriptData { validator, validator_address, policy })
164}
165
166pub(crate) fn d_parameter_scripts(
167	genesis_utxo: UtxoId,
168	network: NetworkIdKind,
169) -> Result<PlutusScriptData, anyhow::Error> {
170	let version_oracle_data = version_oracle(genesis_utxo, network)?;
171	let validator =
172		plutus_script![D_PARAMETER_VALIDATOR, genesis_utxo, version_oracle_data.policy_id()]?;
173	let validator_address = validator.address_bech32(network)?;
174	let policy = plutus_script![
175		D_PARAMETER_POLICY,
176		genesis_utxo,
177		version_oracle_data.policy_id(),
178		validator.address_data(network)?
179	]?;
180	Ok(PlutusScriptData { validator, validator_address, policy })
181}
182
183pub(crate) fn permissioned_candidates_scripts(
184	genesis_utxo: UtxoId,
185	network: NetworkIdKind,
186) -> Result<PlutusScriptData, anyhow::Error> {
187	let version_oracle_data = version_oracle(genesis_utxo, network)?;
188	let validator = plutus_script![
189		PERMISSIONED_CANDIDATES_VALIDATOR,
190		genesis_utxo,
191		version_oracle_data.policy_id()
192	]?;
193	let validator_address = validator.address_bech32(network)?;
194	let policy = plutus_script![
195		PERMISSIONED_CANDIDATES_POLICY,
196		genesis_utxo,
197		version_oracle_data.policy_id(),
198		validator.address_data(network)?
199	]?;
200	Ok(PlutusScriptData { validator, validator_address, policy })
201}
202
203pub(crate) fn registered_candidates_scripts(
204	genesis_utxo: UtxoId,
205) -> Result<PlutusScript, anyhow::Error> {
206	let validator = plutus_script![COMMITTEE_CANDIDATE_VALIDATOR, genesis_utxo]?;
207	Ok(validator)
208}
209
210#[derive(Clone, Debug)]
211pub(crate) struct ReserveScripts {
212	pub(crate) validator: PlutusScript,
213	pub(crate) auth_policy: PlutusScript,
214}
215
216#[derive(Clone, Debug)]
217pub(crate) struct ICSScripts {
218	/// Illiquid Circulation Supply validator that prevents unauthorized spending from the bridge
219	pub(crate) validator: PlutusScript,
220	/// Policy of tokens used to maintain some minimal number of UTXOs at the validator.
221	pub(crate) auth_policy: PlutusScript,
222}
223
224pub(crate) fn reserve_scripts(
225	genesis_utxo: UtxoId,
226	network: NetworkIdKind,
227) -> Result<ReserveScripts, anyhow::Error> {
228	let version_oracle_data = version_oracle(genesis_utxo, network)?;
229	let validator =
230		plutus_script![RESERVE_VALIDATOR, version_oracle_data.policy_id_as_plutus_data()]?;
231	let auth_policy =
232		plutus_script![RESERVE_AUTH_POLICY, version_oracle_data.policy_id_as_plutus_data()]?;
233	Ok(ReserveScripts { validator, auth_policy })
234}
235
236pub(crate) fn ics_scripts(
237	genesis_utxo: UtxoId,
238	network: NetworkIdKind,
239) -> Result<ICSScripts, anyhow::Error> {
240	let version_oracle_data = version_oracle(genesis_utxo, network)?;
241	let validator = plutus_script![
242		ILLIQUID_CIRCULATION_SUPPLY_VALIDATOR,
243		version_oracle_data.policy_id_as_plutus_data()
244	]?;
245	let auth_policy = plutus_script![
246		ILLIQUID_CIRCULATION_SUPPLY_AUTHORITY_TOKEN_POLICY,
247		ScriptId::IlliquidCirculationSupplyAuthorityTokenPolicy,
248		version_oracle_data.policy_id_as_plutus_data()
249	]?;
250	Ok(ICSScripts { validator, auth_policy })
251}
252
253#[cfg(test)]
254mod tests {
255	use crate::scripts_data::{Addresses, PolicyIds, ScriptsData};
256	use cardano_serialization_lib::NetworkIdKind;
257	use hex_literal::hex;
258	use pretty_assertions::assert_eq;
259	use sidechain_domain::{McTxHash, PolicyId, UtxoId};
260
261	pub(crate) const TEST_PARAMS: UtxoId = UtxoId {
262		tx_hash: McTxHash(hex!("8ea10040249ad3033ae7c4d4b69e0b2e2b50a90741b783491cb5ddf8ced0d861")),
263		index: sidechain_domain::UtxoIndex(0),
264	};
265
266	pub(crate) fn scripts_data_test_vector() -> ScriptsData {
267		ScriptsData {
268			addresses: Addresses {
269				committee_candidate_validator:
270					"addr_test1wzx9p24eryn2h8xnns583edq82y5qkwey7wgqygzr34y6dqny7nsj".into(),
271				d_parameter_validator:
272					"addr_test1wqq69vap60sf6nw7q75xcqd6ecch95vx6qylju26qgp429szlhwea".into(),
273				permissioned_candidates_validator:
274					"addr_test1wqhp3xkm7ntcy0q9cjnttngx94vyn4a7fgyyk5cegw3rkhc4pjahq".into(),
275				illiquid_circulation_supply_validator:
276					"addr_test1wr6e3h6crn97w8c2fjsw9aqaxyvm8qvny6vwd9w0444v92gk0mgf5".into(),
277				reserve_validator:
278					"addr_test1wqcs6zzh44mk0jny7c07eww7ztdmlgsczuw6syh94rhqfuga5lghq".into(),
279				version_oracle_validator:
280					"addr_test1wpadfxldpsgn3zk5yswm7ygwgmfmawxaj90dl40s77jajfgnker5v".into(),
281				governed_map_validator:
282					"addr_test1wr6unjvhtdvej4txavu5h4mt0xa0uylm39jm9fvg0tmt4pc5h4akm".into(),
283			},
284			policy_ids: PolicyIds {
285				d_parameter: PolicyId(hex!(
286					"95543debb3d64e2c35fd48129d7a3584870ea9db47859c39ee906c1b"
287				)),
288				permissioned_candidates: PolicyId(hex!(
289					"d29bc1e7643976641cd76888009207f20f0e92c1fca7f43deb8f0f0c"
290				)),
291				reserve_auth: PolicyId(hex!(
292					"ace1f66ced961064a5ff96c463ab04543e733a3a530600332304d574"
293				)),
294				version_oracle: PolicyId(hex!(
295					"d3d6eadae137f555653094f67fe29f7beab90d55d04ca05c1ab9d2af"
296				)),
297				governed_map: PolicyId(hex!(
298					"1b7c0fa2b32502b8e92ec529f1fe3931febf0b7829f23dc514d88aa0"
299				)),
300				illiquid_circulation_supply_auth_token: PolicyId(hex!(
301					"904868d6ec966b9a5a5b4bdd73858a17792821e10e99236c63c3b533"
302				)),
303			},
304		}
305	}
306
307	// Expected values are the ones obtained from pc-contracts-cli for the TEST_PARAMS.
308	#[test]
309	fn test_get_scripts_data() {
310		let actual =
311			crate::scripts_data::get_scripts_data(TEST_PARAMS, NetworkIdKind::Testnet).unwrap();
312		assert_eq!(scripts_data_test_vector(), actual);
313	}
314}