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