1
- use candid:: { Nat , Principal } ;
1
+ use candid:: { utils :: ArgumentEncoder , CandidType , Nat , Principal } ;
2
2
use ic_cdk:: api:: management_canister:: main:: {
3
3
CanisterSettings , CanisterStatusResponse , UpdateSettingsArgument ,
4
4
} ;
5
5
use ic_oss_types:: {
6
6
cluster:: { AddWasmInput , BucketDeploymentInfo , ClusterInfo , DeployWasmInput , WasmInfo } ,
7
7
cose:: Token ,
8
8
} ;
9
+ use serde:: { Deserialize , Serialize } ;
9
10
use serde_bytes:: { ByteArray , ByteBuf } ;
10
11
use std:: collections:: { BTreeMap , BTreeSet } ;
11
12
@@ -20,6 +21,8 @@ mod store;
20
21
use crate :: init:: ChainArgs ;
21
22
22
23
static ANONYMOUS : Principal = Principal :: anonymous ( ) ;
24
+ // NNS Cycles Minting Canister: "rkp4c-7iaaa-aaaaa-aaaca-cai"
25
+ static CMC_PRINCIPAL : Principal = Principal :: from_slice ( & [ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 4 , 1 , 1 ] ) ;
23
26
static TOKEN_KEY_DERIVATION_PATH : & [ u8 ] = b"ic_oss_cluster" ;
24
27
const SECONDS : u64 = 1_000_000_000 ;
25
28
const MILLISECONDS : u64 = 1_000_000 ;
@@ -68,6 +71,70 @@ pub fn validate_principals(principals: &BTreeSet<Principal>) -> Result<(), Strin
68
71
Ok ( ( ) )
69
72
}
70
73
74
+ async fn call < In , Out > ( id : Principal , method : & str , args : In , cycles : u128 ) -> Result < Out , String >
75
+ where
76
+ In : ArgumentEncoder + Send ,
77
+ Out : candid:: CandidType + for < ' a > candid:: Deserialize < ' a > ,
78
+ {
79
+ let ( res, ) : ( Out , ) = ic_cdk:: api:: call:: call_with_payment128 ( id, method, args, cycles)
80
+ . await
81
+ . map_err ( |( code, msg) | {
82
+ format ! (
83
+ "failed to call {} on {:?}, code: {}, message: {}" ,
84
+ method, & id, code as u32 , msg
85
+ )
86
+ } ) ?;
87
+ Ok ( res)
88
+ }
89
+
90
+ #[ derive( Clone , Eq , PartialEq , Debug , CandidType , Deserialize ) ]
91
+ pub struct SubnetId {
92
+ pub principal_id : String ,
93
+ }
94
+
95
+ #[ derive( Clone , Eq , PartialEq , Debug , CandidType , Deserialize ) ]
96
+ pub enum SubnetSelection {
97
+ /// Choose a specific subnet
98
+ Subnet { subnet : SubnetId } ,
99
+ // Skip the SubnetFilter on the CMC SubnetSelection for simplification.
100
+ // https://github.com/dfinity/ic/blob/master/rs/nns/cmc/cmc.did#L35
101
+ }
102
+
103
+ #[ derive( Clone , Eq , PartialEq , Debug , CandidType , Deserialize ) ]
104
+ struct CreateCanisterInput {
105
+ pub settings : Option < CanisterSettings > ,
106
+ pub subnet_selection : Option < SubnetSelection > ,
107
+ pub subnet_type : Option < String > ,
108
+ }
109
+
110
+ /// Error for create_canister.
111
+ #[ derive( Clone , Eq , PartialEq , Debug , CandidType , Deserialize , Serialize ) ]
112
+ pub enum CreateCanisterOutput {
113
+ Refunded {
114
+ refund_amount : u128 ,
115
+ create_error : String ,
116
+ } ,
117
+ }
118
+
119
+ async fn create_canister_on (
120
+ subnet : Principal ,
121
+ settings : Option < CanisterSettings > ,
122
+ cycles : u128 ,
123
+ ) -> Result < Principal , String > {
124
+ let arg = CreateCanisterInput {
125
+ settings,
126
+ subnet_type : None ,
127
+ subnet_selection : Some ( SubnetSelection :: Subnet {
128
+ subnet : SubnetId {
129
+ principal_id : subnet. to_text ( ) ,
130
+ } ,
131
+ } ) ,
132
+ } ;
133
+ let res: Result < Principal , CreateCanisterOutput > =
134
+ call ( CMC_PRINCIPAL , "create_canister" , ( arg, ) , cycles) . await ?;
135
+ res. map_err ( |err| format ! ( "failed to create canister, error: {:?}" , err) )
136
+ }
137
+
71
138
#[ cfg( all(
72
139
target_arch = "wasm32" ,
73
140
target_vendor = "unknown" ,
0 commit comments