1use scale_info::PortableRegistry;
29use sp_core::{sr25519, Pair};
30use subxt::{
31 config::{
32 substrate::SubstrateConfig,
33 transaction_extensions::{
34 ChargeAssetTxPayment, ChargeTransactionPayment, CheckGenesis, CheckMetadataHash,
35 CheckMortality, CheckNonce, CheckSpecVersion, CheckTxVersion, VerifySignature,
36 },
37 ClientState, Config, DefaultExtrinsicParamsBuilder, TransactionExtension,
38 TransactionExtensions,
39 },
40 dynamic::Value,
41 ext::{frame_decode, scale_value::value},
42 transactions::Signer,
43 utils::H256,
44 OnlineClient,
45};
46
47pub struct VerifyMultiSignature<T: Config>(VerifySignature<T>);
49
50impl<T: Config> frame_decode::extrinsics::TransactionExtension<PortableRegistry>
51 for VerifyMultiSignature<T>
52{
53 const NAME: &str = "VerifyMultiSignature";
54
55 fn encode_value_to(
56 &self,
57 type_id: u32,
58 type_resolver: &PortableRegistry,
59 v: &mut Vec<u8>,
60 ) -> Result<(), frame_decode::extrinsics::TransactionExtensionError> {
61 self.0.encode_value_to(type_id, type_resolver, v)
62 }
63
64 fn encode_value_for_signer_payload_to(
65 &self,
66 type_id: u32,
67 type_resolver: &PortableRegistry,
68 v: &mut Vec<u8>,
69 ) -> Result<(), frame_decode::extrinsics::TransactionExtensionError> {
70 self.0.encode_value_for_signer_payload_to(type_id, type_resolver, v)
71 }
72
73 fn encode_implicit_to(
74 &self,
75 type_id: u32,
76 type_resolver: &PortableRegistry,
77 v: &mut Vec<u8>,
78 ) -> Result<(), frame_decode::extrinsics::TransactionExtensionError> {
79 self.0.encode_implicit_to(type_id, type_resolver, v)
80 }
81}
82
83impl<T: Config> TransactionExtension<T> for VerifyMultiSignature<T> {
84 type Decoded = <VerifySignature<T> as TransactionExtension<T>>::Decoded;
85 type Params = ();
86
87 fn new(
88 client: &ClientState<T>,
89 params: Self::Params,
90 ) -> Result<Self, subxt::error::TransactionExtensionError> {
91 Ok(VerifyMultiSignature(VerifySignature::new(client, params)?))
92 }
93
94 fn inject_signature(&mut self, account_id: &T::AccountId, signature: &T::Signature) {
95 self.0.inject_signature(account_id, signature);
96 }
97}
98
99pub struct RestrictOrigins;
105
106impl frame_decode::extrinsics::TransactionExtension<PortableRegistry> for RestrictOrigins {
107 const NAME: &str = "RestrictOrigins";
108
109 fn encode_value_to(
110 &self,
111 _type_id: u32,
112 _type_resolver: &PortableRegistry,
113 v: &mut Vec<u8>,
114 ) -> Result<(), frame_decode::extrinsics::TransactionExtensionError> {
115 v.push(0x00);
117 Ok(())
118 }
119
120 fn encode_implicit_to(
121 &self,
122 _type_id: u32,
123 _type_resolver: &PortableRegistry,
124 _v: &mut Vec<u8>,
125 ) -> Result<(), frame_decode::extrinsics::TransactionExtensionError> {
126 Ok(())
127 }
128}
129
130impl<T: Config> TransactionExtension<T> for RestrictOrigins {
131 type Decoded = u8;
132 type Params = ();
133
134 fn new(
135 _client: &ClientState<T>,
136 _params: Self::Params,
137 ) -> Result<Self, subxt::error::TransactionExtensionError> {
138 Ok(RestrictOrigins)
139 }
140}
141
142#[derive(Debug, Clone)]
147pub struct CustomConfig(SubstrateConfig);
148
149impl Default for CustomConfig {
150 fn default() -> Self {
151 CustomConfig(SubstrateConfig::new())
152 }
153}
154
155impl Config for CustomConfig {
156 type AccountId = <SubstrateConfig as Config>::AccountId;
157 type Address = subxt::utils::MultiAddress<Self::AccountId, ()>;
158 type Signature = <SubstrateConfig as Config>::Signature;
159 type Hasher = <SubstrateConfig as Config>::Hasher;
160 type Header = <SubstrateConfig as Config>::Header;
161 type AssetId = <SubstrateConfig as Config>::AssetId;
162 type TransactionExtensions = (
163 VerifyMultiSignature<Self>,
164 CheckSpecVersion,
165 CheckTxVersion,
166 CheckNonce,
167 CheckGenesis<Self>,
168 CheckMortality<Self>,
169 ChargeAssetTxPayment<Self>,
170 ChargeTransactionPayment,
171 CheckMetadataHash,
172 RestrictOrigins,
173 );
174
175 fn genesis_hash(&self) -> Option<subxt::config::HashFor<Self>> {
176 self.0.genesis_hash()
177 }
178
179 fn spec_and_transaction_version_for_block_number(
180 &self,
181 block_number: u64,
182 ) -> Option<(u32, u32)> {
183 self.0.spec_and_transaction_version_for_block_number(block_number)
184 }
185
186 fn metadata_for_spec_version(&self, spec_version: u32) -> Option<subxt::metadata::ArcMetadata> {
187 self.0.metadata_for_spec_version(spec_version)
188 }
189
190 fn set_metadata_for_spec_version(
191 &self,
192 spec_version: u32,
193 metadata: subxt::metadata::ArcMetadata,
194 ) {
195 self.0.set_metadata_for_spec_version(spec_version, metadata)
196 }
197}
198
199fn build_params(
201 nonce: u64,
202) -> <<CustomConfig as Config>::TransactionExtensions as TransactionExtensions<CustomConfig>>::Params
203{
204 let (a, b, c, d, e, f, g, h, i) = DefaultExtrinsicParamsBuilder::<CustomConfig>::new()
205 .immortal()
206 .nonce(nonce)
207 .build();
208 (a, b, c, d, e, f, g, h, i, ())
209}
210
211pub async fn submit_extrinsic<S: Signer<CustomConfig>>(
213 client: &OnlineClient<CustomConfig>,
214 call: &subxt::transactions::DynamicPayload<Vec<Value>>,
215 signer: &S,
216 nonce: u64,
217) -> Result<H256, anyhow::Error> {
218 let tx_in_block = client
219 .tx()
220 .await?
221 .sign_and_submit_then_watch(call, signer, build_params(nonce))
222 .await?
223 .wait_for_finalized()
224 .await?;
225
226 tx_in_block.wait_for_success().await?;
227 Ok(tx_in_block.block_hash())
228}
229
230pub async fn get_account_nonce(
232 client: &OnlineClient<CustomConfig>,
233 account_id: &<CustomConfig as Config>::AccountId,
234) -> Result<u64, anyhow::Error> {
235 let nonce = client.tx().await?.account_nonce(account_id).await?;
236 Ok(nonce)
237}
238
239pub const MSG_PREFIX: &[u8; 30] = b"pop:people-lite:register using";
241
242pub fn create_increase_allowance_call(
244 who: Vec<u8>,
245 count: u32,
246) -> subxt::transactions::DynamicPayload<Vec<Value>> {
247 subxt::tx::dynamic(
248 "Sudo",
249 "sudo",
250 vec![value! {
251 PeopleLite(increase_attestation_allowance {
252 account: Value::from_bytes(who),
253 count: Value::u128(count as u128),
254 })
255 }],
256 )
257}
258
259pub fn create_attest_call(
261 candidate: Vec<u8>,
262 candidate_signature: Vec<u8>,
263 ring_vrf_key: Vec<u8>,
264 proof_of_ownership: Vec<u8>,
265 consumer_registration: Option<Value>,
266) -> subxt::transactions::DynamicPayload<Vec<Value>> {
267 let reg = match consumer_registration {
268 Some(v) => Value::unnamed_variant("Some", [v]),
269 None => Value::unnamed_variant("None", []),
270 };
271 subxt::tx::dynamic(
272 "PeopleLite",
273 "attest",
274 vec![
275 Value::from_bytes(candidate),
276 Value::unnamed_variant("Sr25519", [Value::from_bytes(candidate_signature)]),
277 Value::from_bytes(ring_vrf_key),
278 Value::from_bytes(proof_of_ownership),
279 reg,
280 ],
281 )
282}
283
284pub fn create_consumer_registration_params(
294 consumer_pair: &sr25519::Pair,
295 consumer_account: &[u8; 32],
296 verifier_account: &[u8; 32],
297) -> Value {
298 use sp_core::Encode;
299
300 let identifier_key = [0u8; 65];
301 let username = b"testuser.00";
302 let reserved_username: Option<Vec<u8>> = None;
303
304 let separator_idx = username.iter().position(|b| *b == b'.').unwrap_or(username.len());
308 let username_prefix = &username[..separator_idx];
309 let payload = (
310 consumer_account,
311 verifier_account,
312 &identifier_key,
313 &username_prefix.to_vec(),
314 &reserved_username,
315 )
316 .encode();
317
318 let sig = consumer_pair.sign(&payload);
319 value! {
320 {
321 signature: Value::unnamed_variant("Sr25519", [Value::from_bytes(sig.0.to_vec())]),
322 account: Value::from_bytes(consumer_account.to_vec()),
323 identifier_key: Value::from_bytes(identifier_key.to_vec()),
324 username: Value::from_bytes(username.to_vec()),
325 reserved_username: Value::unnamed_variant("None", []),
326 }
327 }
328}
329
330pub async fn set_allowances_via_sudo(
332 ws_uri: &str,
333 items: Vec<(Vec<u8>, Vec<u8>)>,
334) -> Result<(), anyhow::Error> {
335 log::info!("Setting {} statement allowances via sudo...", items.len());
336
337 let client = OnlineClient::<CustomConfig>::from_insecure_url_with_config(
338 CustomConfig::default(),
339 ws_uri,
340 )
341 .await?;
342 let alice = subxt_signer::sr25519::dev::alice();
343
344 let items_value: Vec<Value> = items
345 .into_iter()
346 .map(|(key, value)| value!((Value::from_bytes(key), Value::from_bytes(value))))
347 .collect();
348 let call = subxt::tx::dynamic(
349 "Sudo",
350 "sudo",
351 vec![value! {
352 System(set_storage { items: items_value })
353 }],
354 );
355
356 client
357 .tx()
358 .await?
359 .sign_and_submit_then_watch_default(&call, &alice)
360 .await?
361 .wait_for_finalized_success()
362 .await?;
363
364 Ok(())
365}