diff --git a/backend/canisters/user_index/api/can.did b/backend/canisters/user_index/api/can.did index ab8e79c8b6..2b6d222974 100644 --- a/backend/canisters/user_index/api/can.did +++ b/backend/canisters/user_index/api/can.did @@ -309,6 +309,25 @@ type SetUserUpgradeConcurrencyResponse = variant { Success; }; +type SetDiamondMembershipFeesArgs = record { + fees : record { + chat_fees : DiamondMembershipFeesByDuration; + icp_fees : DiamondMembershipFeesByDuration; + }; +}; + +type DiamondMembershipFeesByDuration = record { + one_month : nat64; + three_months : nat64; + one_year : nat64; + lifetime : nat64; +}; + +type SetDiamondMembershipFeesResponse = variant { + Success; + Invalid; +}; + type AddReferralCodesArgs = record { referral_type : ReferralType; codes : vec text; @@ -381,6 +400,7 @@ service : { // Only callable by "platform operators" set_user_upgrade_concurrency : (SetUserUpgradeConcurrencyArgs) -> (SetUserUpgradeConcurrencyResponse); + set_diamond_membership_fees : (SetDiamondMembershipFeesArgs) -> (SetDiamondMembershipFeesResponse); // Only callable by OC dev team dfx identity add_referral_codes : (AddReferralCodesArgs) -> (AddReferralCodesResponse); diff --git a/backend/canisters/user_index/api/src/main.rs b/backend/canisters/user_index/api/src/main.rs index f5dd871494..a4a3d053ee 100644 --- a/backend/canisters/user_index/api/src/main.rs +++ b/backend/canisters/user_index/api/src/main.rs @@ -24,6 +24,7 @@ fn main() { generate_candid_method!(user_index, pay_for_diamond_membership, update); generate_candid_method!(user_index, remove_platform_moderator, update); generate_candid_method!(user_index, remove_platform_operator, update); + generate_candid_method!(user_index, set_diamond_membership_fees, update); generate_candid_method!(user_index, set_display_name, update); generate_candid_method!(user_index, set_user_upgrade_concurrency, update); generate_candid_method!(user_index, set_moderation_flags, update); diff --git a/backend/canisters/user_index/api/src/updates/mod.rs b/backend/canisters/user_index/api/src/updates/mod.rs index 8928c5fd6e..98cc960b2c 100644 --- a/backend/canisters/user_index/api/src/updates/mod.rs +++ b/backend/canisters/user_index/api/src/updates/mod.rs @@ -18,6 +18,7 @@ pub mod pay_for_diamond_membership; pub mod remove_platform_moderator; pub mod remove_platform_operator; pub mod remove_sms_messages; +pub mod set_diamond_membership_fees; pub mod set_display_name; pub mod set_max_concurrent_user_canister_upgrades; pub mod set_moderation_flags; diff --git a/backend/canisters/user_index/api/src/updates/set_diamond_membership_fees.rs b/backend/canisters/user_index/api/src/updates/set_diamond_membership_fees.rs new file mode 100644 index 0000000000..efde09ad9a --- /dev/null +++ b/backend/canisters/user_index/api/src/updates/set_diamond_membership_fees.rs @@ -0,0 +1,14 @@ +use candid::CandidType; +use serde::{Deserialize, Serialize}; +use types::DiamondMembershipFees; + +#[derive(CandidType, Serialize, Deserialize, Debug)] +pub struct Args { + pub fees: DiamondMembershipFees, +} + +#[derive(CandidType, Serialize, Deserialize, Debug)] +pub enum Response { + Success, + Invalid, +} diff --git a/backend/canisters/user_index/impl/src/lib.rs b/backend/canisters/user_index/impl/src/lib.rs index 97ed9b370c..e31f7babe2 100644 --- a/backend/canisters/user_index/impl/src/lib.rs +++ b/backend/canisters/user_index/impl/src/lib.rs @@ -21,7 +21,8 @@ use serde::{Deserialize, Serialize}; use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use types::{ - BuildVersion, CanisterId, CanisterWasm, ChatId, Cryptocurrency, Cycles, Milliseconds, TimestampMillis, Timestamped, UserId, + BuildVersion, CanisterId, CanisterWasm, ChatId, Cryptocurrency, Cycles, DiamondMembershipFees, Milliseconds, + TimestampMillis, Timestamped, UserId, }; use utils::canister::{CanistersRequiringUpgrade, FailedUpgradeCount}; use utils::canister_event_sync_queue::CanisterEventSyncQueue; @@ -228,6 +229,8 @@ struct Data { pub fire_and_forget_handler: FireAndForgetHandler, pub nns_8_year_neuron: Option, pub rng_seed: [u8; 32], + #[serde(default)] + pub diamond_membership_fees: DiamondMembershipFees, } fn escrow_canister_id() -> CanisterId { @@ -285,6 +288,7 @@ impl Data { reported_messages: ReportedMessages::default(), fire_and_forget_handler: FireAndForgetHandler::default(), rng_seed: [0; 32], + diamond_membership_fees: DiamondMembershipFees::default(), }; // Register the ProposalsBot @@ -366,6 +370,7 @@ impl Default for Data { fire_and_forget_handler: FireAndForgetHandler::default(), nns_8_year_neuron: None, rng_seed: [0; 32], + diamond_membership_fees: DiamondMembershipFees::default(), } } } diff --git a/backend/canisters/user_index/impl/src/queries/diamond_membership_fees.rs b/backend/canisters/user_index/impl/src/queries/diamond_membership_fees.rs index 4c80a1ca78..5bece40782 100644 --- a/backend/canisters/user_index/impl/src/queries/diamond_membership_fees.rs +++ b/backend/canisters/user_index/impl/src/queries/diamond_membership_fees.rs @@ -1,23 +1,31 @@ use ic_cdk_macros::query; -use types::{Cryptocurrency, DiamondMembershipPlanDuration}; +use types::Cryptocurrency; use user_index_canister::diamond_membership_fees::{Response::*, *}; +use crate::{read_state, RuntimeState}; + #[query] fn diamond_membership_fees(_args: Args) -> Response { + read_state(diamond_membership_fees_impl) +} + +fn diamond_membership_fees_impl(state: &RuntimeState) -> Response { + let fees = &state.data.diamond_membership_fees; + let fees = vec![ DiamondMembershipFees { token: Cryptocurrency::CHAT, - one_month: DiamondMembershipPlanDuration::OneMonth.chat_price_e8s(), - three_months: DiamondMembershipPlanDuration::ThreeMonths.chat_price_e8s(), - one_year: DiamondMembershipPlanDuration::OneYear.chat_price_e8s(), - lifetime: DiamondMembershipPlanDuration::Lifetime.chat_price_e8s(), + one_month: fees.chat_fees.one_month, + three_months: fees.chat_fees.three_months, + one_year: fees.chat_fees.one_year, + lifetime: fees.chat_fees.lifetime, }, DiamondMembershipFees { token: Cryptocurrency::InternetComputer, - one_month: DiamondMembershipPlanDuration::OneMonth.icp_price_e8s(), - three_months: DiamondMembershipPlanDuration::ThreeMonths.icp_price_e8s(), - one_year: DiamondMembershipPlanDuration::OneYear.icp_price_e8s(), - lifetime: DiamondMembershipPlanDuration::Lifetime.icp_price_e8s(), + one_month: fees.icp_fees.one_month, + three_months: fees.icp_fees.three_months, + one_year: fees.icp_fees.one_year, + lifetime: fees.icp_fees.lifetime, }, ]; diff --git a/backend/canisters/user_index/impl/src/timer_job_types.rs b/backend/canisters/user_index/impl/src/timer_job_types.rs index 5819dc4bc6..6094eaf14b 100644 --- a/backend/canisters/user_index/impl/src/timer_job_types.rs +++ b/backend/canisters/user_index/impl/src/timer_job_types.rs @@ -7,7 +7,8 @@ use ic_ledger_types::Tokens; use local_user_index_canister::{Event as LocalUserIndexEvent, OpenChatBotMessage, UserJoinedGroup}; use serde::{Deserialize, Serialize}; use types::{ - ChatId, CommunityId, Cryptocurrency, DiamondMembershipPlanDuration, MessageContent, Milliseconds, TextContent, UserId, + ChatId, CommunityId, Cryptocurrency, DiamondMembershipFees, DiamondMembershipPlanDuration, MessageContent, Milliseconds, + TextContent, UserId, }; use utils::time::{MINUTE_IN_MS, SECOND_IN_MS}; @@ -77,8 +78,9 @@ impl Job for TimerJob { impl Job for RecurringDiamondMembershipPayment { fn execute(self) { - if let Some((duration, pay_in_chat)) = read_state(|state| { + if let Some((duration, pay_in_chat, fees)) = read_state(|state| { let now = state.env.now(); + let fees = state.data.diamond_membership_fees.clone(); state .data .users @@ -88,16 +90,21 @@ impl Job for RecurringDiamondMembershipPayment { .and_then(|d| { DiamondMembershipPlanDuration::try_from(d.subscription()) .ok() - .map(|duration| (duration, d.pay_in_chat())) + .map(|duration| (duration, d.pay_in_chat(), fees)) }) }) { - ic_cdk::spawn(pay_for_diamond_membership(self.user_id, duration, pay_in_chat)); + ic_cdk::spawn(pay_for_diamond_membership(self.user_id, duration, fees, pay_in_chat)); } - async fn pay_for_diamond_membership(user_id: UserId, duration: DiamondMembershipPlanDuration, pay_in_chat: bool) { + async fn pay_for_diamond_membership( + user_id: UserId, + duration: DiamondMembershipPlanDuration, + fees: DiamondMembershipFees, + pay_in_chat: bool, + ) { use user_index_canister::pay_for_diamond_membership::*; - let price_e8s = if pay_in_chat { duration.chat_price_e8s() } else { duration.icp_price_e8s() }; + let price_e8s = if pay_in_chat { fees.chat_price_e8s(duration) } else { fees.icp_price_e8s(duration) }; let args = Args { duration, diff --git a/backend/canisters/user_index/impl/src/updates/mod.rs b/backend/canisters/user_index/impl/src/updates/mod.rs index aa66139dd0..8de23ed613 100644 --- a/backend/canisters/user_index/impl/src/updates/mod.rs +++ b/backend/canisters/user_index/impl/src/updates/mod.rs @@ -17,6 +17,7 @@ pub mod modclub_callback; pub mod pay_for_diamond_membership; pub mod remove_platform_moderator; pub mod remove_platform_operator; +pub mod set_diamond_membership_fees; pub mod set_display_name; pub mod set_max_concurrent_user_canister_upgrades; pub mod set_moderation_flags; diff --git a/backend/canisters/user_index/impl/src/updates/pay_for_diamond_membership.rs b/backend/canisters/user_index/impl/src/updates/pay_for_diamond_membership.rs index 653ffb0aba..0d1b4d51a0 100644 --- a/backend/canisters/user_index/impl/src/updates/pay_for_diamond_membership.rs +++ b/backend/canisters/user_index/impl/src/updates/pay_for_diamond_membership.rs @@ -12,7 +12,7 @@ use local_user_index_canister::{DiamondMembershipPaymentReceived, Event}; use rand::Rng; use storage_index_canister::add_or_update_users::UserConfig; use tracing::error; -use types::{Cryptocurrency, DiamondMembershipPlanDuration, UserId, ICP}; +use types::{Cryptocurrency, DiamondMembershipFees, DiamondMembershipPlanDuration, UserId, ICP}; use user_index_canister::pay_for_diamond_membership::{Response::*, *}; use utils::consts::SNS_GOVERNANCE_CANISTER_ID; use utils::time::DAY_IN_MS; @@ -64,6 +64,7 @@ pub(crate) async fn pay_for_diamond_membership_impl(args: Args, user_id: UserId, fn prepare(args: &Args, user_id: UserId, state: &mut RuntimeState) -> Result<(), Response> { let diamond_membership = state.data.users.diamond_membership_details_mut(&user_id).unwrap(); + let fees = &state.data.diamond_membership_fees; if diamond_membership.payment_in_progress() { Err(PaymentAlreadyInProgress) } else if diamond_membership.is_lifetime_diamond_member() { @@ -71,12 +72,12 @@ fn prepare(args: &Args, user_id: UserId, state: &mut RuntimeState) -> Result<(), } else { match args.token { Cryptocurrency::CHAT => { - if args.expected_price_e8s != args.duration.chat_price_e8s() { + if args.expected_price_e8s != fees.chat_price_e8s(args.duration) { return Err(PriceMismatch); } } Cryptocurrency::InternetComputer => { - if args.expected_price_e8s != args.duration.icp_price_e8s() { + if args.expected_price_e8s != fees.icp_price_e8s(args.duration) { return Err(PriceMismatch); } } @@ -155,7 +156,9 @@ fn process_charge( let now_nanos = state.env.now_nanos(); if let Some(share_with) = share_with { - let amount_to_referrer = amount_to_referer(&args.token, args.duration); + let fees = &state.data.diamond_membership_fees; + + let amount_to_referrer = amount_to_referer(&args.token, args.duration, fees); amount_to_treasury = amount_to_treasury.saturating_sub(amount_to_referrer + transaction_fee); let referral_payment = PendingPayment { @@ -251,7 +254,7 @@ fn referrer_to_share_payment(user_id: UserId, state: &RuntimeState) -> Option u64 { +fn amount_to_referer(token: &Cryptocurrency, duration: DiamondMembershipPlanDuration, fees: &DiamondMembershipFees) -> u64 { // The referral reward is only for membership payments for the first year, so if a user pays for // lifetime Diamond membership, the referer is rewarded as if they had paid for 1 year. let reward_based_on_duration = if matches!(duration, DiamondMembershipPlanDuration::Lifetime) { @@ -261,9 +264,9 @@ fn amount_to_referer(token: &Cryptocurrency, duration: DiamondMembershipPlanDura }; if matches!(token, Cryptocurrency::CHAT) { - reward_based_on_duration.chat_price_e8s() / 2 + fees.chat_price_e8s(reward_based_on_duration) / 2 } else { - reward_based_on_duration.icp_price_e8s() / 2 + fees.icp_price_e8s(reward_based_on_duration) / 2 } } diff --git a/backend/canisters/user_index/impl/src/updates/set_diamond_membership_fees.rs b/backend/canisters/user_index/impl/src/updates/set_diamond_membership_fees.rs new file mode 100644 index 0000000000..a867b0447b --- /dev/null +++ b/backend/canisters/user_index/impl/src/updates/set_diamond_membership_fees.rs @@ -0,0 +1,29 @@ +use crate::guards::caller_is_platform_operator; +use crate::{mutate_state, RuntimeState}; +use canister_tracing_macros::trace; +use ic_cdk_macros::update; +use types::{DiamondMembershipFees, DiamondMembershipFeesByDuration}; +use user_index_canister::set_diamond_membership_fees::{Response::*, *}; + +#[update(guard = "caller_is_platform_operator")] +#[trace] +fn set_diamond_membership_fees(args: Args) -> Response { + mutate_state(|state| set_diamond_membership_fees_impl(args, state)) +} + +fn set_diamond_membership_fees_impl(args: Args, state: &mut RuntimeState) -> Response { + if fees_valid(&args.fees) { + state.data.diamond_membership_fees = args.fees; + Success + } else { + Invalid + } +} + +fn fees_valid(fees: &DiamondMembershipFees) -> bool { + fees_by_duration_valid(&fees.chat_fees) && fees_by_duration_valid(&fees.icp_fees) +} + +fn fees_by_duration_valid(fees: &DiamondMembershipFeesByDuration) -> bool { + (fees.one_month < fees.three_months) && (fees.three_months < fees.one_year) && (fees.one_year < fees.lifetime) +} diff --git a/backend/integration_tests/src/client/user_index.rs b/backend/integration_tests/src/client/user_index.rs index 63e1e58961..bccacdb4dd 100644 --- a/backend/integration_tests/src/client/user_index.rs +++ b/backend/integration_tests/src/client/user_index.rs @@ -29,7 +29,8 @@ pub mod happy_path { use candid::Principal; use pocket_ic::PocketIc; use types::{ - CanisterId, CanisterWasm, Cryptocurrency, DiamondMembershipDetails, DiamondMembershipPlanDuration, UserId, UserSummary, + CanisterId, CanisterWasm, Cryptocurrency, DiamondMembershipDetails, DiamondMembershipFees, + DiamondMembershipPlanDuration, UserId, UserSummary, }; use user_index_canister::users_v2::UserGroup; @@ -80,6 +81,8 @@ pub mod happy_path { pay_in_chat: bool, recurring: bool, ) -> DiamondMembershipDetails { + let fees = DiamondMembershipFees::default(); + let response = super::pay_for_diamond_membership( env, sender, @@ -87,7 +90,7 @@ pub mod happy_path { &user_index_canister::pay_for_diamond_membership::Args { duration, token: if pay_in_chat { Cryptocurrency::CHAT } else { Cryptocurrency::InternetComputer }, - expected_price_e8s: if pay_in_chat { duration.chat_price_e8s() } else { duration.icp_price_e8s() }, + expected_price_e8s: if pay_in_chat { fees.chat_price_e8s(duration) } else { fees.icp_price_e8s(duration) }, recurring, }, ); diff --git a/backend/integration_tests/src/diamond_membership_tests.rs b/backend/integration_tests/src/diamond_membership_tests.rs index 1ad476a140..400dfbbfe4 100644 --- a/backend/integration_tests/src/diamond_membership_tests.rs +++ b/backend/integration_tests/src/diamond_membership_tests.rs @@ -6,7 +6,7 @@ use serial_test::serial; use std::ops::Deref; use std::time::Duration; use test_case::test_case; -use types::{Cryptocurrency, DiamondMembershipPlanDuration, DiamondMembershipSubscription}; +use types::{Cryptocurrency, DiamondMembershipFees, DiamondMembershipPlanDuration, DiamondMembershipSubscription}; use utils::consts::SNS_GOVERNANCE_CANISTER_ID; use utils::time::MINUTE_IN_MS; @@ -68,11 +68,13 @@ fn can_upgrade_to_diamond(pay_in_chat: bool, lifetime: bool) { .subscription .is_active()); + let fees = DiamondMembershipFees::default(); + let (expected_price, transfer_fee) = if pay_in_chat { - (duration.chat_price_e8s() as u128, Cryptocurrency::CHAT.fee().unwrap()) + (fees.chat_price_e8s(duration) as u128, Cryptocurrency::CHAT.fee().unwrap()) } else { ( - duration.icp_price_e8s() as u128, + fees.icp_price_e8s(duration) as u128, Cryptocurrency::InternetComputer.fee().unwrap(), ) }; @@ -129,9 +131,11 @@ fn membership_renews_automatically_if_set_to_recurring(ledger_error: bool) { .is_active()); let new_balance = client::icrc1::happy_path::balance_of(env, canister_ids.icp_ledger, user.user_id); + let fees = DiamondMembershipFees::default(); + assert_eq!( new_balance, - 1_000_000_000 - (2 * DiamondMembershipPlanDuration::OneMonth.icp_price_e8s() as u128) + 1_000_000_000 - (2 * fees.icp_price_e8s(DiamondMembershipPlanDuration::OneMonth) as u128) ); } @@ -176,10 +180,12 @@ fn membership_payment_shared_with_referrer(lifetime: bool) { }; client::upgrade_user(&user_b, env, canister_ids, *controller, duration); + let fees = DiamondMembershipFees::default(); + let amount_to_referer = if lifetime { - DiamondMembershipPlanDuration::OneYear.icp_price_e8s() / 2 + fees.icp_price_e8s(DiamondMembershipPlanDuration::OneYear) / 2 } else { - DiamondMembershipPlanDuration::OneMonth.icp_price_e8s() / 2 + fees.icp_price_e8s(DiamondMembershipPlanDuration::OneMonth) / 2 } as u128; // Check the referrer has been credited with half the Diamond payment @@ -188,9 +194,11 @@ fn membership_payment_shared_with_referrer(lifetime: bool) { // Check the treasury has received the remainder less the fees let treasury_balance = client::icrc1::happy_path::balance_of(env, canister_ids.icp_ledger, SNS_GOVERNANCE_CANISTER_ID); + let fees = DiamondMembershipFees::default(); + assert_eq!( treasury_balance - init_treasury_balance, - u128::from(duration.icp_price_e8s()) - amount_to_referer - (3 * Cryptocurrency::InternetComputer.fee().unwrap()) + u128::from(fees.icp_price_e8s(duration)) - amount_to_referer - (3 * Cryptocurrency::InternetComputer.fee().unwrap()) ); } @@ -231,6 +239,7 @@ fn update_subscription_succeeds(disable: bool) { tick_many(env, 5); let user_response = client::user_index::happy_path::current_user(env, user.principal, canister_ids.user_index); + let fees = DiamondMembershipFees::default(); if disable { assert_eq!( @@ -245,7 +254,7 @@ fn update_subscription_succeeds(disable: bool) { let new_balance = client::icrc1::happy_path::balance_of(env, canister_ids.icp_ledger, user.user_id); assert_eq!( new_balance, - 1_000_000_000 - DiamondMembershipPlanDuration::OneMonth.icp_price_e8s() as u128 + 1_000_000_000 - fees.icp_price_e8s(DiamondMembershipPlanDuration::OneMonth) as u128 ); } else { let one_year_millis = DiamondMembershipPlanDuration::OneYear.as_millis(); @@ -262,8 +271,8 @@ fn update_subscription_succeeds(disable: bool) { assert_eq!( new_balance, 1_000_000_000 - - (DiamondMembershipPlanDuration::OneMonth.icp_price_e8s() - + DiamondMembershipPlanDuration::OneYear.icp_price_e8s()) as u128 + - (fees.icp_price_e8s(DiamondMembershipPlanDuration::OneMonth) + + fees.icp_price_e8s(DiamondMembershipPlanDuration::OneYear)) as u128 ); } } diff --git a/backend/libraries/types/src/diamond_membership.rs b/backend/libraries/types/src/diamond_membership.rs index a736bae885..e759719d25 100644 --- a/backend/libraries/types/src/diamond_membership.rs +++ b/backend/libraries/types/src/diamond_membership.rs @@ -35,6 +35,59 @@ pub enum DiamondMembershipPlanDuration { Lifetime = 255, } +#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] +pub struct DiamondMembershipFees { + pub chat_fees: DiamondMembershipFeesByDuration, + pub icp_fees: DiamondMembershipFeesByDuration, +} + +#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] +pub struct DiamondMembershipFeesByDuration { + pub one_month: u64, + pub three_months: u64, + pub one_year: u64, + pub lifetime: u64, +} + +impl DiamondMembershipFees { + pub fn chat_price_e8s(&self, duration: DiamondMembershipPlanDuration) -> u64 { + match duration { + DiamondMembershipPlanDuration::OneMonth => self.chat_fees.one_month, + DiamondMembershipPlanDuration::ThreeMonths => self.chat_fees.three_months, + DiamondMembershipPlanDuration::OneYear => self.chat_fees.one_year, + DiamondMembershipPlanDuration::Lifetime => self.chat_fees.lifetime, + } + } + + pub fn icp_price_e8s(&self, duration: DiamondMembershipPlanDuration) -> u64 { + match duration { + DiamondMembershipPlanDuration::OneMonth => self.icp_fees.one_month, + DiamondMembershipPlanDuration::ThreeMonths => self.icp_fees.three_months, + DiamondMembershipPlanDuration::OneYear => self.icp_fees.one_year, + DiamondMembershipPlanDuration::Lifetime => self.icp_fees.lifetime, + } + } +} + +impl Default for DiamondMembershipFees { + fn default() -> Self { + DiamondMembershipFees { + chat_fees: DiamondMembershipFeesByDuration { + one_month: 200_000_000, // 2 CHAT + three_months: 500_000_000, // 5 CHAT + one_year: 1_500_000_000, // 15 CHAT + lifetime: 6_000_000_000, // 60 CHAT + }, + icp_fees: DiamondMembershipFeesByDuration { + one_month: 15_000_000, // 0.15 ICP + three_months: 35_000_000, // 0.35 ICP + one_year: 100_000_000, // 1 ICP + lifetime: 400_000_000, // 4 ICP + }, + } + } +} + impl DiamondMembershipPlanDuration { // Using 1 year = 365.25 days const MONTH_IN_MS: Milliseconds = ((4 * 365) + 1) * 24 * 60 * 60 * 1000 / (4 * 12); @@ -48,24 +101,6 @@ impl DiamondMembershipPlanDuration { } } - pub const fn icp_price_e8s(&self) -> u64 { - match self { - DiamondMembershipPlanDuration::OneMonth => 15_000_000, // 0.15 ICP - DiamondMembershipPlanDuration::ThreeMonths => 35_000_000, // 0.35 ICP - DiamondMembershipPlanDuration::OneYear => 100_000_000, // 1 ICP - DiamondMembershipPlanDuration::Lifetime => 400_000_000, // 4 ICP - } - } - - pub const fn chat_price_e8s(&self) -> u64 { - match self { - DiamondMembershipPlanDuration::OneMonth => 200_000_000, // 2 CHAT - DiamondMembershipPlanDuration::ThreeMonths => 500_000_000, // 5 CHAT - DiamondMembershipPlanDuration::OneYear => 1_500_000_000, // 15 CHAT - DiamondMembershipPlanDuration::Lifetime => 6_000_000_000, // 60 CHAT - } - } - pub const fn is_lifetime(&self) -> bool { matches!(self, DiamondMembershipPlanDuration::Lifetime) }