Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: proof of participation #471

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8e9d3e1
feat(shared_utils): add utility for proof of participation
rupansh Sep 29, 2024
89778da
feat: initial integration for proof of participation
rupansh Sep 29, 2024
3580a3a
feat: add new referral flow with proof of participation
rupansh Sep 29, 2024
17c20b2
chore: rename Proof of Participant related identifiers
rupansh Oct 23, 2024
5745f1f
refactor: move PoP data to heap
rupansh Nov 27, 2024
7f03139
fix: update post_upgrade hooks for individual user and user index
rupansh Oct 24, 2024
8f48fda
refactor: use `DFX_NETWORK` instead of feature flag for local network…
rupansh Oct 24, 2024
b1626a6
chore(scripts/local_deploy/install_all_canisters): remove unnecessary…
rupansh Oct 24, 2024
bc8334f
chore: update nix env
rupansh Oct 24, 2024
ef9d96e
feat: add proof of participation merkleization
rupansh Nov 3, 2024
24cf650
chore(integration_tests/authentication/referral): increase waiting ti…
rupansh Nov 27, 2024
86dcaac
Revert "chore(integration_tests/authentication/referral): increase wa…
rupansh Nov 27, 2024
3018f16
fix(scripts/local_deploy/install_all_canisters): add back gzip
rupansh Nov 27, 2024
97003fc
fix+refactor(shared_utils/participant_crypto): use GenericArray inste…
rupansh Nov 27, 2024
d5c6035
refactor: switch from ciborium to minicbor-serde
rupansh Nov 29, 2024
41a16a1
Merge remote-tracking branch 'origin/main' into rupansh/pop
rupansh Nov 29, 2024
4a1cd56
refactor(integration_tests): update wait time for provision_subnet_or…
rupansh Nov 29, 2024
c870115
fix(user_index/create_pool_of_available_canisters): decrease concurrency
rupansh Nov 29, 2024
c1e983c
fix: fixes for integration tests
rupansh Dec 2, 2024
967378c
Merge remote-tracking branch 'origin/main' into rupansh/pop
rupansh Dec 2, 2024
68c4273
fix(test_utils/pocket_ic_env): fix provision_n_subnet_orchestrator_ca…
rupansh Dec 2, 2024
442f1f5
fix: fixes for subnet orchestrator tests
rupansh Dec 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
257 changes: 205 additions & 52 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ members = [

[workspace.dependencies]
candid = "0.10.2"
ciborium = "0.2.1"
minicbor-serde = { version = "0.3.2", features = ["std"] }
pocket-ic = "6.0.0"
ic-cdk = "0.15.1"
ic-cdk-timers = "0.7.0"
Expand Down
2 changes: 1 addition & 1 deletion default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ let
rev = "1c3a28d84f970e7774af04372ade06399add182e";
nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/archive/${rev}.tar.gz";
pkgs = import nixpkgs { };
dfx-env = import (builtins.fetchTarball "https://github.com/ninegua/ic-nix/releases/download/20240610/dfx-env.tar.gz") { version = "20240610"; inherit pkgs; };
dfx-env = import (builtins.fetchTarball "https://github.com/ninegua/ic-nix/releases/download/20240924/dfx-env.tar.gz") { version = "20240924"; inherit pkgs; };
in
dfx-env.overrideAttrs (old: {
nativeBuildInputs = with pkgs; old.nativeBuildInputs ++
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ char_escaped=$(printf "%s" "$char" | sed 's/../\\&/g')

# Create a shell script with the escaped hexadecimal string
printf "(\"v1.0.0\", blob \"%s\")" "$char_escaped" > argument
dfx canister call user_index create_pool_of_individual_user_available_canisters --argument-file argument
dfx ledger fabricate-cycles --cycles 20000000000000000 --canister user_index
dfx canister call user_index create_pool_of_individual_user_available_canisters --argument-file argument
3 changes: 3 additions & 0 deletions scripts/canisters/local_deploy/install_all_canisters.sh
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ dfx canister install user_index --argument "(record {
vec { variant { CanisterAdmin }; variant { CanisterController }; }
};
};
proof_of_participation = opt record {
chain = vec {};
};
version= \"v1.0.0\"
})"

Expand Down
3 changes: 2 additions & 1 deletion src/canister/individual_user_template/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ crate-type = ["cdylib"]

[dependencies]
candid = { workspace = true }
ciborium = { workspace = true }
minicbor-serde = { workspace = true }
ic-stable-structures = { workspace = true }
ic-cdk = { workspace = true }
ic-cdk-timers = { workspace = true }
Expand All @@ -36,3 +36,4 @@ hex = "0.4.3"

[dev-dependencies]
test_utils = { workspace = true }

