diff --git a/src/canister/individual_user_template/can.did b/src/canister/individual_user_template/can.did index 48ddfc75..d46ad618 100644 --- a/src/canister/individual_user_template/can.did +++ b/src/canister/individual_user_template/can.did @@ -39,6 +39,7 @@ type BettingStatus = variant { }; type Canister = record { id : opt principal }; type CdaoDeployError = variant { + CycleError : text; Unregistered; CallError : record { RejectionCode; text }; InvalidInitPayload : text; diff --git a/src/canister/individual_user_template/src/api/cdao/mod.rs b/src/canister/individual_user_template/src/api/cdao/mod.rs index 4b27f049..9f93577c 100644 --- a/src/canister/individual_user_template/src/api/cdao/mod.rs +++ b/src/canister/individual_user_template/src/api/cdao/mod.rs @@ -12,23 +12,26 @@ use ic_cdk::{ api::management_canister::main::{ create_canister, install_code, update_settings, CanisterInstallMode, CanisterSettings, CreateCanisterArgument, InstallCodeArgument, UpdateSettingsArgument, - }, query, update + }, + query, update, }; use ic_sns_init::{pb::v1::SnsInitPayload, SnsCanisterIds}; -use ic_sns_wasm::pb::v1::{GetWasmResponse, GetWasmRequest}; +use ic_sns_wasm::pb::v1::{GetWasmRequest, GetWasmResponse}; // use ic_sns_swap::pb::v1::{SettleNeuronsFundParticipationRequest, SettleNeuronsFundParticipationResponse}; use ic_nns_governance::neurons_fund::NeuronsFundSnapshot; -use ic_nns_governance::pb::v1::{SettleNeuronsFundParticipationRequest, SettleNeuronsFundParticipationResponse}; +use ic_nns_governance::pb::v1::{ + SettleNeuronsFundParticipationRequest, SettleNeuronsFundParticipationResponse, +}; use shared_utils::{ - canister_specific::individual_user_template::{consts::CDAO_TOKEN_LIMIT, types::{ - cdao::DeployedCdaoCanisters, error::CdaoDeployError, session::SessionType, - }}, + canister_specific::individual_user_template::{ + consts::CDAO_TOKEN_LIMIT, + types::{cdao::DeployedCdaoCanisters, error::CdaoDeployError, session::SessionType}, + }, common::types::known_principal::KnownPrincipalType, + constant::{NNS_LEDGER_CANISTER_ID, USER_SNS_CANISTER_INITIAL_CYCLES}, }; -use crate::CANISTER_DATA; -// 5 * 0.1T -const CDAO_CYCLE_CNT: u128 = 5 * 100000000000; +use crate::{util::cycles::request_cycles_from_subnet_orchestrator, CANISTER_DATA}; #[update] pub async fn settle_neurons_fund_participation( @@ -42,7 +45,7 @@ pub async fn settle_neurons_fund_participation( async fn create_empty_canister( arg: CreateCanisterArgument, ) -> Result { - let can = create_canister(arg, CDAO_CYCLE_CNT).await?; + let can = create_canister(arg, USER_SNS_CANISTER_INITIAL_CYCLES).await?; Ok(PrincipalId(can.0.canister_id)) } @@ -78,19 +81,14 @@ async fn update_controllers( #[query] async fn deployed_cdao_canisters() -> Vec { - CANISTER_DATA.with(|cdata| { - cdata - .borrow() - .cdao_canisters - .clone() - }) + CANISTER_DATA.with(|cdata| cdata.borrow().cdao_canisters.clone()) } #[update] async fn deploy_cdao_sns( init_payload: SnsInitPayload, swap_time: u64, -) -> Result { +) -> Result { // * access control let current_caller = ic_cdk::caller(); let my_principal_id = CANISTER_DATA @@ -104,13 +102,16 @@ async fn deploy_cdao_sns( let registered = matches!(cdata.session_type, Some(SessionType::RegisteredSession)); (registered, cdata.cdao_canisters.len() == CDAO_TOKEN_LIMIT) }); - /*if !registered { - return Err(CdaoDeployError::Unregistered); - }*/ + if limit_hit { return Err(CdaoDeployError::TokenLimit(CDAO_TOKEN_LIMIT)); } + // Alloting 0.5T more to the user canister to be on safer side while deploying canisters + request_cycles_from_subnet_orchestrator(6 * USER_SNS_CANISTER_INITIAL_CYCLES) + .await + .map_err(|e| CdaoDeployError::CycleError(e))?; + let creation_arg = CreateCanisterArgument { settings: Some(CanisterSettings { controllers: Some(vec![ic_cdk::id()]), @@ -142,9 +143,9 @@ async fn deploy_cdao_sns( let time_seconds = ic_cdk::api::time() / 1_000_000_000; payloads.swap.swap_start_timestamp_seconds = Some(time_seconds); payloads.swap.swap_due_timestamp_seconds = Some(time_seconds + swap_time); - payloads.swap.icp_ledger_canister_id = "ryjl3-tyaaa-aaaaa-aaaba-cai".to_string(); + payloads.swap.icp_ledger_canister_id = NNS_LEDGER_CANISTER_ID.into(); payloads.swap.nns_governance_canister_id = ic_cdk::id().to_string(); - + let sns_wasm = CANISTER_DATA .with(|cdata| { cdata @@ -154,21 +155,24 @@ async fn deploy_cdao_sns( .copied() }) .expect("SNS WASM not specified in config"); - - let gov_hash = hex::decode("3feb8ff7b47f53da83235e4c68676bb6db54df1e62df3681de9425ad5cf43be5").unwrap(); - let ledger_hash = hex::decode("e8942f56f9439b89b13bd8037f357126e24f1e7932cf03018243347505959fd4").unwrap();; - let root_hash = hex::decode("495e31370b14fa61c76bd1483c9f9ba66733793ee2963e8e44a231436a60bcc6").unwrap();; - let swap_hash = hex::decode("3bb490d197b8cf2e7d9948bcb5d1fc46747a835294b3ffe47b882dbfa584555f").unwrap();; - let index_hash = hex::decode("08ae5042c8e413716d04a08db886b8c6b01bb610b8197cdbe052c59538b924f0").unwrap();; + + let gov_hash = + hex::decode("3feb8ff7b47f53da83235e4c68676bb6db54df1e62df3681de9425ad5cf43be5").unwrap(); + let ledger_hash = + hex::decode("e8942f56f9439b89b13bd8037f357126e24f1e7932cf03018243347505959fd4").unwrap(); + let root_hash = + hex::decode("495e31370b14fa61c76bd1483c9f9ba66733793ee2963e8e44a231436a60bcc6").unwrap(); + let swap_hash = + hex::decode("3bb490d197b8cf2e7d9948bcb5d1fc46747a835294b3ffe47b882dbfa584555f").unwrap(); + let index_hash = + hex::decode("08ae5042c8e413716d04a08db886b8c6b01bb610b8197cdbe052c59538b924f0").unwrap(); ic_cdk::println!("gov_hash: {:?}", gov_hash); let mut wasm_bins: VecDeque<_> = [gov_hash, ledger_hash, root_hash, swap_hash, index_hash] .into_iter() .map(|hash| async move { - let req = GetWasmRequest { - hash, - }; + let req = GetWasmRequest { hash }; let wasm_res = ic_cdk::call::<_, (GetWasmResponse,)>(sns_wasm, "get_wasm", (req,)).await?; Ok::<_, CdaoDeployError>(wasm_res.0.wasm.unwrap().wasm) diff --git a/src/canister/individual_user_template/src/util/cycles.rs b/src/canister/individual_user_template/src/util/cycles.rs new file mode 100644 index 00000000..f1088c4b --- /dev/null +++ b/src/canister/individual_user_template/src/util/cycles.rs @@ -0,0 +1,26 @@ +use ic_cdk::call; +use shared_utils::common::types::known_principal::KnownPrincipalType; + +use crate::CANISTER_DATA; + +pub async fn request_cycles_from_subnet_orchestrator(amount: u128) -> Result<(), String> { + let subnet_orchestrator_canister_id = CANISTER_DATA + .with_borrow(|canister_data| { + canister_data + .known_principal_ids + .get(&KnownPrincipalType::CanisterIdUserIndex) + .copied() + }) + .ok_or("Subnet Orchestrator Canister Id not found".to_owned())?; + + let result = call::<_, (Result<(), String>,)>( + subnet_orchestrator_canister_id, + "request_cycles", + (amount,), + ) + .await + .map_err(|e| e.1)? + .0; + + result +} diff --git a/src/canister/individual_user_template/src/util/mod.rs b/src/canister/individual_user_template/src/util/mod.rs index 7536d159..cb94a7fc 100644 --- a/src/canister/individual_user_template/src/util/mod.rs +++ b/src/canister/individual_user_template/src/util/mod.rs @@ -1,3 +1,4 @@ +pub mod cycles; pub mod migration; pub mod periodic_update; pub mod score_ranking; diff --git a/src/canister/user_index/src/api/canister_management/request_cycles.rs b/src/canister/user_index/src/api/canister_management/request_cycles.rs index 998bd019..45c4a7ca 100644 --- a/src/canister/user_index/src/api/canister_management/request_cycles.rs +++ b/src/canister/user_index/src/api/canister_management/request_cycles.rs @@ -4,7 +4,9 @@ use ic_cdk::{ }; use ic_cdk_macros::update; -use crate::CANISTER_DATA; +use crate::{ + util::canister_management::check_and_request_cycles_from_platform_orchestrator, CANISTER_DATA, +}; #[update] async fn request_cycles(cycle_amount: u128) -> Result<(), String> { @@ -25,6 +27,8 @@ async fn request_cycles(cycle_amount: u128) -> Result<(), String> { let recharge_amount = u128::max(cycle_amount, 5_000_000_000_000); + check_and_request_cycles_from_platform_orchestrator().await?; + deposit_cycles(CanisterIdRecord { canister_id }, recharge_amount) .await .map_err(|e| e.1) diff --git a/src/lib/integration_tests/tests/creator_dao/main.rs b/src/lib/integration_tests/tests/creator_dao/main.rs index 9d8ef0a8..05f7e4ff 100644 --- a/src/lib/integration_tests/tests/creator_dao/main.rs +++ b/src/lib/integration_tests/tests/creator_dao/main.rs @@ -1,50 +1,42 @@ pub mod types; -use core::{hash, time}; -use std::{ - collections::{HashMap, HashSet}, fmt::Debug, fs, str::FromStr, time::SystemTime, vec +use ic_sns_governance::pb::v1::{ + manage_neuron, neuron, Account, ListNeurons, ListNeuronsResponse, ManageNeuron, + ManageNeuronResponse, }; -use ic_sns_init::pb::v1::{SnsInitPayload, FractionalDeveloperVotingPower, sns_init_payload::InitialTokenDistribution, DeveloperDistribution, SwapDistribution, NeuronDistribution, TreasuryDistribution, AirdropDistribution}; -use ic_sns_swap::{pb::v1::{GetInitRequest, GetInitResponse, NeuronBasketConstructionParameters, NewSaleTicketRequest, NewSaleTicketResponse, RefreshBuyerTokensRequest, RefreshBuyerTokensResponse}, swap}; -use sha2::{Sha256, Digest}; -use ic_sns_governance::pb::v1::{ListNeurons, ListNeuronsResponse, neuron, ManageNeuron, ManageNeuronResponse, manage_neuron, Account}; -use flate2::read::GzDecoder; -use std::io::Read; +use ic_sns_init::pb::v1::{ + sns_init_payload::InitialTokenDistribution, AirdropDistribution, DeveloperDistribution, + FractionalDeveloperVotingPower, NeuronDistribution, SnsInitPayload, SwapDistribution, + TreasuryDistribution, +}; +use ic_sns_swap::pb::v1::{ + GetInitRequest, GetInitResponse, NeuronBasketConstructionParameters, NewSaleTicketRequest, + NewSaleTicketResponse, RefreshBuyerTokensRequest, RefreshBuyerTokensResponse, +}; +use sha2::{Digest, Sha256}; use std::time::{Duration, UNIX_EPOCH}; +use std::{collections::HashMap, fmt::Debug, str::FromStr, time::SystemTime, vec}; - -use candid::{CandidType, Decode, Encode, Principal, Nat}; -use icp_ledger::{AccountIdentifier, Memo, Subaccount, TimeStamp, Tokens as ledgerTokens, TransferArgs}; -use ic_cdk::api::{management_canister::provisional::CanisterSettings, time}; -use ic_ledger_types::{BlockIndex, Tokens, DEFAULT_SUBACCOUNT}; -use pocket_ic::{PocketIc, PocketIcBuilder, WasmResult}; +use candid::{CandidType, Decode, Encode, Nat, Principal}; +use ic_base_types::PrincipalId; +use ic_sns_wasm::init::SnsWasmCanisterInitPayload; +use icp_ledger::Subaccount; +use pocket_ic::WasmResult; use serde::{Deserialize, Serialize}; use shared_utils::{ - canister_specific::{ - individual_user_template::{self, types::cdao::DeployedCdaoCanisters, types::error::CdaoDeployError}, - platform_orchestrator::{ - self, - types::args::{PlatformOrchestratorInitArgs, UpgradeCanisterArg}, - }, - post_cache::types::arg::PostCacheInitArgs, - }, - common::{ - types::{ - known_principal::{self, KnownPrincipalMap, KnownPrincipalType}, - wasm::WasmType, - }, - utils::system_time, + canister_specific::individual_user_template::{ + types::cdao::DeployedCdaoCanisters, types::error::CdaoDeployError, }, - constant::{NNS_CYCLE_MINTING_CANISTER, NNS_LEDGER_CANISTER_ID, SNS_WASM_W_PRINCIPAL_ID, YRAL_POST_CACHE_CANISTER_ID}, + common::types::known_principal::KnownPrincipalType, + constant::SNS_WASM_W_PRINCIPAL_ID, }; use test_utils::setup::{ env::pocket_ic_env::get_new_pocket_ic_env, test_constants::{ - get_global_super_admin_principal_id, get_mock_user_alice_principal_id, get_mock_user_charlie_principal_id, get_mock_user_dan_canister_id, v1::CANISTER_INITIAL_CYCLES_FOR_SPAWNING_CANISTERS + get_global_super_admin_principal_id, get_mock_user_alice_principal_id, + get_mock_user_charlie_principal_id, }, }; -use ic_base_types::PrincipalId; -use ic_sns_wasm::init::SnsWasmCanisterInitPayload; pub const ICP_LEDGER_CANISTER_ID: &'static str = "ryjl3-tyaaa-aaaaa-aaaba-cai"; pub const ICP_INDEX_CANISTER_ID: &'static str = "qhbym-qaaaa-aaaaa-aaafq-cai"; @@ -53,7 +45,7 @@ pub const ICP_INDEX_CANISTER_ID: &'static str = "qhbym-qaaaa-aaaaa-aaafq-cai"; struct Wasm { wasm: Vec, proposal_id: Option, - canister_type: i32 + canister_type: i32, } impl Debug for Wasm { @@ -68,7 +60,7 @@ impl Debug for Wasm { #[derive(CandidType, Deserialize, PartialEq, Eq, Hash, Serialize, Clone, Debug)] struct AddWasmPayload { hash: Vec, - wasm: Option + wasm: Option, } #[derive(CandidType, Serialize, Deserialize, Debug, Clone)] @@ -97,11 +89,16 @@ fn add_wasm(wasm_file: &[u8], canister_type: u32) -> AddWasmPayload { wasm: Some(Wasm { wasm: wasm_file.to_vec(), proposal_id: None, - canister_type: canister_type as i32 - }) + canister_type: canister_type as i32, + }), }; - ic_cdk::println!("Wasm data: {:?}\nType: {}, Hash: {}", wasm_data, canister_type, hex::encode(file_hash)); + ic_cdk::println!( + "Wasm data: {:?}\nType: {}, Hash: {}", + wasm_data, + canister_type, + hex::encode(file_hash) + ); wasm_data } @@ -128,13 +125,17 @@ fn creator_dao_tests() { candid::encode_one(charlie_global_admin).unwrap(), ) .unwrap(); - + pocket_ic .update_call( platform_canister_id, super_admin, "update_global_known_principal", - candid::encode_args((KnownPrincipalType::CanisterIdSnsWasm, Principal::from_text(SNS_WASM_W_PRINCIPAL_ID).unwrap())).unwrap(), + candid::encode_args(( + KnownPrincipalType::CanisterIdSnsWasm, + Principal::from_text(SNS_WASM_W_PRINCIPAL_ID).unwrap(), + )) + .unwrap(), ) .unwrap(); @@ -159,7 +160,7 @@ fn creator_dao_tests() { } let alice_principal = get_mock_user_alice_principal_id(); - let alice_cannister_id: Principal = pocket_ic.update_call( + let alice_canister_id: Principal = pocket_ic.update_call( subnet_orchestrator_canister_id, alice_principal, "get_requester_principals_canister_id_create_if_not_exists_and_optionally_allow_referrer", @@ -173,10 +174,7 @@ fn creator_dao_tests() { }) .unwrap(); - pocket_ic.add_cycles(alice_cannister_id, 1_000_000_000_000_000); - - let offchain_account = get_mock_user_dan_canister_id(); - let icp_ledger_canister_id = Principal::from_text(ICP_LEDGER_CANISTER_ID).unwrap(); + let alice_initial_cycle_balance = pocket_ic.cycle_balance(alice_canister_id); let sns_wasm_w_canister_wasm = include_bytes!("../../../../../wasms/sns-wasm-canister.wasm"); let sns_wasm_w_canister_id = Principal::from_text(SNS_WASM_W_PRINCIPAL_ID).unwrap(); @@ -200,88 +198,130 @@ fn creator_dao_tests() { Some(super_admin), ); - let res = pocket_ic.update_call( - sns_wasm_w_canister_id, - super_admin, - "add_wasm", - candid::encode_one(add_wasm(include_bytes!("../../../../../wasms/root.wasm.gz"), 1)).unwrap() - ).map(|res| { - let response: AddWasmResultRecord = match res { - WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + sns_wasm_w_canister_id, + super_admin, + "add_wasm", + candid::encode_one(add_wasm( + include_bytes!("../../../../../wasms/root.wasm.gz"), + 1, + )) + .unwrap(), + ) + .map(|res| { + let response: AddWasmResultRecord = match res { + WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); - - let res = pocket_ic.update_call( - sns_wasm_w_canister_id, - super_admin, - "add_wasm", - candid::encode_one(add_wasm(include_bytes!("../../../../../wasms/governance.wasm.gz"), 2)).unwrap() - ).map(|res| { - let response: AddWasmResultRecord = match res { - WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + + let res = pocket_ic + .update_call( + sns_wasm_w_canister_id, + super_admin, + "add_wasm", + candid::encode_one(add_wasm( + include_bytes!("../../../../../wasms/governance.wasm.gz"), + 2, + )) + .unwrap(), + ) + .map(|res| { + let response: AddWasmResultRecord = match res { + WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); - let res = pocket_ic.update_call( - sns_wasm_w_canister_id, - super_admin, - "add_wasm", - candid::encode_one(add_wasm(include_bytes!("../../../../../wasms/ledger.wasm.gz"), 3)).unwrap() - ).map(|res| { - let response: AddWasmResultRecord = match res { - WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + sns_wasm_w_canister_id, + super_admin, + "add_wasm", + candid::encode_one(add_wasm( + include_bytes!("../../../../../wasms/ledger.wasm.gz"), + 3, + )) + .unwrap(), + ) + .map(|res| { + let response: AddWasmResultRecord = match res { + WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); - let res = pocket_ic.update_call( - sns_wasm_w_canister_id, - super_admin, - "add_wasm", - candid::encode_one(add_wasm(include_bytes!("../../../../../wasms/swap.wasm.gz"), 4)).unwrap() - ).map(|res| { - let response: AddWasmResultRecord = match res { - WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + sns_wasm_w_canister_id, + super_admin, + "add_wasm", + candid::encode_one(add_wasm( + include_bytes!("../../../../../wasms/swap.wasm.gz"), + 4, + )) + .unwrap(), + ) + .map(|res| { + let response: AddWasmResultRecord = match res { + WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); - let res = pocket_ic.update_call( - sns_wasm_w_canister_id, - super_admin, - "add_wasm", - candid::encode_one(add_wasm(include_bytes!("../../../../../wasms/archive.wasm.gz"), 5)).unwrap() - ).map(|res| { - let response: AddWasmResultRecord = match res { - WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + sns_wasm_w_canister_id, + super_admin, + "add_wasm", + candid::encode_one(add_wasm( + include_bytes!("../../../../../wasms/archive.wasm.gz"), + 5, + )) + .unwrap(), + ) + .map(|res| { + let response: AddWasmResultRecord = match res { + WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); - let res = pocket_ic.update_call( - sns_wasm_w_canister_id, - super_admin, - "add_wasm", - candid::encode_one(add_wasm(include_bytes!("../../../../../wasms/index.wasm.gz"), 6)).unwrap() - ).map(|res| { - let response: AddWasmResultRecord = match res { - WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + sns_wasm_w_canister_id, + super_admin, + "add_wasm", + candid::encode_one(add_wasm( + include_bytes!("../../../../../wasms/index.wasm.gz"), + 6, + )) + .unwrap(), + ) + .map(|res| { + let response: AddWasmResultRecord = match res { + WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); for _ in 0..50 { @@ -309,7 +349,7 @@ fn creator_dao_tests() { let start = SystemTime::now(); let tx_fee = 1u64; - + let sns_init_args = SnsInitPayload { confirmation_text: Some("GET RICH QUICK".to_string()), transaction_fee_e8s: Some(tx_fee), @@ -345,92 +385,103 @@ fn creator_dao_tests() { swap_due_timestamp_seconds: Some(start.duration_since(UNIX_EPOCH).unwrap().as_secs() + 300), // year 3000 - hopefully we'll all be gone by then, neuron_basket_construction_parameters: Some(NeuronBasketConstructionParameters { count: 2, - dissolve_delay_interval_seconds: 2 + dissolve_delay_interval_seconds: 2, }), nns_proposal_id: Some(1), neurons_fund_participation: Some(false), neurons_fund_participants: None, token_logo: Some("data:image/png;base64,iVBORw0".to_string()), neurons_fund_participation_constraints: None, - initial_token_distribution: Some( - InitialTokenDistribution::FractionalDeveloperVotingPower( - FractionalDeveloperVotingPower { - airdrop_distribution: Some(AirdropDistribution { - airdrop_neurons: vec![] - }), - developer_distribution: Some(DeveloperDistribution{ - developer_neurons: vec![ - NeuronDistribution { - controller: Some(PrincipalId::from_str(&alice_principal.to_string()).unwrap()), - stake_e8s: 4_400_000, - memo: 0, - dissolve_delay_seconds: 0, - vesting_period_seconds: None - }, - NeuronDistribution { - controller: Some(PrincipalId::from_str(&alice_principal.to_string()).unwrap()), - stake_e8s: 100_000, - memo: 1, - dissolve_delay_seconds: 2, - vesting_period_seconds: None - } - ] - }), - treasury_distribution: Some(TreasuryDistribution { - total_e8s: 10_000_000 - }), - swap_distribution: Some(SwapDistribution { - total_e8s: 5_000_000, - initial_swap_amount_e8s: 5_000_000, - }), - } - ) - ), + initial_token_distribution: Some(InitialTokenDistribution::FractionalDeveloperVotingPower( + FractionalDeveloperVotingPower { + airdrop_distribution: Some(AirdropDistribution { + airdrop_neurons: vec![], + }), + developer_distribution: Some(DeveloperDistribution { + developer_neurons: vec![ + NeuronDistribution { + controller: Some( + PrincipalId::from_str(&alice_principal.to_string()).unwrap(), + ), + stake_e8s: 4_400_000, + memo: 0, + dissolve_delay_seconds: 0, + vesting_period_seconds: None, + }, + NeuronDistribution { + controller: Some( + PrincipalId::from_str(&alice_principal.to_string()).unwrap(), + ), + stake_e8s: 100_000, + memo: 1, + dissolve_delay_seconds: 2, + vesting_period_seconds: None, + }, + ], + }), + treasury_distribution: Some(TreasuryDistribution { + total_e8s: 10_000_000, + }), + swap_distribution: Some(SwapDistribution { + total_e8s: 5_000_000, + initial_swap_amount_e8s: 5_000_000, + }), + }, + )), }; - let res = pocket_ic.update_call( - alice_cannister_id, - alice_principal, - "deploy_cdao_sns", - candid::encode_args((sns_init_args, 300 as u64)).unwrap(), - ).map(|res| { - let response: Result = match res { - WasmResult::Reply(payload) => { - ic_cdk::println!("๐Ÿงช Call made"); - Decode!(&payload, Result).unwrap() - }, - _ => panic!("\n๐Ÿ›‘ deploy cdao failed with {:?}", res) - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + alice_canister_id, + alice_principal, + "deploy_cdao_sns", + candid::encode_args((sns_init_args, 300 as u64)).unwrap(), + ) + .map(|res| { + let response: Result = match res { + WasmResult::Reply(payload) => { + ic_cdk::println!("๐Ÿงช Call made"); + Decode!(&payload, Result).unwrap() + } + _ => panic!("\n๐Ÿ›‘ deploy cdao failed with {:?}", res), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); - let res = pocket_ic.query_call( - alice_cannister_id, - alice_principal, - "get_well_known_principal_value", - candid::encode_one((KnownPrincipalType::CanisterIdSnsWasm)).unwrap(), - ).map(|res| { - let response: Option = match res { - WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), - _ => panic!("\n๐Ÿ›‘ get_well_known_principal_value failed") - }; - response - }).unwrap(); + let res = pocket_ic + .query_call( + alice_canister_id, + alice_principal, + "get_well_known_principal_value", + candid::encode_one((KnownPrincipalType::CanisterIdSnsWasm)).unwrap(), + ) + .map(|res| { + let response: Option = match res { + WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), + _ => panic!("\n๐Ÿ›‘ get_well_known_principal_value failed"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res.unwrap().to_string()); - let res = pocket_ic.query_call( - alice_cannister_id, - alice_principal, - "deployed_cdao_canisters", - candid::encode_one(()).unwrap(), - ).map(|res| { - let response: Vec = match res { - WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .query_call( + alice_canister_id, + alice_principal, + "deployed_cdao_canisters", + candid::encode_one(()).unwrap(), + ) + .map(|res| { + let response: Vec = match res { + WasmResult::Reply(payload) => candid::decode_one(&payload).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); for can in &res { ic_cdk::println!("๐Ÿงช Gov Canister ID: {:?}", can.governance.to_string()); @@ -448,50 +499,64 @@ fn creator_dao_tests() { ic_cdk::println!("๐Ÿงช๐Ÿงช๐Ÿงช Swap Canister ID: {:?}", swap_canister.to_string()); - let res = pocket_ic.query_call( - Principal::from_text(ICP_LEDGER_CANISTER_ID).unwrap(), - super_admin, - "icrc1_total_supply", - candid::encode_one(()).unwrap(), - ).map(|res| { - let response = match res { - WasmResult::Reply(payload) => Decode!(&payload, Nat).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .query_call( + Principal::from_text(ICP_LEDGER_CANISTER_ID).unwrap(), + super_admin, + "icrc1_total_supply", + candid::encode_one(()).unwrap(), + ) + .map(|res| { + let response = match res { + WasmResult::Reply(payload) => Decode!(&payload, Nat).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); // check super admin icp balance - let res = pocket_ic.query_call( - Principal::from_text(ICP_LEDGER_CANISTER_ID).unwrap(), - super_admin, - "icrc1_balance_of", - candid::encode_one(types::Icrc1BalanceOfArg{owner: super_admin, subaccount: None}).unwrap(), - ).map(|res| { - let response = match res { - WasmResult::Reply(payload) => Decode!(&payload, Nat).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .query_call( + Principal::from_text(ICP_LEDGER_CANISTER_ID).unwrap(), + super_admin, + "icrc1_balance_of", + candid::encode_one(types::Icrc1BalanceOfArg { + owner: super_admin, + subaccount: None, + }) + .unwrap(), + ) + .map(|res| { + let response = match res { + WasmResult::Reply(payload) => Decode!(&payload, Nat).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); - let res = pocket_ic.update_call( - swap_canister, - super_admin, - "new_sale_ticket", - candid::encode_one(NewSaleTicketRequest { - amount_icp_e8s: 1000000, - subaccount: None, - }).unwrap() - ).map(|res| { - let response: NewSaleTicketResponse = match res { - WasmResult::Reply(payload) => Decode!(&payload, NewSaleTicketResponse).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + swap_canister, + super_admin, + "new_sale_ticket", + candid::encode_one(NewSaleTicketRequest { + amount_icp_e8s: 1000000, + subaccount: None, + }) + .unwrap(), + ) + .map(|res| { + let response: NewSaleTicketResponse = match res { + WasmResult::Reply(payload) => Decode!(&payload, NewSaleTicketResponse).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); let subaccount = Subaccount::from(&PrincipalId(super_admin)); @@ -506,35 +571,44 @@ fn creator_dao_tests() { }, created_at_time: None, }; - let res = pocket_ic.update_call( - Principal::from_text(ICP_LEDGER_CANISTER_ID).unwrap(), - super_admin, - "icrc1_transfer", - Encode!(&transfer_args).unwrap() - ).map(|res| { - let response: types::TransferResult = match res { - WasmResult::Reply(payload) => Decode!(&payload, types::TransferResult).unwrap(), - _ => panic!("\n๐Ÿ›‘ icrc1_transfer failed with: {:?}", res), - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + Principal::from_text(ICP_LEDGER_CANISTER_ID).unwrap(), + super_admin, + "icrc1_transfer", + Encode!(&transfer_args).unwrap(), + ) + .map(|res| { + let response: types::TransferResult = match res { + WasmResult::Reply(payload) => Decode!(&payload, types::TransferResult).unwrap(), + _ => panic!("\n๐Ÿ›‘ icrc1_transfer failed with: {:?}", res), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); - let res = pocket_ic.update_call( - swap_canister, - super_admin, - "refresh_buyer_tokens", - candid::encode_one(RefreshBuyerTokensRequest { - buyer: super_admin.to_string(), - confirmation_text: Some("GET RICH QUICK".to_string()), - }).unwrap() - ).map(|res| { - let response: RefreshBuyerTokensResponse = match res { - WasmResult::Reply(payload) => Decode!(&payload, RefreshBuyerTokensResponse).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + swap_canister, + super_admin, + "refresh_buyer_tokens", + candid::encode_one(RefreshBuyerTokensRequest { + buyer: super_admin.to_string(), + confirmation_text: Some("GET RICH QUICK".to_string()), + }) + .unwrap(), + ) + .map(|res| { + let response: RefreshBuyerTokensResponse = match res { + WasmResult::Reply(payload) => { + Decode!(&payload, RefreshBuyerTokensResponse).unwrap() + } + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); pocket_ic.advance_time(Duration::from_secs(301)); @@ -542,42 +616,51 @@ fn creator_dao_tests() { pocket_ic.tick(); } - let res = pocket_ic.query_call( - swap_canister, - super_admin, - "get_init", - candid::encode_one(GetInitRequest {}).unwrap(), - ).map(|res| { - let response = match res { - WasmResult::Reply(payload) => Decode!(&payload, GetInitResponse).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .query_call( + swap_canister, + super_admin, + "get_init", + candid::encode_one(GetInitRequest {}).unwrap(), + ) + .map(|res| { + let response = match res { + WasmResult::Reply(payload) => Decode!(&payload, GetInitResponse).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); - let res = pocket_ic.update_call( - gov_canister, - super_admin, - "list_neurons", - candid::encode_one(ListNeurons { - of_principal: Some(PrincipalId(alice_principal)), - limit: 2, - start_page_at: None - }).unwrap() - ).map(|res| { - let response: ListNeuronsResponse = match res { - WasmResult::Reply(payload) => Decode!(&payload, ListNeuronsResponse).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + gov_canister, + super_admin, + "list_neurons", + candid::encode_one(ListNeurons { + of_principal: Some(PrincipalId(alice_principal)), + limit: 2, + start_page_at: None, + }) + .unwrap(), + ) + .map(|res| { + let response: ListNeuronsResponse = match res { + WasmResult::Reply(payload) => Decode!(&payload, ListNeuronsResponse).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); let neurons = res.neurons; let mut ix = 0; if neurons[1].dissolve_state.is_some() { - if let Some(neuron::DissolveState::DissolveDelaySeconds(x)) = neurons[1].dissolve_state.as_ref() { + if let Some(neuron::DissolveState::DissolveDelaySeconds(x)) = + neurons[1].dissolve_state.as_ref() + { if *x == 0 { ix = 1; } @@ -587,46 +670,58 @@ fn creator_dao_tests() { let amount = neurons[ix].cached_neuron_stake_e8s; let manage_neuron_arg = ManageNeuron { subaccount: neuron_id, - command: Some( - manage_neuron::Command::Disburse(manage_neuron::Disburse { - to_account: Some(Account { - owner: Some(PrincipalId(alice_principal)), - subaccount: None - }), - amount: Some(manage_neuron::disburse::Amount { e8s: amount }) - }) - ) + command: Some(manage_neuron::Command::Disburse(manage_neuron::Disburse { + to_account: Some(Account { + owner: Some(PrincipalId(alice_principal)), + subaccount: None, + }), + amount: Some(manage_neuron::disburse::Amount { e8s: amount }), + })), }; - let res = pocket_ic.update_call( - gov_canister, - alice_principal, - "manage_neuron", - candid::encode_one(manage_neuron_arg).unwrap() - ).map(|res| { - let response: ManageNeuronResponse = match res { - WasmResult::Reply(payload) => Decode!(&payload, ManageNeuronResponse).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .update_call( + gov_canister, + alice_principal, + "manage_neuron", + candid::encode_one(manage_neuron_arg).unwrap(), + ) + .map(|res| { + let response: ManageNeuronResponse = match res { + WasmResult::Reply(payload) => Decode!(&payload, ManageNeuronResponse).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช Result: {:?}", res); - let res = pocket_ic.query_call( - ledger_canister, - alice_principal, - "icrc1_balance_of", - candid::encode_one(types::Icrc1BalanceOfArg{owner: alice_principal, subaccount: None}).unwrap(), - ).map(|res| { - let response = match res { - WasmResult::Reply(payload) => Decode!(&payload, Nat).unwrap(), - _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), - }; - response - }).unwrap(); + let res = pocket_ic + .query_call( + ledger_canister, + alice_principal, + "icrc1_balance_of", + candid::encode_one(types::Icrc1BalanceOfArg { + owner: alice_principal, + subaccount: None, + }) + .unwrap(), + ) + .map(|res| { + let response = match res { + WasmResult::Reply(payload) => Decode!(&payload, Nat).unwrap(), + _ => panic!("\n๐Ÿ›‘ get requester principals canister id failed\n"), + }; + response + }) + .unwrap(); ic_cdk::println!("๐Ÿงช SNS token Balance of alice: {:?}", res); let expected_balance = Nat::from(4_400_000 - tx_fee); ic_cdk::println!("๐Ÿงช Expected Balance: {:?}", expected_balance); + let alice_canister_final_cycle_balance = pocket_ic.cycle_balance(alice_canister_id); + + assert!(alice_canister_final_cycle_balance > alice_initial_cycle_balance); + assert!(res == expected_balance); } diff --git a/src/lib/shared_utils/src/canister_specific/individual_user_template/types/error.rs b/src/lib/shared_utils/src/canister_specific/individual_user_template/types/error.rs index 9aa00836..2e22806a 100644 --- a/src/lib/shared_utils/src/canister_specific/individual_user_template/types/error.rs +++ b/src/lib/shared_utils/src/canister_specific/individual_user_template/types/error.rs @@ -49,6 +49,7 @@ pub enum CdaoDeployError { CallError(RejectionCode, String), InvalidInitPayload(String), Unauthenticated, + CycleError(String), } impl From<(RejectionCode, String)> for CdaoDeployError { @@ -63,7 +64,7 @@ pub enum CdaoTokenError { Transfer(TransferError), NoBalance, CallError(RejectionCode, String), - Unauthenticated + Unauthenticated, } impl From<(RejectionCode, String)> for CdaoTokenError { diff --git a/src/lib/shared_utils/src/constant.rs b/src/lib/shared_utils/src/constant.rs index 04eb4013..69e4a3f0 100644 --- a/src/lib/shared_utils/src/constant.rs +++ b/src/lib/shared_utils/src/constant.rs @@ -9,6 +9,7 @@ pub const SUBNET_ORCHESTRATOR_CANISTER_INITIAL_CYCLES: u128 = 2_500_000_000_000_ pub const SUBNET_ORCHESTRATOR_CANISTER_CYCLES_THRESHOLD: u128 = 1_000_000_000_000_000; //1kT Cycles pub const POST_CACHE_CANISTER_CYCLES_RECHARGE_AMOUMT: u128 = 5_000_000_000_000; //5T Cycles pub const POST_CACHE_CANISTER_CYCLES_THRESHOLD: u128 = 2_000_000_000_000; //2T Cycles +pub const USER_SNS_CANISTER_INITIAL_CYCLES: u128 = 500_000_000_000; //0.5T Cycles pub const PAGE_SIZE_RECHARGE_DIVIDER: u128 = 500; // 500 pages (recharge by page_size/page_size_recharge_divider * recharge_amout) pub const MAX_USERS_IN_FOLLOWER_FOLLOWING_LIST: u64 = 10000;