1#![cfg_attr(not(feature = "std"), no_std)]
20
21extern crate alloc;
22
23use fp_evm::PrecompileHandle;
24use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo};
25use frame_support::sp_runtime::traits::StaticLookup;
26use frame_support::traits::Currency;
27use pallet_evm::AddressMapping;
28use pallet_identity::legacy::IdentityField;
29use parity_scale_codec::MaxEncodedLen;
30use precompile_utils::prelude::*;
31use sp_core::{ConstU32, Get, H160, H256, U256};
32use sp_runtime::traits::Dispatchable;
33use sp_std::boxed::Box;
34use sp_std::marker::PhantomData;
35use sp_std::vec::Vec;
36
37#[cfg(test)]
38mod mock;
39#[cfg(test)]
40mod tests;
41
42type BalanceOf<T> = <<T as pallet_identity::Config>::Currency as Currency<
43 <T as frame_system::Config>::AccountId,
44>>::Balance;
45
46type IdentityFieldOf<T> = <<T as pallet_identity::Config>::IdentityInformation
47 as pallet_identity::IdentityInformationProvider>::FieldsIdentifier;
48
49pub(crate) const SELECTOR_LOG_IDENTITY_SET: [u8; 32] = keccak256!("IdentitySet(address)");
51pub(crate) const SELECTOR_LOG_IDENTITY_CLEARED: [u8; 32] = keccak256!("IdentityCleared(address)");
52pub(crate) const SELECTOR_LOG_JUDGEMENT_REQUESTED: [u8; 32] =
53 keccak256!("JudgementRequested(address,uint32)");
54pub(crate) const SELECTOR_LOG_JUDGEMENT_UNREQUESTED: [u8; 32] =
55 keccak256!("JudgementUnrequested(address,uint32)");
56pub(crate) const SELECTOR_LOG_JUDGEMENT_GIVEN: [u8; 32] =
57 keccak256!("JudgementGiven(address,uint32)");
58pub(crate) const SELECTOR_LOG_SUB_IDENTITY_ADDED: [u8; 32] =
59 keccak256!("SubIdentityAdded(address,address)");
60pub(crate) const SELECTOR_LOG_SUB_IDENTITY_REMOVED: [u8; 32] =
61 keccak256!("SubIdentityRemoved(address,address)");
62pub(crate) const SELECTOR_LOG_SUB_IDENTITY_REVOKED: [u8; 32] =
63 keccak256!("SubIdentityRevoked(address)");
64
65pub struct IdentityPrecompile<Runtime, MaxAdditionalFields>(
67 PhantomData<(Runtime, MaxAdditionalFields)>,
68);
69
70#[precompile_utils::precompile]
71#[precompile::test_concrete_types(mock::Runtime, mock::MaxAdditionalFields)]
72impl<Runtime, MaxAdditionalFields> IdentityPrecompile<Runtime, MaxAdditionalFields>
73where
74 MaxAdditionalFields: Get<u32> + 'static,
75 Runtime: pallet_evm::Config
76 + pallet_identity::Config<
77 IdentityInformation = pallet_identity::legacy::IdentityInfo<MaxAdditionalFields>,
78 >,
79 Runtime::AccountId: Into<H160>,
80 Runtime::Hash: From<H256>,
81 Runtime::RuntimeCall: Dispatchable<PostInfo = PostDispatchInfo> + GetDispatchInfo,
82 Runtime::RuntimeCall: From<pallet_identity::Call<Runtime>>,
83 BalanceOf<Runtime>: TryFrom<U256> + Into<U256> + solidity::Codec,
84 <Runtime as pallet_evm::Config>::AddressMapping: AddressMapping<Runtime::AccountId>,
85{
86 #[precompile::public("setIdentity((((bool,bytes),(bool,bytes))[],(bool,bytes),(bool,bytes),(bool,bytes),(bool,bytes),(bool,bytes),bool,bytes,(bool,bytes),(bool,bytes)))")]
90 fn set_identity(
91 handle: &mut impl PrecompileHandle,
92 info: IdentityInfo<MaxAdditionalFields>,
93 ) -> EvmResult {
94 let caller = handle.context().caller;
95
96 let event = log1(
97 handle.context().address,
98 SELECTOR_LOG_IDENTITY_SET,
99 solidity::encode_event_data(Address(caller)),
100 );
101 handle.record_log_costs(&[&event])?;
102
103 let info: Box<Runtime::IdentityInformation> = Self::identity_to_input(info)?;
104
105 let call = pallet_identity::Call::<Runtime>::set_identity { info };
106
107 let origin = Runtime::AddressMapping::into_account_id(caller);
108 RuntimeHelper::<Runtime>::try_dispatch(
109 handle,
110 frame_system::RawOrigin::Signed(origin).into(),
111 call,
112 0,
113 )?;
114
115 event.record(handle)?;
116
117 Ok(())
118 }
119
120 #[precompile::public("setSubs((address,(bool,bytes))[])")]
121 fn set_subs(
122 handle: &mut impl PrecompileHandle,
123 subs: BoundedVec<(Address, Data), Runtime::MaxSubAccounts>,
124 ) -> EvmResult {
125 let subs: Vec<_> = subs.into();
126 let mut call_subs = Vec::with_capacity(subs.len());
127 for (i, (addr, data)) in subs.into_iter().enumerate() {
128 let addr = Runtime::AddressMapping::into_account_id(addr.into());
129 let data: pallet_identity::Data = data
130 .try_into()
131 .map_err(|e| RevertReason::custom(e).in_field(alloc::format!("index {i}")))?;
132 call_subs.push((addr, data));
133 }
134 let call = pallet_identity::Call::<Runtime>::set_subs { subs: call_subs };
135
136 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
137 RuntimeHelper::<Runtime>::try_dispatch(
138 handle,
139 frame_system::RawOrigin::Signed(origin).into(),
140 call,
141 0,
142 )?;
143
144 Ok(())
145 }
146
147 #[precompile::public("clearIdentity()")]
148 fn clear_identity(handle: &mut impl PrecompileHandle) -> EvmResult {
149 let caller = handle.context().caller;
150
151 let event = log1(
152 handle.context().address,
153 SELECTOR_LOG_IDENTITY_CLEARED,
154 solidity::encode_event_data(Address(caller)),
155 );
156 handle.record_log_costs(&[&event])?;
157
158 let call = pallet_identity::Call::<Runtime>::clear_identity {};
159
160 let origin = Runtime::AddressMapping::into_account_id(caller);
161 RuntimeHelper::<Runtime>::try_dispatch(
162 handle,
163 frame_system::RawOrigin::Signed(origin).into(),
164 call,
165 0,
166 )?;
167
168 event.record(handle)?;
169
170 Ok(())
171 }
172
173 #[precompile::public("requestJudgement(uint32,uint256)")]
174 fn request_judgement(
175 handle: &mut impl PrecompileHandle,
176 reg_index: u32,
177 max_fee: U256,
178 ) -> EvmResult {
179 let caller = handle.context().caller;
180
181 let event = log1(
182 handle.context().address,
183 SELECTOR_LOG_JUDGEMENT_REQUESTED,
184 solidity::encode_event_data((Address(caller), reg_index)),
185 );
186 handle.record_log_costs(&[&event])?;
187
188 let max_fee = max_fee
189 .try_into()
190 .map_err(|_| RevertReason::value_is_too_large("max_fee"))?;
191 let call = pallet_identity::Call::<Runtime>::request_judgement { reg_index, max_fee };
192
193 let origin = Runtime::AddressMapping::into_account_id(caller);
194 RuntimeHelper::<Runtime>::try_dispatch(
195 handle,
196 frame_system::RawOrigin::Signed(origin).into(),
197 call,
198 0,
199 )?;
200
201 event.record(handle)?;
202
203 Ok(())
204 }
205
206 #[precompile::public("cancelRequest(uint32)")]
207 fn cancel_request(handle: &mut impl PrecompileHandle, reg_index: u32) -> EvmResult {
208 let caller = handle.context().caller;
209
210 let event = log1(
211 handle.context().address,
212 SELECTOR_LOG_JUDGEMENT_UNREQUESTED,
213 solidity::encode_event_data((Address(caller), reg_index)),
214 );
215 handle.record_log_costs(&[&event])?;
216
217 let call = pallet_identity::Call::<Runtime>::cancel_request { reg_index };
218
219 let origin = Runtime::AddressMapping::into_account_id(caller);
220 RuntimeHelper::<Runtime>::try_dispatch(
221 handle,
222 frame_system::RawOrigin::Signed(origin).into(),
223 call,
224 0,
225 )?;
226
227 event.record(handle)?;
228
229 Ok(())
230 }
231
232 #[precompile::public("setFee(uint32,uint256)")]
233 fn set_fee(handle: &mut impl PrecompileHandle, index: u32, fee: U256) -> EvmResult {
234 let fee = fee
235 .try_into()
236 .map_err(|_| RevertReason::value_is_too_large("fee"))?;
237 let call = pallet_identity::Call::<Runtime>::set_fee { index, fee };
238
239 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
240 RuntimeHelper::<Runtime>::try_dispatch(
241 handle,
242 frame_system::RawOrigin::Signed(origin).into(),
243 call,
244 0,
245 )?;
246
247 Ok(())
248 }
249
250 #[precompile::public("setAccountId(uint32,address)")]
251 fn set_account_id(handle: &mut impl PrecompileHandle, index: u32, new: Address) -> EvmResult {
252 let new = Runtime::Lookup::unlookup(Runtime::AddressMapping::into_account_id(new.0));
253 let call = pallet_identity::Call::<Runtime>::set_account_id { index, new };
254
255 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
256 RuntimeHelper::<Runtime>::try_dispatch(
257 handle,
258 frame_system::RawOrigin::Signed(origin).into(),
259 call,
260 0,
261 )?;
262
263 Ok(())
264 }
265
266 #[precompile::public("setFields(uint32,(bool,bool,bool,bool,bool,bool,bool,bool))")]
267 fn set_fields(
268 handle: &mut impl PrecompileHandle,
269 index: u32,
270 fields: IdentityFields,
271 ) -> EvmResult {
272 let fields = Self::identity_fields_to_input(fields);
273 let call = pallet_identity::Call::<Runtime>::set_fields { index, fields };
274
275 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
276 RuntimeHelper::<Runtime>::try_dispatch(
277 handle,
278 frame_system::RawOrigin::Signed(origin).into(),
279 call,
280 0,
281 )?;
282
283 Ok(())
284 }
285
286 #[precompile::public(
287 "provideJudgement(uint32,address,(bool,bool,uint256,bool,bool,bool,bool,bool),bytes32)"
288 )]
289 fn provide_judgement(
290 handle: &mut impl PrecompileHandle,
291 reg_index: u32,
292 target: Address,
293 judgement: Judgement,
294 identity: H256,
295 ) -> EvmResult {
296 let caller = handle.context().caller;
297
298 let event = log1(
299 handle.context().address,
300 SELECTOR_LOG_JUDGEMENT_GIVEN,
301 solidity::encode_event_data((target, reg_index)),
302 );
303 handle.record_log_costs(&[&event])?;
304
305 let target = Runtime::Lookup::unlookup(Runtime::AddressMapping::into_account_id(target.0));
306 let judgement = Self::judgment_to_input(judgement)?;
307 let identity: Runtime::Hash = identity.into();
308 let call = pallet_identity::Call::<Runtime>::provide_judgement {
309 reg_index,
310 target,
311 judgement,
312 identity,
313 };
314
315 let origin = Runtime::AddressMapping::into_account_id(caller);
316 RuntimeHelper::<Runtime>::try_dispatch(
317 handle,
318 frame_system::RawOrigin::Signed(origin).into(),
319 call,
320 0,
321 )?;
322
323 event.record(handle)?;
324
325 Ok(())
326 }
327
328 #[precompile::public("addSub(address,(bool,bytes))")]
329 fn add_sub(handle: &mut impl PrecompileHandle, sub: Address, data: Data) -> EvmResult {
330 let caller = handle.context().caller;
331
332 let event = log1(
333 handle.context().address,
334 SELECTOR_LOG_SUB_IDENTITY_ADDED,
335 solidity::encode_event_data((sub, Address(caller))),
336 );
337 handle.record_log_costs(&[&event])?;
338
339 let sub = Runtime::Lookup::unlookup(Runtime::AddressMapping::into_account_id(sub.0));
340 let data: pallet_identity::Data = data
341 .try_into()
342 .map_err(|e| RevertReason::custom(e).in_field("data"))?;
343 let call = pallet_identity::Call::<Runtime>::add_sub { sub, data };
344
345 let origin = Runtime::AddressMapping::into_account_id(caller);
346 RuntimeHelper::<Runtime>::try_dispatch(
347 handle,
348 frame_system::RawOrigin::Signed(origin).into(),
349 call,
350 0,
351 )?;
352
353 event.record(handle)?;
354
355 Ok(())
356 }
357
358 #[precompile::public("renameSub(address,(bool,bytes))")]
359 fn rename_sub(handle: &mut impl PrecompileHandle, sub: Address, data: Data) -> EvmResult {
360 let sub = Runtime::Lookup::unlookup(Runtime::AddressMapping::into_account_id(sub.0));
361 let data: pallet_identity::Data = data
362 .try_into()
363 .map_err(|e| RevertReason::custom(e).in_field("data"))?;
364 let call = pallet_identity::Call::<Runtime>::rename_sub { sub, data };
365
366 let origin = Runtime::AddressMapping::into_account_id(handle.context().caller);
367 RuntimeHelper::<Runtime>::try_dispatch(
368 handle,
369 frame_system::RawOrigin::Signed(origin).into(),
370 call,
371 0,
372 )?;
373
374 Ok(())
375 }
376
377 #[precompile::public("removeSub(address)")]
378 fn remove_sub(handle: &mut impl PrecompileHandle, sub: Address) -> EvmResult {
379 let caller = handle.context().caller;
380
381 let event = log1(
382 handle.context().address,
383 SELECTOR_LOG_SUB_IDENTITY_REMOVED,
384 solidity::encode_event_data((sub, Address(caller))),
385 );
386 handle.record_log_costs(&[&event])?;
387
388 let sub = Runtime::Lookup::unlookup(Runtime::AddressMapping::into_account_id(sub.0));
389 let call = pallet_identity::Call::<Runtime>::remove_sub { sub };
390
391 let origin = Runtime::AddressMapping::into_account_id(caller);
392 RuntimeHelper::<Runtime>::try_dispatch(
393 handle,
394 frame_system::RawOrigin::Signed(origin).into(),
395 call,
396 0,
397 )?;
398
399 event.record(handle)?;
400
401 Ok(())
402 }
403
404 #[precompile::public("quitSub()")]
405 fn quit_sub(handle: &mut impl PrecompileHandle) -> EvmResult {
406 let caller = handle.context().caller;
407
408 let event = log1(
409 handle.context().address,
410 SELECTOR_LOG_SUB_IDENTITY_REVOKED,
411 solidity::encode_event_data(Address(caller)),
412 );
413 handle.record_log_costs(&[&event])?;
414
415 let call = pallet_identity::Call::<Runtime>::quit_sub {};
416
417 let origin = Runtime::AddressMapping::into_account_id(caller);
418 RuntimeHelper::<Runtime>::try_dispatch(
419 handle,
420 frame_system::RawOrigin::Signed(origin).into(),
421 call,
422 0,
423 )?;
424
425 event.record(handle)?;
426
427 Ok(())
428 }
429
430 #[precompile::public("identity(address)")]
431 #[precompile::view]
432 fn identity(
433 handle: &mut impl PrecompileHandle,
434 who: Address,
435 ) -> EvmResult<Registration<MaxAdditionalFields>> {
436 handle.record_db_read::<Runtime>(pallet_identity::Registration::<
439 BalanceOf<Runtime>,
440 Runtime::MaxRegistrars,
441 Runtime::IdentityInformation,
442 >::max_encoded_len())?;
443
444 let who: H160 = who.into();
445 let who = Runtime::AddressMapping::into_account_id(who);
446 let identity = pallet_identity::IdentityOf::<Runtime>::get(who);
447
448 Ok(Self::identity_to_output(identity)?)
449 }
450
451 #[precompile::public("superOf(address)")]
452 #[precompile::view]
453 fn super_of(handle: &mut impl PrecompileHandle, who: Address) -> EvmResult<SuperOf> {
454 handle.record_db_read::<Runtime>(
456 Runtime::AccountId::max_encoded_len()
457 .saturating_add(pallet_identity::Data::max_encoded_len()),
458 )?;
459
460 let who: H160 = who.into();
461 let who = Runtime::AddressMapping::into_account_id(who);
462 if let Some((account, data)) = pallet_identity::SuperOf::<Runtime>::get(who) {
463 Ok(SuperOf {
464 is_valid: true,
465 account: Address(account.into()),
466 data: Self::data_to_output(data),
467 })
468 } else {
469 Ok(SuperOf::default())
470 }
471 }
472
473 #[precompile::public("subsOf(address)")]
474 #[precompile::view]
475 fn subs_of(handle: &mut impl PrecompileHandle, who: Address) -> EvmResult<SubsOf> {
476 handle.record_db_read::<Runtime>(
478 BalanceOf::<Runtime>::max_encoded_len().saturating_add(
479 Runtime::AccountId::max_encoded_len()
480 .saturating_mul(Runtime::MaxSubAccounts::get() as usize),
481 ),
482 )?;
483
484 let who: H160 = who.into();
485 let who = Runtime::AddressMapping::into_account_id(who);
486 let (deposit, accounts) = pallet_identity::SubsOf::<Runtime>::get(who);
487
488 let accounts = accounts
489 .into_iter()
490 .map(|account| Address(account.into()))
491 .collect();
492
493 Ok(SubsOf {
494 deposit: deposit.into(),
495 accounts,
496 })
497 }
498
499 #[precompile::public("registrars()")]
500 #[precompile::view]
501 fn registrars(handle: &mut impl PrecompileHandle) -> EvmResult<Vec<Registrar>> {
502 handle.record_db_read::<Runtime>(
505 pallet_identity::RegistrarInfo::<
506 BalanceOf<Runtime>,
507 Runtime::AccountId,
508 IdentityFieldOf<Runtime>,
509 >::max_encoded_len()
510 .saturating_mul(Runtime::MaxRegistrars::get() as usize),
511 )?;
512
513 let registrars = pallet_identity::Registrars::<Runtime>::get()
514 .into_iter()
515 .enumerate()
516 .map(|(index, maybe_reg)| {
517 if let Some(reg) = maybe_reg {
518 let fields: u64 = reg.fields.into();
519 Registrar {
520 is_valid: true,
521 index: index as u32,
522 account: Address(reg.account.into()),
523 fee: reg.fee.into(),
524 fields: IdentityFields {
525 display: fields & (IdentityField::Display as u64)
526 == (IdentityField::Display as u64),
527 legal: fields & (IdentityField::Legal as u64)
528 == (IdentityField::Legal as u64),
529 web: fields & (IdentityField::Web as u64)
530 == (IdentityField::Web as u64),
531 riot: fields & (IdentityField::Riot as u64)
532 == (IdentityField::Riot as u64),
533 email: fields & (IdentityField::Email as u64)
534 == (IdentityField::Email as u64),
535 pgp_fingerprint: fields & (IdentityField::PgpFingerprint as u64)
536 == (IdentityField::PgpFingerprint as u64),
537 image: fields & (IdentityField::Image as u64)
538 == (IdentityField::Image as u64),
539 twitter: fields & (IdentityField::Twitter as u64)
540 == (IdentityField::Twitter as u64),
541 },
542 }
543 } else {
544 Registrar {
545 is_valid: false,
546 index: index as u32,
547 ..Default::default()
548 }
549 }
550 })
551 .collect();
552
553 Ok(registrars)
554 }
555
556 fn identity_fields_to_input(fields: IdentityFields) -> IdentityFieldOf<Runtime> {
557 let mut field_bits = 0u64;
558 if fields.display {
559 field_bits = field_bits | IdentityField::Display as u64;
560 }
561 if fields.legal {
562 field_bits = field_bits | IdentityField::Legal as u64;
563 }
564 if fields.web {
565 field_bits = field_bits | IdentityField::Web as u64;
566 }
567 if fields.riot {
568 field_bits = field_bits | IdentityField::Riot as u64;
569 }
570 if fields.email {
571 field_bits = field_bits | IdentityField::Email as u64;
572 }
573 if fields.pgp_fingerprint {
574 field_bits = field_bits | IdentityField::PgpFingerprint as u64;
575 }
576 if fields.image {
577 field_bits = field_bits | IdentityField::Image as u64;
578 }
579 if fields.twitter {
580 field_bits = field_bits | IdentityField::Twitter as u64;
581 }
582
583 IdentityFieldOf::<Runtime>::from(field_bits)
584 }
585
586 fn identity_to_input(
587 info: IdentityInfo<MaxAdditionalFields>,
588 ) -> MayRevert<Box<pallet_identity::legacy::IdentityInfo<MaxAdditionalFields>>> {
589 let mut additional: sp_runtime::BoundedVec<
591 (pallet_identity::Data, pallet_identity::Data),
592 MaxAdditionalFields,
593 > = Default::default();
594 let iter: Vec<_> = info.additional.into();
595 for (i, (k, v)) in iter.into_iter().enumerate() {
596 let k: pallet_identity::Data = k.try_into().map_err(|e| {
597 RevertReason::custom(e).in_field(alloc::format!("additional.{i}.key"))
598 })?;
599 let v: pallet_identity::Data = v.try_into().map_err(|e| {
600 RevertReason::custom(e).in_field(alloc::format!("additional.{i}.value"))
601 })?;
602 additional
603 .try_push((k, v))
604 .map_err(|_| RevertReason::custom("out of bounds").in_field("additional"))?;
605 }
606
607 let pgp_fingerprint: Option<[u8; 20]> = if info.has_pgp_fingerprint {
608 let fingerprint: Vec<_> = info.pgp_fingerprint.into();
609 let fingerprint = fingerprint
610 .try_into()
611 .map_err(|_| RevertReason::custom("pgp_fingerprint must be 20 bytes long"))?;
612 Some(fingerprint)
613 } else {
614 None
615 };
616 let identity_info = pallet_identity::legacy::IdentityInfo::<MaxAdditionalFields> {
617 additional,
618 display: info
619 .display
620 .try_into()
621 .map_err(|e| RevertReason::custom(e).in_field("display"))?,
622 legal: info
623 .legal
624 .try_into()
625 .map_err(|e| RevertReason::custom(e).in_field("legal"))?,
626 web: info
627 .web
628 .try_into()
629 .map_err(|e| RevertReason::custom(e).in_field("web"))?,
630 riot: info
631 .riot
632 .try_into()
633 .map_err(|e| RevertReason::custom(e).in_field("riot"))?,
634 email: info
635 .email
636 .try_into()
637 .map_err(|e| RevertReason::custom(e).in_field("email"))?,
638 pgp_fingerprint,
639 image: info
640 .image
641 .try_into()
642 .map_err(|e| RevertReason::custom(e).in_field("image"))?,
643 twitter: info
644 .twitter
645 .try_into()
646 .map_err(|e| RevertReason::custom(e).in_field("twitter"))?,
647 };
648
649 Ok(Box::new(identity_info))
650 }
651
652 fn identity_to_output(
653 registration: Option<
654 pallet_identity::Registration<
655 BalanceOf<Runtime>,
656 Runtime::MaxRegistrars,
657 Runtime::IdentityInformation,
658 >,
659 >,
660 ) -> MayRevert<Registration<MaxAdditionalFields>> {
661 let Some(registration) = registration else {
662 return Ok(Registration::<MaxAdditionalFields>::default());
663 };
664
665 let mut identity_info = IdentityInfo::<MaxAdditionalFields> {
666 additional: Default::default(),
667 display: Self::data_to_output(registration.info.display),
668 legal: Self::data_to_output(registration.info.legal),
669 web: Self::data_to_output(registration.info.web),
670 riot: Self::data_to_output(registration.info.riot),
671 email: Self::data_to_output(registration.info.email),
672 has_pgp_fingerprint: false,
673 pgp_fingerprint: Default::default(),
674 image: Self::data_to_output(registration.info.image),
675 twitter: Self::data_to_output(registration.info.twitter),
676 };
677
678 let mut additional = Vec::new();
679 for (k, v) in registration.info.additional.into_iter() {
680 let k: Data = Self::data_to_output(k);
681 let v: Data = Self::data_to_output(v);
682 additional.push((k, v));
683 }
684
685 if let Some(pgp_fingerprint) = registration.info.pgp_fingerprint {
686 identity_info.has_pgp_fingerprint = true;
687 identity_info.pgp_fingerprint = pgp_fingerprint.into();
688 }
689
690 identity_info.additional = additional.into();
691
692 let mut judgements = Vec::new();
693 for (index, judgement) in registration.judgements.into_iter() {
694 judgements.push((index, Self::judgement_to_output(judgement)));
695 }
696
697 let reg = Registration::<MaxAdditionalFields> {
698 is_valid: true,
699 judgements: judgements.into(),
700 deposit: registration.deposit.into(),
701 info: identity_info,
702 };
703
704 Ok(reg)
705 }
706
707 fn judgement_to_output(value: pallet_identity::Judgement<BalanceOf<Runtime>>) -> Judgement {
708 let mut judgement = Judgement::default();
709
710 match value {
711 pallet_identity::Judgement::Unknown => {
712 judgement.is_unknown = true;
713 }
714 pallet_identity::Judgement::FeePaid(balance) => {
715 judgement.is_fee_paid = true;
716 judgement.fee_paid_deposit = balance.into();
717 }
718 pallet_identity::Judgement::Reasonable => {
719 judgement.is_reasonable = true;
720 }
721 pallet_identity::Judgement::KnownGood => {
722 judgement.is_known_good = true;
723 }
724 pallet_identity::Judgement::OutOfDate => {
725 judgement.is_out_of_date = true;
726 }
727 pallet_identity::Judgement::LowQuality => {
728 judgement.is_low_quality = true;
729 }
730 pallet_identity::Judgement::Erroneous => {
731 judgement.is_erroneous = true;
732 }
733 };
734
735 judgement
736 }
737
738 fn judgment_to_input(
739 value: Judgement,
740 ) -> Result<pallet_identity::Judgement<BalanceOf<Runtime>>, RevertReason> {
741 if value.is_unknown {
742 return Ok(pallet_identity::Judgement::Unknown);
743 }
744
745 if value.is_fee_paid {
746 let amount: BalanceOf<Runtime> = value
747 .fee_paid_deposit
748 .try_into()
749 .map_err(|_| RevertReason::value_is_too_large("fee_paid_deposit").into())?;
750
751 return Ok(pallet_identity::Judgement::FeePaid(amount));
752 }
753
754 if value.is_reasonable {
755 return Ok(pallet_identity::Judgement::Reasonable);
756 }
757
758 if value.is_known_good {
759 return Ok(pallet_identity::Judgement::KnownGood);
760 }
761
762 if value.is_out_of_date {
763 return Ok(pallet_identity::Judgement::OutOfDate);
764 }
765
766 if value.is_low_quality {
767 return Ok(pallet_identity::Judgement::LowQuality);
768 }
769
770 if value.is_erroneous {
771 return Ok(pallet_identity::Judgement::Erroneous);
772 }
773
774 return Err(RevertReason::custom("invalid"));
775 }
776
777 fn data_to_output(data: pallet_identity::Data) -> Data {
778 let mut output = Data::default();
779 match data {
780 pallet_identity::Data::None => (),
781 pallet_identity::Data::Raw(bytes) => {
782 let bytes: Vec<_> = bytes.into();
783 output.has_data = true;
784 output.value = bytes.into();
785 }
786 pallet_identity::Data::BlakeTwo256(bytes) => {
787 output.has_data = true;
788 output.value = bytes.into();
789 }
790 pallet_identity::Data::Sha256(bytes) => {
791 output.has_data = true;
792 output.value = bytes.into();
793 }
794 pallet_identity::Data::Keccak256(bytes) => {
795 output.has_data = true;
796 output.value = bytes.into();
797 }
798 pallet_identity::Data::ShaThree256(bytes) => {
799 output.has_data = true;
800 output.value = bytes.into();
801 }
802 }
803
804 output
805 }
806}
807
808#[derive(Default, Debug, Eq, PartialEq, solidity::Codec)]
809pub struct Data {
810 has_data: bool,
811 value: BoundedBytes<ConstU32<32>>,
812}
813
814impl TryFrom<Data> for pallet_identity::Data {
815 type Error = &'static str;
816
817 fn try_from(value: Data) -> Result<Self, Self::Error> {
818 if !value.has_data {
819 return Ok(pallet_identity::Data::None);
820 }
821
822 let value: Vec<_> = value.value.into();
823 let value: sp_runtime::BoundedVec<_, ConstU32<32>> =
824 value.try_into().map_err(|_| "exceeded bounds")?;
825 Ok(pallet_identity::Data::Raw(value))
826 }
827}
828
829#[derive(Eq, PartialEq, Debug, solidity::Codec)]
830pub struct Additional {
831 key: Data,
832 value: Data,
833}
834
835#[derive(Eq, PartialEq, Debug, solidity::Codec)]
836pub struct IdentityInfo<FieldLimit> {
837 additional: BoundedVec<(Data, Data), FieldLimit>,
838 display: Data,
839 legal: Data,
840 web: Data,
841 riot: Data,
842 email: Data,
843 has_pgp_fingerprint: bool,
844 pgp_fingerprint: BoundedBytes<ConstU32<20>>,
845 image: Data,
846 twitter: Data,
847}
848
849impl<T> Default for IdentityInfo<T> {
850 fn default() -> Self {
851 Self {
852 additional: Default::default(),
853 display: Default::default(),
854 legal: Default::default(),
855 web: Default::default(),
856 riot: Default::default(),
857 email: Default::default(),
858 has_pgp_fingerprint: Default::default(),
859 pgp_fingerprint: Default::default(),
860 image: Default::default(),
861 twitter: Default::default(),
862 }
863 }
864}
865
866#[derive(Eq, PartialEq, Default, Debug, solidity::Codec)]
867pub struct Judgement {
868 is_unknown: bool,
869 is_fee_paid: bool,
870 fee_paid_deposit: U256,
871 is_reasonable: bool,
872 is_known_good: bool,
873 is_out_of_date: bool,
874 is_low_quality: bool,
875 is_erroneous: bool,
876}
877
878#[derive(Eq, PartialEq, Debug, solidity::Codec)]
879pub struct Registration<FieldLimit> {
880 is_valid: bool,
881 judgements: Vec<(u32, Judgement)>,
882 deposit: U256,
883 info: IdentityInfo<FieldLimit>,
884}
885
886impl<T> Default for Registration<T> {
887 fn default() -> Self {
888 Self {
889 is_valid: false,
890 judgements: Vec::new(),
891 deposit: Default::default(),
892 info: Default::default(),
893 }
894 }
895}
896
897#[derive(Default, Debug, solidity::Codec)]
898pub struct SuperOf {
899 is_valid: bool,
900 account: Address,
901 data: Data,
902}
903
904#[derive(Default, Debug, solidity::Codec)]
905pub struct SubsOf {
906 deposit: U256,
907 accounts: Vec<Address>,
908}
909
910#[derive(Default, Debug, solidity::Codec)]
911pub struct IdentityFields {
912 display: bool,
913 legal: bool,
914 web: bool,
915 riot: bool,
916 email: bool,
917 pgp_fingerprint: bool,
918 image: bool,
919 twitter: bool,
920}
921
922#[derive(Default, Debug, solidity::Codec)]
923pub struct Registrar {
924 is_valid: bool,
925 index: u32,
926 account: Address,
927 fee: U256,
928 fields: IdentityFields,
929}