60 changes: 36 additions & 24 deletions src/canister/individual_user_template/can.did
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ type IndividualUserCreatorDaoEntry = record {
individual_profile_id : principal;
};
type IndividualUserTemplateInitArgs = record {
proof_of_participation : opt ProofOfParticipation;
known_principal_ids : opt vec record { KnownPrincipalType; principal };
version : text;
url_to_send_canister_metrics_to : opt text;
Expand Down Expand Up @@ -347,6 +348,13 @@ type PostViewStatistics = record {
threshold_view_count : nat64;
};
type Principals = record { principals : vec principal };
type ProofOfChild = record {
proof_of_inclusion : vec blob;
"principal" : principal;
children_proof : ProofOfChildren;
};
type ProofOfChildren = record { signature : blob; merkle_root : blob };
type ProofOfParticipation = record { chain : vec ProofOfChild };
type RejectionCode = variant {
NoError;
CanisterError;
Expand Down Expand Up @@ -376,17 +384,17 @@ type Result_18 = variant { Ok : vec text; Err : NamespaceErrors };
type Result_19 = variant { Ok : vec record { nat64; nat8 }; Err : text };
type Result_2 = variant { Ok : bool; Err : CdaoTokenError };
type Result_20 = variant { Ok; Err : MigrationErrors };
type Result_21 = variant { Ok; Err : AirdropError };
type Result_22 = variant { Ok : text; Err : text };
type Result_23 = variant { Ok : IndividualUserCreatorDaoEntry; Err : text };
type Result_24 = variant { Committed : Committed; Aborted : record {} };
type Result_25 = variant { Ok : Ok; Err : GovernanceError };
type Result_26 = variant { Ok; Err : CdaoTokenError };
type Result_27 = variant {
type Result_21 = variant { Ok; Err : text };
type Result_22 = variant { Ok; Err : AirdropError };
type Result_23 = variant { Ok : text; Err : text };
type Result_24 = variant { Ok : IndividualUserCreatorDaoEntry; Err : text };
type Result_25 = variant { Committed : Committed; Aborted : record {} };
type Result_26 = variant { Ok : Ok; Err : GovernanceError };
type Result_27 = variant { Ok; Err : CdaoTokenError };
type Result_28 = variant {
Ok : UserProfileDetailsForFrontend;
Err : UpdateProfileDetailsError;
};
type Result_28 = variant { Ok; Err : text };
type Result_29 = variant { Ok; Err : UpdateProfileSetUniqueUsernameError };
type Result_3 = variant {
Ok : BettingStatus;
Expand All @@ -408,10 +416,10 @@ type RoomDetails = record {
};
type SessionType = variant { AnonymousSession; RegisteredSession };
type SettleNeuronsFundParticipationRequest = record {
result : opt Result_24;
result : opt Result_25;
nns_proposal_id : opt nat64;
};
type SettleNeuronsFundParticipationResponse = record { result : opt Result_25 };
type SettleNeuronsFundParticipationResponse = record { result : opt Result_26 };
type SlotDetails = record { room_details : vec record { nat64; RoomDetails } };
type SnsInitPayload = record {
url : opt text;
Expand Down Expand Up @@ -631,45 +639,49 @@ service : (IndividualUserTemplateInitArgs) -> {
receive_bet_from_bet_makers_canister : (PlaceBetArg, principal) -> (Result_3);
receive_bet_winnings_when_distributed : (nat64, BetOutcomeForBetMaker) -> ();
receive_data_from_hotornot : (principal, nat64, vec Post) -> (Result_20);
request_airdrop : (principal, opt blob, nat, principal) -> (Result_21);
reset_ml_feed_cache : () -> (Result_22);
receive_reward_for_being_referred : () -> (Result_21);
receive_reward_for_referring : (ProofOfParticipation, principal) -> (
Result_21,
);
request_airdrop : (principal, opt blob, nat, principal) -> (Result_22);
reset_ml_feed_cache : () -> (Result_23);
return_cycles_to_user_index_canister : (opt nat) -> ();
save_snapshot_json : () -> (nat32);
send_creator_dao_stats_to_subnet_orchestrator : () -> (Result_23);
send_creator_dao_stats_to_subnet_orchestrator : () -> (Result_24);
set_controller_as_subnet_orchestrator : (principal) -> ();
settle_neurons_fund_participation : (
SettleNeuronsFundParticipationRequest,
) -> (SettleNeuronsFundParticipationResponse);
transfer_token_to_user_canister : (principal, principal, opt blob, nat) -> (
Result_26,
Result_27,
);
transfer_tokens_and_posts : (principal, principal) -> (Result_20);
update_last_access_time : () -> (Result_22);
update_last_access_time : () -> (Result_23);
update_last_canister_functionality_access_time : () -> ();
update_ml_feed_cache : (vec MLFeedCacheItem) -> (Result_22);
update_ml_feed_cache : (vec MLFeedCacheItem) -> (Result_23);
update_post_add_view_details : (nat64, PostViewDetailsFromFrontend) -> ();
update_post_as_ready_to_view : (nat64) -> ();
update_post_increment_share_count : (nat64) -> (nat64);
update_post_status : (nat64, PostStatus) -> ();
update_post_toggle_like_status_by_caller : (nat64) -> (bool);
update_profile_display_details : (UserProfileUpdateDetailsFromFrontend) -> (
Result_27,
Result_28,
);
update_profile_owner : (opt principal) -> (Result_28);
update_profile_owner : (opt principal) -> (Result_21);
update_profile_set_unique_username_once : (text) -> (Result_29);
update_profiles_i_follow_toggle_list_with_specified_profile : (
FolloweeArg,
) -> (Result_8);
update_profiles_that_follow_me_toggle_list_with_specified_profile : (
FollowerArg,
) -> (Result_8);
update_referrer_details : (UserCanisterDetails) -> (Result_22);
update_session_type : (SessionType) -> (Result_22);
update_success_history : (SuccessHistoryItemV1) -> (Result_22);
update_user_propensity : (float64) -> (Result_22);
update_watch_history : (WatchHistoryItem) -> (Result_22);
update_referrer_details : (UserCanisterDetails) -> (Result_23);
update_session_type : (SessionType) -> (Result_23);
update_success_history : (SuccessHistoryItemV1) -> (Result_23);
update_user_propensity : (float64) -> (Result_23);
update_watch_history : (WatchHistoryItem) -> (Result_23);
update_well_known_principal : (KnownPrincipalType, principal) -> ();
upgrade_creator_dao_governance_canisters : (blob) -> (Result_28);
upgrade_creator_dao_governance_canisters : (blob) -> (Result_21);
write_key_value_pair : (nat64, text, text) -> (Result_5);
write_multiple_key_value_pairs : (nat64, vec record { text; text }) -> (
Result_6,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ fn init_impl(init_args: IndividualUserTemplateInitArgs, data: &mut CanisterData)

data.version_details.version_number = init_args.upgrade_version_number.unwrap_or_default();
data.version_details.version = init_args.version;
if let Some(pop) = init_args.proof_of_participation {
data.proof_of_participation = Some(pop);
}
}

#[cfg(test)]
Expand Down Expand Up @@ -60,6 +63,7 @@ mod test {
"http://metrics-url.com/receive-metrics".to_string(),
),
version: String::from("v1.0.0"),
proof_of_participation: None,
};
let mut data = CanisterData::default();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use ciborium::de;
use ic_cdk::api::call::ArgDecoderConfig;
use ic_cdk_macros::post_upgrade;
use ic_stable_structures::Memory;
Expand Down Expand Up @@ -31,7 +30,7 @@ fn restore_data_from_stable_memory() {
heap_data.read(4, &mut canister_data_bytes);

let canister_data =
de::from_reader(&*canister_data_bytes).expect("Failed to deserialize heap data");
minicbor_serde::from_slice(&canister_data_bytes).expect("Failed to deserialize heap data");
CANISTER_DATA.with(|canister_data_ref_cell| {
*canister_data_ref_cell.borrow_mut() = canister_data;
});
Expand Down Expand Up @@ -66,6 +65,10 @@ fn save_upgrade_args_to_memory() {
.configuration
.url_to_send_canister_metrics_to = Some(url_to_send_canister_metrics_to);
}

if let Some(pop) = upgrade_args.proof_of_participation {
canister_data_ref_cell.proof_of_participation = Some(pop);
}
});
}

Expand All @@ -76,4 +79,4 @@ fn migrate_excessive_tokens(){
canister_data_ref_cell.my_token_balance.utility_token_balance = 1000;
}
});
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use ciborium::ser;
use ic_cdk::api::stable;
use ic_cdk_macros::pre_upgrade;
use ic_stable_structures::writer::Writer;
Expand All @@ -9,9 +8,8 @@ use crate::CANISTER_DATA;

#[pre_upgrade]
fn pre_upgrade() {
let mut state_bytes = vec![];
CANISTER_DATA.with(|canister_data_ref_cell| {
ser::into_writer(&*canister_data_ref_cell.borrow(), &mut state_bytes)
let state_bytes = CANISTER_DATA.with(|canister_data_ref_cell| {
minicbor_serde::to_vec(&*canister_data_ref_cell.borrow())
})
.expect("failed to encode state");

Expand Down
1 change: 1 addition & 0 deletions src/canister/individual_user_template/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ pub mod token;
pub mod well_known_principal;
pub mod cdao;
pub mod device_id_management;
pub mod referral;
94 changes: 94 additions & 0 deletions src/canister/individual_user_template/src/api/referral/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use candid::Principal;
use ic_cdk::{notify, update};
use shared_utils::{canister_specific::individual_user_template::types::session::SessionType, common::{participant_crypto::ProofOfParticipation, types::utility_token::token_event::{MintEvent, TokenEvent}, utils::system_time}};

use crate::{api::canister_management::update_last_access_time::update_last_canister_functionality_access_time, CANISTER_DATA, util::cycles::notify_to_recharge_canister};

pub(crate) fn coyn_token_reward_for_referral(referrer: Principal, referree: Principal) {
let current_time = system_time::get_current_system_time_from_ic();

CANISTER_DATA.with_borrow_mut(|cdata| {
let my_token_balance = &mut cdata.my_token_balance;

let referral_reward_amount = TokenEvent::get_token_amount_for_token_event(&TokenEvent::Mint {
amount: 0,
details: MintEvent::Referral {
referee_user_principal_id: referree,
referrer_user_principal_id: referrer,
},
timestamp: current_time,
});

my_token_balance.handle_token_event(TokenEvent::Mint {
amount: referral_reward_amount,
details: MintEvent::Referral {
referrer_user_principal_id: referrer,
referee_user_principal_id: referree,
},
timestamp: current_time,
});
})
}

#[update]
pub async fn receive_reward_for_being_referred() -> Result<(), String> {
notify_to_recharge_canister();
let (pop, user_principal, referrer_details, session_type, has_parent) = CANISTER_DATA.with_borrow(|cdata| {
let profile = &cdata.profile;
(
cdata.proof_of_participation.clone(),
profile.principal_id,
profile.referrer_details.clone(),
cdata.session_type,
cdata.airdrop.parent.is_some()
)
});

let Some(pop) = pop else {
return Err("method is not available right now".into());
};

let Some(user_principal) = user_principal else {
return Err("canister is not ready".into());
};

let Some(referrer_details) = referrer_details else {
return Err("no referrer details found".into());
};

if session_type != Some(SessionType::RegisteredSession) {
return Err("user not signed up".into());
}

if has_parent {
return Err("User has already claimed the reward".into());
}

update_last_canister_functionality_access_time();

coyn_token_reward_for_referral(referrer_details.profile_owner, user_principal);

// Rollback if the notification fails
notify(
referrer_details.user_canister_id,
"receive_reward_for_referring",
(pop, user_principal)
).map_err(|_| "failed to reward referrer".to_string())
.unwrap();

Ok(())
}

#[update]
pub async fn receive_reward_for_referring(pop: ProofOfParticipation, referree_principal: Principal) -> Result<(), String> {
notify_to_recharge_canister();
pop.verify_caller_is_participant(&CANISTER_DATA).await?;

let Some(profile_owner) = CANISTER_DATA.with_borrow(|cdata| cdata.profile.principal_id) else {
return Err("canister is not ready".into());
};

coyn_token_reward_for_referral(profile_owner, referree_principal);

Ok(())
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
use crate::{
api::canister_management::update_last_access_time::update_last_canister_functionality_access_time,
api::{canister_management::update_last_access_time::update_last_canister_functionality_access_time, referral::coyn_token_reward_for_referral},
util::cycles::notify_to_recharge_canister, CANISTER_DATA,
};
use candid::Principal;
use ic_cdk_macros::update;
use shared_utils::common::{
types::{
known_principal::KnownPrincipalType,
utility_token::token_event::{MintEvent, TokenEvent},
},
utils::system_time,
};
use shared_utils::common::types::known_principal::KnownPrincipalType;

#[deprecated = "use new methods in crate::api::referral"]
#[update]
fn get_rewarded_for_referral(referrer: Principal, referree: Principal) {
// * access control
Expand All @@ -32,28 +27,5 @@ fn get_rewarded_for_referral(referrer: Principal, referree: Principal) {

update_last_canister_functionality_access_time();

let current_time = system_time::get_current_system_time_from_ic();

CANISTER_DATA.with(|canister_data_ref_cell| {
let my_token_balance = &mut canister_data_ref_cell.borrow_mut().my_token_balance;

let referral_reward_amount =
TokenEvent::get_token_amount_for_token_event(&TokenEvent::Mint {
amount: 0,
details: MintEvent::Referral {
referrer_user_principal_id: referrer,
referee_user_principal_id: referree,
},
timestamp: current_time,
});

my_token_balance.handle_token_event(TokenEvent::Mint {
amount: referral_reward_amount,
details: MintEvent::Referral {
referrer_user_principal_id: referrer,
referee_user_principal_id: referree,
},
timestamp: current_time,
});
});
coyn_token_reward_for_referral(referrer, referree);
}
Loading