1use core::hash;
2use std::fmt::Display;
3
4use crate::{
5 tx_builder::SinceSource,
6 types::{
7 omni_lock::{Auth, Identity as IdentityType, IdentityOpt, OmniLockWitnessLock},
8 xudt_rce_mol::SmtProofEntryVec,
9 },
10};
11use ckb_types::{
12 bytes::{BufMut, Bytes, BytesMut},
13 packed::WitnessArgs,
14 prelude::*,
15 H160, H256,
16};
17
18pub use ckb_types::prelude::Pack;
19use enum_repr_derive::{FromEnumToRepr, TryFromReprToEnum};
20use serde::{de::Unexpected, Deserialize, Serialize};
21use std::convert::TryFrom;
22
23use bitflags::bitflags;
24
25use super::{MultisigConfig, OmniUnlockMode};
26use thiserror::Error;
27
28#[derive(
29 Clone,
30 Copy,
31 Serialize,
32 Deserialize,
33 Debug,
34 Hash,
35 Eq,
36 PartialEq,
37 TryFromReprToEnum,
38 FromEnumToRepr,
39)]
40#[repr(u8)]
41#[derive(Default)]
42pub enum IdentityFlag {
43 #[default]
46 PubkeyHash = 0,
47 Ethereum = 1,
49 Eos = 2,
51 Tron = 3,
53 Bitcoin = 4,
55 Dogecoin = 5,
57 Multisig = 6,
59
60 OwnerLock = 0xFC,
64 Exec = 0xFD,
67 Dl = 0xFE,
71}
72
73#[derive(Clone, Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Default)]
74pub struct Identity {
75 flag: IdentityFlag,
77 auth_content: H160,
79}
80
81impl Identity {
82 pub fn new(flag: IdentityFlag, auth_content: H160) -> Self {
84 Identity { flag, auth_content }
85 }
86
87 pub fn new_pubkey_hash(pubkey_hash: H160) -> Self {
91 Self::new(IdentityFlag::PubkeyHash, pubkey_hash)
92 }
93
94 pub fn new_multisig(multisig_config: MultisigConfig) -> Self {
96 let blake160 = multisig_config.hash160();
97 Identity::new(IdentityFlag::Multisig, blake160)
98 }
99 pub fn new_ethereum(pubkey_hash: H160) -> Self {
103 Self::new(IdentityFlag::Ethereum, pubkey_hash)
104 }
105
106 pub fn new_ownerlock(script_hash: H160) -> Self {
110 Self::new(IdentityFlag::OwnerLock, script_hash)
111 }
112
113 pub fn to_smt_key(&self) -> [u8; 32] {
115 let mut ret = [0u8; 32];
116 ret[0] = self.flag as u8;
117 ret[1..21].copy_from_slice(self.auth_content.as_ref());
118 ret
119 }
120
121 pub fn flag(&self) -> IdentityFlag {
123 self.flag
124 }
125 pub fn auth_content(&self) -> &H160 {
127 &self.auth_content
128 }
129
130 pub fn from_slice(slice: &[u8]) -> Result<Self, String> {
132 if slice.len() < 21 {
133 return Err("Not enough bytes to parse".to_string());
134 }
135 let flag = IdentityFlag::try_from(slice[0])
136 .map_err(|e| format!("can't parse {} to valide IdentityFlat.", e))?;
137 let auth_content = H160::from_slice(&slice[1..21]).map_err(|e| e.to_string())?;
138 Ok(Identity { flag, auth_content })
139 }
140}
141
142impl From<Identity> for [u8; 21] {
143 fn from(id: Identity) -> Self {
144 let mut res = [0u8; 21];
145 res[0] = id.flag as u8;
146 res[1..].copy_from_slice(id.auth_content.as_bytes());
147 res
148 }
149}
150
151impl From<Identity> for Vec<u8> {
152 fn from(id: Identity) -> Self {
153 let mut bytes: Vec<u8> = vec![id.flag as u8];
154 bytes.extend(id.auth_content.as_bytes());
155 bytes
156 }
157}
158
159impl From<Identity> for ckb_types::bytes::Bytes {
160 fn from(id: Identity) -> Self {
161 let v: Vec<u8> = id.into();
162 v.into()
163 }
164}
165
166impl Display for Identity {
167 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168 write!(f, "(")?;
169 let alternate = f.alternate();
170 if alternate {
171 write!(f, "0x")?;
172 }
173 write!(f, "{:02x},", self.flag as u8)?;
174 if alternate {
175 write!(f, "0x")?;
176 }
177 for x in self.auth_content.as_bytes() {
178 write!(f, "{:02x}", x)?;
179 }
180 write!(f, ")")?;
181 Ok(())
182 }
183}
184bitflags! {
185 #[derive(Serialize, Deserialize)]
186 pub struct OmniLockFlags: u8 {
187 const ADMIN = 1;
189 const ACP = 1<<1;
191 const TIME_LOCK = 1<<2;
193 const SUPPLY = 1<<3;
195 }
196}
197
198impl Serialize for SmtProofEntryVec {
199 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
200 where
201 S: serde::Serializer,
202 {
203 serializer.serialize_newtype_struct("SmtProofEntryVec", &self.as_bytes())
204 }
205}
206
207impl<'de> Deserialize<'de> for SmtProofEntryVec {
208 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
209 where
210 D: serde::Deserializer<'de>,
211 {
212 let bytes = Bytes::deserialize(deserializer)?;
213 SmtProofEntryVec::from_slice(bytes.as_ref()).map_err(|e| {
214 serde::de::Error::invalid_value(
215 Unexpected::Bytes(bytes.as_ref()),
216 &format!("can not convert the value to SmtProofEntryVec: {}", e).as_str(),
217 )
218 })
219 }
220}
221
222impl hash::Hash for SmtProofEntryVec {
223 fn hash<H>(&self, state: &mut H)
224 where
225 H: hash::Hasher,
226 {
227 self.as_slice().hash(state);
228 }
229}
230
231impl PartialEq for SmtProofEntryVec {
234 fn eq(&self, other: &SmtProofEntryVec) -> bool {
235 self.as_slice() == other.as_slice()
236 }
237}
238impl Eq for SmtProofEntryVec {}
239
240#[derive(Debug, Clone, Eq, PartialEq, Hash)]
242pub struct InfoCellData {
243 pub version: u8,
245 pub current_supply: u128,
247 pub max_supply: u128,
249 pub sudt_script_hash: H256,
251 pub other_data: Vec<u8>,
253}
254
255impl InfoCellData {
256 pub fn new_simple(current_supply: u128, max_supply: u128, sudt_script_hash: H256) -> Self {
262 InfoCellData::new(current_supply, max_supply, sudt_script_hash, vec![])
263 }
264
265 pub fn new(
267 current_supply: u128,
268 max_supply: u128,
269 sudt_script_hash: H256,
270 other_data: Vec<u8>,
271 ) -> Self {
272 InfoCellData {
273 version: 0u8,
274 current_supply,
275 max_supply,
276 sudt_script_hash,
277 other_data,
278 }
279 }
280
281 pub fn pack(&self) -> Bytes {
283 let len = 65 + self.other_data.len();
284 let mut bytes = BytesMut::with_capacity(len);
285 bytes.put_u8(self.version);
286 bytes.put_u128_le(self.current_supply);
287 bytes.put_u128_le(self.max_supply);
288 bytes.extend(self.sudt_script_hash.as_bytes());
289 bytes.extend(&self.other_data);
290 bytes.freeze()
291 }
292}
293
294#[derive(Clone, Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Default)]
296pub struct AdminConfig {
297 rc_type_id: H256,
299 proofs: SmtProofEntryVec,
301 auth: Identity,
303 multisig_config: Option<MultisigConfig>,
305 rce_in_input: bool,
307}
308
309impl AdminConfig {
310 pub fn set_rc_type_id(&mut self, rc_type_id: H256) {
311 self.rc_type_id = rc_type_id;
312 }
313 pub fn set_proofs(&mut self, proofs: SmtProofEntryVec) {
314 self.proofs = proofs;
315 }
316 pub fn rc_type_id(&self) -> &H256 {
317 &self.rc_type_id
318 }
319 pub fn proofs(&self) -> &SmtProofEntryVec {
320 &self.proofs
321 }
322
323 pub fn set_auth(&mut self, auth: Identity) {
325 self.auth = auth;
326 }
327
328 pub fn get_auth(&self) -> &Identity {
330 &self.auth
331 }
332
333 pub fn get_multisig_config(&self) -> Option<&MultisigConfig> {
335 self.multisig_config.as_ref()
336 }
337
338 pub fn set_rce_in_input(&mut self, value: bool) {
340 self.rce_in_input = value;
341 }
342
343 pub fn rce_in_input(&self) -> bool {
345 self.rce_in_input
346 }
347
348 pub fn new(
349 rc_type_id: H256,
350 proofs: SmtProofEntryVec,
351 auth: Identity,
352 multisig_config: Option<MultisigConfig>,
353 rce_in_input: bool,
354 ) -> AdminConfig {
355 AdminConfig {
356 rc_type_id,
357 proofs,
358 auth,
359 multisig_config,
360 rce_in_input,
361 }
362 }
363}
364
365#[derive(Error, Debug)]
366pub enum ConfigError {
367 #[error("there is no admin configuration in the OmniLockConfig")]
368 NoAdminConfig,
369
370 #[error("there is no multisig config in the OmniLockConfig")]
371 NoMultiSigConfig,
372
373 #[error(transparent)]
374 Other(#[from] anyhow::Error),
375}
376
377#[derive(Clone, Serialize, Deserialize, Debug, Hash, Eq, PartialEq, Default)]
378pub struct OmniLockAcpConfig {
379 pub ckb_minimum: u8,
381 pub udt_minimum: u8,
383}
384
385impl OmniLockAcpConfig {
386 pub fn new(ckb_minimum: u8, udt_minimum: u8) -> Self {
387 OmniLockAcpConfig {
388 ckb_minimum,
389 udt_minimum,
390 }
391 }
392}
393
394#[derive(Clone, Serialize, Deserialize, Debug, Hash, Eq, PartialEq)]
403pub struct OmniLockConfig {
404 id: Identity,
406 multisig_config: Option<MultisigConfig>,
408 omni_lock_flags: OmniLockFlags,
410 admin_config: Option<AdminConfig>,
412 acp_config: Option<OmniLockAcpConfig>,
414 time_lock_config: Option<u64>,
416 info_cell: Option<H256>,
418}
419
420impl OmniLockConfig {
421 pub fn new_pubkey_hash(lock_arg: H160) -> Self {
425 Self::new(IdentityFlag::PubkeyHash, lock_arg)
426 }
427
428 pub fn new_multisig(multisig_config: MultisigConfig) -> Self {
429 let blake160 = multisig_config.hash160();
430 OmniLockConfig {
431 id: Identity {
432 flag: IdentityFlag::Multisig,
433 auth_content: blake160,
434 },
435 multisig_config: Some(multisig_config),
436 omni_lock_flags: OmniLockFlags::empty(),
437 admin_config: None,
438 acp_config: None,
439 time_lock_config: None,
440 info_cell: None,
441 }
442 }
443 pub fn new_ethereum(pubkey_hash: H160) -> Self {
460 Self::new(IdentityFlag::Ethereum, pubkey_hash)
461 }
462
463 pub fn new_ownerlock(script_hash: H160) -> Self {
467 Self::new(IdentityFlag::OwnerLock, script_hash)
468 }
469
470 pub fn new(flag: IdentityFlag, auth_content: H160) -> Self {
472 let auth_content = match flag {
473 IdentityFlag::PubkeyHash | IdentityFlag::Ethereum | IdentityFlag::OwnerLock => {
474 auth_content
475 }
476 _ => H160::from_slice(&[0; 20]).unwrap(),
477 };
478
479 OmniLockConfig {
480 id: Identity { flag, auth_content },
481 multisig_config: None,
482 omni_lock_flags: OmniLockFlags::empty(),
483 admin_config: None,
484 acp_config: None,
485 time_lock_config: None,
486 info_cell: None,
487 }
488 }
489
490 pub fn set_admin_config(&mut self, admin_config: AdminConfig) {
494 self.omni_lock_flags.set(OmniLockFlags::ADMIN, true);
495 self.admin_config = Some(admin_config);
496 }
497
498 pub fn clear_admin_config(&mut self) {
500 self.omni_lock_flags.set(OmniLockFlags::ADMIN, false);
501 self.admin_config = None;
502 }
503
504 pub fn set_acp_config(&mut self, acp_config: OmniLockAcpConfig) {
506 self.omni_lock_flags.set(OmniLockFlags::ACP, true);
507 self.acp_config = Some(acp_config);
508 }
509
510 pub fn clear_acp_config(&mut self) {
512 self.omni_lock_flags.set(OmniLockFlags::ACP, false);
513 self.acp_config = None;
514 }
515 pub fn set_time_lock_config(&mut self, since: u64) {
517 self.omni_lock_flags.set(OmniLockFlags::TIME_LOCK, true);
518 self.time_lock_config = Some(since);
519 }
520 pub fn clear_time_lock_config(&mut self) {
522 self.omni_lock_flags.set(OmniLockFlags::TIME_LOCK, false);
523 self.time_lock_config = None;
524 }
525
526 pub fn set_info_cell(&mut self, type_script_hash: H256) {
528 self.omni_lock_flags.set(OmniLockFlags::SUPPLY, true);
529 self.info_cell = Some(type_script_hash);
530 }
531
532 pub fn clear_info_cell(&mut self) {
534 self.omni_lock_flags.set(OmniLockFlags::SUPPLY, false);
535 self.info_cell = None;
536 }
537
538 pub fn id(&self) -> &Identity {
539 &self.id
540 }
541
542 pub fn multisig_config(&self) -> Option<&MultisigConfig> {
545 self.multisig_config.as_ref()
546 }
547
548 pub fn omni_lock_flags(&self) -> &OmniLockFlags {
549 &self.omni_lock_flags
550 }
551
552 pub fn use_rc(&self) -> bool {
553 self.admin_config.is_some()
554 }
555
556 pub fn build_args(&self) -> Bytes {
558 let mut bytes = BytesMut::with_capacity(128);
559
560 bytes.put_u8(self.id.flag as u8);
562 bytes.put(self.id.auth_content.as_ref());
563 bytes.put_u8(self.omni_lock_flags.bits);
564
565 if let Some(config) = self.admin_config.as_ref() {
566 bytes.put(config.rc_type_id.as_bytes());
567 }
568 if let Some(config) = self.acp_config.as_ref() {
569 bytes.put_u8(config.ckb_minimum);
570 bytes.put_u8(config.udt_minimum);
571 }
572 if let Some(since) = self.time_lock_config.as_ref() {
573 bytes.extend(since.to_le_bytes().iter());
574 }
575
576 if let Some(info_cell) = self.info_cell.as_ref() {
577 bytes.extend(info_cell.as_bytes());
578 }
579 bytes.freeze()
580 }
581
582 pub fn get_admin_config(&self) -> Option<&AdminConfig> {
584 self.admin_config.as_ref()
585 }
586
587 pub fn get_info_cell(&self) -> Option<&H256> {
588 self.info_cell.as_ref()
589 }
590
591 pub fn get_args_len(&self) -> usize {
593 let mut len = 22;
594 if self.omni_lock_flags.contains(OmniLockFlags::ADMIN) {
595 len += 32;
596 }
597 if self.omni_lock_flags.contains(OmniLockFlags::ACP) {
598 len += 2;
599 }
600 if self.omni_lock_flags.contains(OmniLockFlags::TIME_LOCK) {
601 len += 8;
602 }
603 if self.omni_lock_flags.contains(OmniLockFlags::SUPPLY) {
604 len += 32;
605 }
606 len
607 }
608
609 pub fn get_since_source(&self) -> SinceSource {
611 if self.omni_lock_flags.contains(OmniLockFlags::TIME_LOCK) {
612 let mut offset = 22;
613 if self.omni_lock_flags.contains(OmniLockFlags::ADMIN) {
614 offset += 32;
615 }
616 if self.omni_lock_flags.contains(OmniLockFlags::ACP) {
617 offset += 2;
618 }
619 SinceSource::LockArgs(offset)
620 } else {
621 SinceSource::Value(0)
622 }
623 }
624
625 pub fn is_pubkey_hash(&self) -> bool {
627 self.id.flag == IdentityFlag::PubkeyHash
628 }
629
630 pub fn is_ethereum(&self) -> bool {
632 self.id.flag == IdentityFlag::Ethereum
633 }
634
635 pub fn is_multisig(&self) -> bool {
637 self.id.flag == IdentityFlag::Multisig
638 }
639
640 pub fn is_ownerlock(&self) -> bool {
642 self.id.flag == IdentityFlag::OwnerLock
643 }
644
645 pub fn placeholder_witness_lock(
646 &self,
647 unlock_mode: OmniUnlockMode,
648 ) -> Result<Bytes, ConfigError> {
649 let mut builder = match self.id.flag {
650 IdentityFlag::PubkeyHash | IdentityFlag::Ethereum => OmniLockWitnessLock::new_builder()
651 .signature(Some(Bytes::from(vec![0u8; 65])).pack()),
652 IdentityFlag::Multisig => {
653 let multisig_config = match unlock_mode {
654 OmniUnlockMode::Admin => self
655 .admin_config
656 .as_ref()
657 .ok_or(ConfigError::NoAdminConfig)?
658 .multisig_config
659 .as_ref()
660 .ok_or(ConfigError::NoMultiSigConfig)?,
661 OmniUnlockMode::Normal => self
662 .multisig_config
663 .as_ref()
664 .ok_or(ConfigError::NoMultiSigConfig)?,
665 };
666 let config_data = multisig_config.to_witness_data();
667 let multisig_len = config_data.len() + multisig_config.threshold() as usize * 65;
668 let mut omni_sig = vec![0u8; multisig_len];
669 omni_sig[..config_data.len()].copy_from_slice(&config_data);
670 OmniLockWitnessLock::new_builder().signature(Some(Bytes::from(omni_sig)).pack())
671 }
672 IdentityFlag::OwnerLock => OmniLockWitnessLock::new_builder(),
673 _ => todo!("to support other placeholder_witness_lock implementions"),
674 };
675
676 if unlock_mode == OmniUnlockMode::Admin {
677 if let Some(config) = self.admin_config.as_ref() {
678 let mut temp = [0u8; 21];
679 temp[0] = config.auth.flag as u8;
680 temp[1..21].copy_from_slice(config.auth.auth_content.as_bytes());
681 let auth = Auth::from_slice(&temp).unwrap();
682 let ident = IdentityType::new_builder()
683 .identity(auth)
684 .proofs(config.proofs.clone())
685 .build();
686
687 let ident_opt = IdentityOpt::new_builder().set(Some(ident)).build();
688 builder = builder.omni_identity(ident_opt);
689 } else {
690 return Err(ConfigError::NoAdminConfig);
691 }
692 }
693 Ok(builder.build().as_bytes())
694 }
695
696 pub fn zero_lock(&self, unlock_mode: OmniUnlockMode) -> Result<Bytes, ConfigError> {
698 let len = self.placeholder_witness_lock(unlock_mode)?.len();
699 Ok(Bytes::from(vec![0u8; len]))
700 }
701
702 pub fn placeholder_witness(
704 &self,
705 unlock_mode: OmniUnlockMode,
706 ) -> Result<WitnessArgs, ConfigError> {
707 match self.id.flag {
708 IdentityFlag::PubkeyHash | IdentityFlag::Ethereum | IdentityFlag::Multisig => {
709 let lock = self.placeholder_witness_lock(unlock_mode)?;
710 Ok(WitnessArgs::new_builder().lock(Some(lock).pack()).build())
711 }
712 IdentityFlag::OwnerLock => {
713 if self.admin_config.is_some() {
714 let lock = self.placeholder_witness_lock(unlock_mode)?;
715 Ok(WitnessArgs::new_builder().lock(Some(lock).pack()).build())
716 } else {
717 Ok(WitnessArgs::default())
718 }
719 }
720 _ => todo!("to support other placeholder_witness implementions"),
721 }
722 }
723}
724
725#[cfg(test)]
726mod tests {
727 use ckb_types::packed::Byte;
728
729 use crate::{
730 types::xudt_rce_mol::{SmtProof, SmtProofEntry, SmtProofEntryVec},
731 unlock::omni_lock::AdminConfig,
732 };
733 use ckb_types::{h256, prelude::*};
734 #[test]
735 fn test_adminconfig_serde() {
736 let mut i = (0u8..=255u8).cycle();
737 let type_id = h256!("0x1234567890abcdeffedcba0987654321");
738 let mut proofs_builder = SmtProofEntryVec::new_builder();
739 for _ in 0..2 {
740 let proof = SmtProof::new_builder()
741 .extend(i.by_ref().take(8).map(Byte::new))
742 .build();
743 let entry = SmtProofEntry::new_builder()
744 .mask(Byte::new(0))
745 .proof(proof)
746 .build();
747 proofs_builder = proofs_builder.push(entry);
748 }
749 let cfg = AdminConfig {
750 rc_type_id: type_id,
751 proofs: proofs_builder.build(),
752 ..Default::default()
753 };
754 let x = serde_json::to_string_pretty(&cfg).unwrap();
755 let cfg2: AdminConfig = serde_json::from_str(&x).unwrap();
756 assert_eq!(cfg, cfg2);
757 }
758}
759#[cfg(test)]
760mod anyhow_tests {
761 use anyhow::anyhow;
762 #[test]
763 fn test_config_error() {
764 let error = super::ConfigError::NoAdminConfig;
765 let error = anyhow!(error);
766 assert_eq!(
767 "there is no admin configuration in the OmniLockConfig",
768 error.to_string()
769 );
770 }
771}