stellar_registry_cli/
contract.rs1use sha2::{Digest, Sha256};
2
3use soroban_rpc as rpc;
4use stellar_cli::{
5 commands::{contract::invoke, NetworkRunnable},
6 config::{self, network::Network, UnresolvedContract},
7 xdr::{self, WriteXdr},
8};
9
10pub trait NetworkContract {
11 fn contract_id(&self) -> Result<stellar_strkey::Contract, config::Error>;
12
13 fn contract_sc_address(&self) -> Result<xdr::ScAddress, config::Error> {
14 Ok(xdr::ScAddress::Contract(xdr::ContractId(xdr::Hash(
15 self.contract_id()?.0,
16 ))))
17 }
18
19 fn invoke_registry(
20 &self,
21 slop: &[&str],
22 fee: Option<&stellar_cli::fee::Args>,
23 view_only: bool,
24 ) -> impl std::future::Future<Output = Result<String, invoke::Error>> + Send;
25
26 fn rpc_client(&self) -> Result<rpc::Client, config::Error>;
27}
28
29impl NetworkContract for config::Args {
30 fn contract_id(&self) -> Result<stellar_strkey::Contract, config::Error> {
31 let Network {
32 network_passphrase, ..
33 } = &self.get_network()?;
34 let contract: UnresolvedContract = unsafe {
35 if let Ok(contract_id) = std::env::var("STELLAR_REGISTRY_CONTRACT_ID") {
36 contract_id.parse()
37 } else {
38 contract_id(network_passphrase).to_string().parse()
39 }
40 .unwrap_unchecked()
41 };
42 Ok(contract.resolve_contract_id(&self.locator, network_passphrase)?)
43 }
44
45 async fn invoke_registry(
46 &self,
47 slop: &[&str],
48 fee: Option<&stellar_cli::fee::Args>,
49 view_only: bool,
50 ) -> Result<String, invoke::Error> {
51 invoke_registry(slop, self, fee, view_only).await
52 }
53
54 fn rpc_client(&self) -> Result<rpc::Client, config::Error> {
55 Ok(rpc::Client::new(&self.get_network()?.rpc_url)?)
56 }
57}
58
59pub fn build_invoke_cmd(
60 slop: &[&str],
61 config: &stellar_cli::config::Args,
62 fee: Option<&stellar_cli::fee::Args>,
63 view_only: bool,
64) -> Result<invoke::Cmd, config::Error> {
65 Ok(invoke::Cmd {
66 contract_id: UnresolvedContract::Resolved(config.contract_id()?),
67 slop: slop.iter().map(Into::into).collect(),
68 config: config.clone(),
69 fee: fee.cloned().unwrap_or_default(),
70 send: view_only.then_some(invoke::Send::No).unwrap_or_default(),
71 ..Default::default()
72 })
73}
74
75pub async fn invoke_registry(
76 slop: &[&str],
77 config: &stellar_cli::config::Args,
78 fee: Option<&stellar_cli::fee::Args>,
79 view_only: bool,
80) -> Result<String, invoke::Error> {
81 Ok(build_invoke_cmd(slop, config, fee, view_only)?
82 .run_against_rpc_server(Some(&stellar_cli::commands::global::Args::default()), None)
83 .await?
84 .into_result()
85 .expect("Failed to parse JSON"))
86}
87
88pub fn stellar_address() -> stellar_strkey::ed25519::PublicKey {
89 "GAMPJROHOAW662FINQ4XQOY2ULX5IEGYXCI4SMZYE75EHQBR6PSTJG3M"
90 .parse()
91 .unwrap()
92}
93
94pub fn contract_id(network_passphrase: &str) -> stellar_strkey::Contract {
95 let network_id = xdr::Hash(Sha256::digest(network_passphrase.as_bytes()).into());
96 let preimage = xdr::HashIdPreimage::ContractId(xdr::HashIdPreimageContractId {
97 network_id,
98 contract_id_preimage: xdr::ContractIdPreimage::Address(
99 xdr::ContractIdPreimageFromAddress {
100 address: xdr::ScAddress::Account(xdr::AccountId(
101 xdr::PublicKey::PublicKeyTypeEd25519(stellar_address().0.into()),
102 )),
103 salt: xdr::Uint256([0; 32]),
104 },
105 ),
106 });
107 let preimage_xdr = preimage
108 .to_xdr(xdr::Limits::none())
109 .expect("HashIdPreimage should not fail encoding to xdr");
110 stellar_strkey::Contract(Sha256::digest(preimage_xdr).into())
111}
112
113#[cfg(test)]
114mod generate_id {
115 use stellar_cli::config::network::passphrase::*;
116
117 fn test_contract_id((passphrase, contract_id): (&str, &str)) {
118 assert_eq!(
119 &super::contract_id(passphrase).to_string(),
120 contract_id,
121 "{passphrase}"
122 );
123 }
124 #[test]
125 fn futurenet() {
126 test_contract_id((
127 FUTURENET,
128 "CACPZCQSLEGF6QOSBF42X6LOUQXQB2EJRDKNKQO6US6ZZH5FD6EB325M",
129 ));
130 }
131
132 #[test]
133 fn testnet() {
134 test_contract_id((
135 TESTNET,
136 "CBCOGWBDGBFWR5LQFKRQUPFIG6OLOON35PBKUPB6C542DFZI3OMBOGHX",
137 ));
138 }
139
140 #[test]
141 fn mainnet() {
142 test_contract_id((
143 MAINNET,
144 "CC3SILHAJ5O75KMSJ5J6I5HV753OTPWEVMZUYHS4QEM2ZTISQRAOMMF4",
145 ));
146 }
147
148 #[test]
149 fn local() {
150 test_contract_id((
151 LOCAL,
152 "CCMHAZ6QTUUF2W4PUBW5BAI6R75BVKIUVHJU6IBQTWCS5RBASDOKHF7T",
153 ));
154 }
155}