canic/env/
sns.rs

1//! Preconfigured SNS deployments and helpers for looking up their canisters.
2
3use crate::{Error, env::EnvError};
4use candid::Principal;
5use thiserror::Error as ThisError;
6
7///
8/// SnsError
9///
10
11#[derive(Debug, ThisError)]
12pub enum SnsError {
13    #[error("invalid principal: {0} ({1})")]
14    InvalidPrincipal(String, String),
15}
16
17impl From<SnsError> for Error {
18    fn from(err: SnsError) -> Self {
19        EnvError::SnsError(err).into()
20    }
21}
22
23///
24/// SnsCanisters
25///
26
27#[derive(Clone, Debug)]
28pub struct SnsCanisters {
29    pub root: Principal,
30    pub governance: Principal,
31    pub index: Principal,
32    pub ledger: Principal,
33}
34
35///
36/// SnsRole
37///
38
39#[derive(Clone, Copy, Debug)]
40pub enum SnsRole {
41    Root,
42    Governance,
43    Index,
44    Ledger,
45}
46
47///
48/// SnsType
49///
50
51#[derive(Clone, Copy, Debug)]
52#[remain::sorted]
53pub enum SnsType {
54    Alice,
55    Catalyze,
56    CecilTheLion,
57    DecideAi,
58    Dragginz,
59    GoldDao,
60    Kinic,
61    KongSwap,
62    Mimic,
63    Motoko,
64    Neutrinite,
65    Nuance,
66    OpenChat,
67    Origyn,
68    PokedBots,
69    Sneed,
70    Swampies,
71    TacoDao,
72    Trax,
73}
74
75// ---- Helpers ----
76
77fn parse_required(name: &str, text: &str) -> Result<Principal, SnsError> {
78    Principal::from_text(text)
79        .map_err(|_| SnsError::InvalidPrincipal(name.to_string(), text.to_string()))
80}
81
82fn bundle(root: &str, gov: &str, idx: &str, led: &str) -> Result<SnsCanisters, SnsError> {
83    Ok(SnsCanisters {
84        root: parse_required("root", root)?,
85        governance: parse_required("governance", gov)?,
86        index: parse_required("index", idx)?,
87        ledger: parse_required("ledger", led)?,
88    })
89}
90
91// ---- Table + impl (DRY via macro) ----
92
93macro_rules! define_sns_table {
94    (
95        $(
96            $name:ident {
97                root: $root:expr,
98                governance: $gov:expr,
99                index: $idx:expr,
100                ledger: $led:expr $(,)?
101            }
102        ),+ $(,)?
103    ) => {
104        impl SnsType {
105            pub fn principal(self, role: SnsRole) -> Result<Principal, Error> {
106                let set = self.principals()?;
107                Ok(match role {
108                    SnsRole::Root       => set.root,
109                    SnsRole::Governance => set.governance,
110                    SnsRole::Index      => set.index,
111                    SnsRole::Ledger     => set.ledger,
112                })
113            }
114
115            pub fn principals(self) -> Result<SnsCanisters, Error> {
116                match self {
117                    $(
118                        Self::$name => bundle($root, $gov, $idx, $led),
119                    )+
120                }
121                .map_err(EnvError::from)
122                .map_err(Error::from)
123            }
124        }
125
126        // Optional: test all non-empty entries parse (runs in `cargo test`)
127        #[cfg(test)]
128        mod __sns_parse_tests {
129            use super::*;
130            #[test]
131            fn all_configured_ids_parse() {
132                $(
133                    // If any of these are non-empty, principals() must succeed
134                    if !($root.is_empty() || $gov.is_empty() || $idx.is_empty() || $led.is_empty()) {
135                        let _ = SnsType::$name.principals().expect(concat!("failed for ", stringify!($name)));
136                    }
137                )+
138            }
139        }
140    }
141}
142
143// ---- Fill the table once (short & readable) ----
144
145define_sns_table! {
146
147    Alice {
148        root:       "oh4fn-kyaaa-aaaaq-aaega-cai",
149        governance: "oa5dz-haaaa-aaaaq-aaegq-cai",
150        index:      "mtcaz-pyaaa-aaaaq-aaeia-cai",
151        ledger:     "oj6if-riaaa-aaaaq-aaeha-cai",
152    },
153
154    Catalyze {
155        root:       "uly3p-iqaaa-aaaaq-aabma-cai",
156        governance: "umz53-fiaaa-aaaaq-aabmq-cai",
157        index:      "ux4b6-7qaaa-aaaaq-aaboa-cai",
158        ledger:     "uf2wh-taaaa-aaaaq-aabna-cai",
159    },
160
161    CecilTheLion {
162        root:       "ju4gz-6iaaa-aaaaq-aaeva-cai",
163        governance: "jt5an-tqaaa-aaaaq-aaevq-cai",
164        index:      "jiy4i-jiaaa-aaaaq-aaexa-cai",
165        ledger:     "jg2ra-syaaa-aaaaq-aaewa-cai",
166    },
167
168    DecideAi {
169        root:       "x4kx5-ziaaa-aaaaq-aabeq-cai",
170        governance: "xvj4b-paaaa-aaaaq-aabfa-cai",
171        index:      "xaonm-oiaaa-aaaaq-aabgq-cai",
172        ledger:     "xsi2v-cyaaa-aaaaq-aabfq-cai",
173    },
174
175    Dragginz {
176        root:       "zxeu2-7aaaa-aaaaq-aaafa-cai",
177        governance: "zqfso-syaaa-aaaaq-aaafq-cai",
178        index:      "zlaol-iaaaa-aaaaq-aaaha-cai",
179        ledger:     "zfcdd-tqaaa-aaaaq-aaaga-cai",
180    },
181
182    GoldDao {
183        root:       "tw2vt-hqaaa-aaaaq-aab6a-cai",
184        governance: "tr3th-kiaaa-aaaaq-aab6q-cai",
185        index:      "efv5g-kqaaa-aaaaq-aacaa-cai",
186        ledger:     "tyyy3-4aaaa-aaaaq-aab7a-cai",
187    },
188
189    Kinic {
190        root:       "7jkta-eyaaa-aaaaq-aaarq-cai",
191        governance: "74ncn-fqaaa-aaaaq-aaasa-cai",
192        index:      "7vojr-tyaaa-aaaaq-aaatq-cai",
193        ledger:     "73mez-iiaaa-aaaaq-aaasq-cai",
194    },
195
196    KongSwap {
197        root:       "ormnc-tiaaa-aaaaq-aadyq-cai",
198        governance: "oypg6-faaaa-aaaaq-aadza-cai",
199        index:      "onixt-eiaaa-aaaaq-aad2q-cai",
200        ledger:     "o7oak-iyaaa-aaaaq-aadzq-cai",
201    },
202
203    Mimic {
204        root:       "4m6il-zqaaa-aaaaq-aaa2a-cai",
205        governance: "4l7o7-uiaaa-aaaaq-aaa2q-cai",
206        index:      "ks7eq-3yaaa-aaaaq-aaddq-cai",
207        ledger:     "4c4fd-caaaa-aaaaq-aaa3a-cai",
208    },
209
210    Motoko {
211        root:       "ko36b-myaaa-aaaaq-aadbq-cai",
212        governance: "k34pm-nqaaa-aaaaq-aadca-cai",
213        index:      "5ithz-aqaaa-aaaaq-aaa4a-cai",
214        ledger:     "k45jy-aiaaa-aaaaq-aadcq-cai",
215    },
216
217    Neutrinite {
218        root:       "extk7-gaaaa-aaaaq-aacda-cai",
219        governance: "eqsml-lyaaa-aaaaq-aacdq-cai",
220        index:      "ft6fn-7aaaa-aaaaq-aacfa-cai",
221        ledger:     "f54if-eqaaa-aaaaq-aacea-cai",
222    },
223
224    Nuance {
225        root:       "rzbmc-yiaaa-aaaaq-aabsq-cai",
226        governance: "rqch6-oaaaa-aaaaq-aabta-cai",
227        index:      "q5mdq-biaaa-aaaaq-aabuq-cai",
228        ledger:     "rxdbk-dyaaa-aaaaq-aabtq-cai",
229    },
230
231    OpenChat {
232        root:       "3e3x2-xyaaa-aaaaq-aaalq-cai",
233        governance: "2jvtu-yqaaa-aaaaq-aaama-cai",
234        index:      "2awyi-oyaaa-aaaaq-aaanq-cai",
235        ledger:     "2ouva-viaaa-aaaaq-aaamq-cai",
236    },
237
238    Origyn      {
239        root:       "leu43-oiaaa-aaaaq-aadgq-cai",
240        governance: "lnxxh-yaaaa-aaaaq-aadha-cai",
241        index:      "jqkzp-liaaa-aaaaq-aadiq-cai",
242        ledger:     "lkwrt-vyaaa-aaaaq-aadhq-cai",
243    },
244
245    PokedBots {
246        root:       "nb7he-piaaa-aaaaq-aadqq-cai",
247        governance: "ni4my-zaaaa-aaaaq-aadra-cai",
248        index:      "n535v-yiaaa-aaaaq-aadsq-cai",
249        ledger:     "np5km-uyaaa-aaaaq-aadrq-cai",
250    },
251
252    Sneed {
253        root:       "fp274-iaaaa-aaaaq-aacha-cai",
254        governance: "fi3zi-fyaaa-aaaaq-aachq-cai",
255        index:      "h3e2i-naaaa-aaaaq-aacja-cai",
256        ledger:     "hvgxa-wqaaa-aaaaq-aacia-cai",
257    },
258
259    Swampies {
260        root:       "l7ra6-uqaaa-aaaaq-aadea-cai",
261        governance: "lyqgk-ziaaa-aaaaq-aadeq-cai",
262        index:      "ldv2p-dqaaa-aaaaq-aadga-cai",
263        ledger:     "lrtnw-paaaa-aaaaq-aadfa-cai",
264    },
265
266    TacoDao {
267        root:       "lacdn-3iaaa-aaaaq-aae3a-cai",
268        governance: "lhdfz-wqaaa-aaaaq-aae3q-cai",
269        index:      "kepm7-ciaaa-aaaaq-aae5a-cai",
270        ledger:     "kknbx-zyaaa-aaaaq-aae4a-cai",
271    },
272
273    Trax {
274        root:       "ecu3s-hiaaa-aaaaq-aacaq-cai",
275        governance: "elxqo-raaaa-aaaaq-aacba-cai",
276        index:      "e6qbd-qiaaa-aaaaq-aaccq-cai",
277        ledger:     "emww2-4yaaa-aaaaq-aacbq-cai",
278    },
279}