iop_coeus_proto/
operations.rs

1use super::*;
2
3#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
4#[serde(rename_all = "camelCase")]
5pub struct DoDelete {
6    #[serde(with = "serde_str")]
7    pub name: DomainName,
8}
9
10#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
11#[serde(rename_all = "camelCase")]
12pub struct DoRegister {
13    #[serde(with = "serde_str")]
14    pub name: DomainName,
15    pub owner: Principal,
16    pub subtree_policies: SubtreePolicies,
17    pub registration_policy: RegistrationPolicy,
18    pub data: DynamicContent,
19    pub expires_at_height: BlockHeight,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
23#[serde(rename_all = "camelCase")]
24pub struct DoRenew {
25    #[serde(with = "serde_str")]
26    pub name: DomainName,
27    pub expires_at_height: BlockHeight,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
31#[serde(rename_all = "camelCase")]
32pub struct DoTransfer {
33    #[serde(with = "serde_str")]
34    pub name: DomainName,
35    pub to_owner: Principal,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
39#[serde(rename_all = "camelCase")]
40pub struct DoUpdate {
41    #[serde(with = "serde_str")]
42    pub name: DomainName,
43    pub data: DynamicContent,
44}
45
46pub trait Priced {
47    fn get_price(&self) -> Price;
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
51#[serde(tag = "type", rename_all = "camelCase")]
52pub enum UserOperation {
53    Register(Box<DoRegister>),
54    Update(DoUpdate),
55    Renew(DoRenew),
56    Transfer(DoTransfer),
57    Delete(DoDelete),
58}
59
60impl UserOperation {
61    pub fn register(
62        name: DomainName, owner: Principal, subtree_policies: SubtreePolicies,
63        registration_policy: RegistrationPolicy, data: DynamicContent,
64        expires_at_height: BlockHeight,
65    ) -> Self {
66        Self::Register(Box::new(DoRegister {
67            name,
68            owner,
69            subtree_policies,
70            registration_policy,
71            data,
72            expires_at_height,
73        }))
74    }
75
76    pub fn update(name: DomainName, data: DynamicContent) -> Self {
77        Self::Update(DoUpdate { name, data })
78    }
79
80    pub fn renew(name: DomainName, expires_at_height: BlockHeight) -> Self {
81        Self::Renew(DoRenew { name, expires_at_height })
82    }
83
84    pub fn transfer(name: DomainName, to_owner: Principal) -> Self {
85        Self::Transfer(DoTransfer { name, to_owner })
86    }
87
88    pub fn delete(name: DomainName) -> Self {
89        Self::Delete(DoDelete { name })
90    }
91}
92
93impl Priced for UserOperation {
94    fn get_price(&self) -> Price {
95        // Register is sooo much bigger in its serialized form that we try to compensate other operations
96        // with a small offset in addition to the size-based fee of the whole transaction
97        match self {
98            Self::Register(_op) => Price::fee(0),
99            Self::Update(_op) => Price::fee(200_000),
100            Self::Renew(_op) => Price::fee(200_000),
101            Self::Transfer(_op) => Price::fee(200_000),
102            Self::Delete(_op) => Price::fee(200_000),
103        }
104    }
105}
106
107#[cfg(test)]
108mod test {
109    use super::*;
110
111    #[test]
112    fn serde() {
113        let input = r#"{"type":"register","name":".schema.company","owner":"pszp9HBQY4qrx2yPGqM6biZeLmudJanMK6LXzXzLZGciLYA","subtreePolicies":{},"registrationPolicy":"owner","data":{},"expiresAtHeight":1000}"#;
114        let op: UserOperation = serde_json::from_str(input).unwrap();
115
116        assert!(matches!(op, UserOperation::Register(_)));
117        if let UserOperation::Register(r) = &op {
118            assert_eq!(r.name.to_string(), ".schema.company");
119        }
120
121        let output = serde_json::to_string(&op).unwrap();
122
123        assert_eq!(output, input);
124    }
125}