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

Add support for P2P trades #4897

Merged
merged 29 commits into from
Dec 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8e4683b
Support P2P trades WIP
hpeebles Nov 30, 2023
169b37f
Merge branch 'master' into p2p
hpeebles Dec 5, 2023
58be076
Fixes
hpeebles Dec 5, 2023
64263ef
Merge branch 'master' into p2p
hpeebles Dec 12, 2023
4769f84
Call into Escrow canister to set up p2p trade
hpeebles Dec 12, 2023
fff8396
Merge branch 'master' into p2p
hpeebles Dec 12, 2023
83a74a1
Notify Escrow canister of deposit
hpeebles Dec 12, 2023
fd0b9f8
More
hpeebles Dec 13, 2023
32e5924
Merge branch 'master' into p2p
hpeebles Dec 13, 2023
afc48d0
More
hpeebles Dec 13, 2023
1dd3479
Add `escrow_canister_id` to GroupIndex/LocalGroupIndex/Group
hpeebles Dec 13, 2023
b6ab584
clippy
hpeebles Dec 13, 2023
20e1c34
Add test
hpeebles Dec 13, 2023
1885e82
Merge branch 'master' into p2p
hpeebles Dec 13, 2023
d64255a
candid
hpeebles Dec 13, 2023
defd4af
Fix
hpeebles Dec 13, 2023
d2459f6
Use msgpack for c2c call
hpeebles Dec 13, 2023
a3dd2ec
Fix ledger canister Id
hpeebles Dec 13, 2023
9539fba
Fixes
hpeebles Dec 14, 2023
1b48ed7
Fixes
hpeebles Dec 14, 2023
ad2867f
Add 10 minutes to expiry in Escrow canister
hpeebles Dec 14, 2023
f91d203
Update CHANGELOGs
hpeebles Dec 14, 2023
2588f53
Update CHANGELOGs
hpeebles Dec 14, 2023
b7e1563
Implement P2P trades in communities
hpeebles Dec 14, 2023
73a3819
candid
hpeebles Dec 14, 2023
9c547b6
Only update status after notifying Escrow canister
hpeebles Dec 14, 2023
f85d5cc
Check status at end of test
hpeebles Dec 14, 2023
9372fd1
Merge branch 'master' into p2p
hpeebles Dec 14, 2023
7184540
clippy
hpeebles Dec 14, 2023
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
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ members = [
"backend/canisters/cycles_dispenser/api",
"backend/canisters/cycles_dispenser/impl",
"backend/canisters/escrow/api",
"backend/canisters/escrow/c2c_client",
"backend/canisters/escrow/impl",
"backend/canisters/group/api",
"backend/canisters/group/c2c_client",
Expand Down
2 changes: 2 additions & 0 deletions backend/canister_installer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ async fn install_service_canisters_impl(
proposals_bot_canister_id: canister_ids.proposals_bot,
storage_index_canister_id: canister_ids.storage_index,
cycles_dispenser_canister_id: canister_ids.cycles_dispenser,
escrow_canister_id: canister_ids.escrow,
nns_governance_canister_id: canister_ids.nns_governance,
internet_identity_canister_id: canister_ids.nns_internet_identity,
wasm_version: version,
Expand All @@ -79,6 +80,7 @@ async fn install_service_canisters_impl(
user_index_canister_id: canister_ids.user_index,
cycles_dispenser_canister_id: canister_ids.cycles_dispenser,
proposals_bot_user_id: canister_ids.proposals_bot.into(),
escrow_canister_id: canister_ids.escrow,
wasm_version: version,
test_mode,
};
Expand Down
1 change: 1 addition & 0 deletions backend/canisters/community/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added

- Support getting batches of summary updates via LocalUserIndex ([#4983](https://github.com/open-chat-labs/open-chat/pull/4983))
- Add support for P2P trades ([#4897](https://github.com/open-chat-labs/open-chat/pull/4897))

### Changed

Expand Down
23 changes: 23 additions & 0 deletions backend/canisters/community/api/can.did
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,28 @@ type ThreadPreviewsResponse = variant {
ReplicaNotUpToDate : TimestampMillis;
};

type AcceptP2PTradeOfferArgs = record {
channel_id : ChannelId;
thread_root_message_index : opt MessageIndex;
message_index : MessageIndex;
};

type AcceptP2PTradeOfferResponse = variant {
Success;
InsufficientFunds;
AlreadyAccepted;
AlreadyCompleted;
OfferExpired;
OfferCancelled;
OfferNotFound;
ChannelNotFound;
UserNotInCommunity;
UserNotInChannel;
UserSuspended;
ChatFrozen;
InternalError : text;
};

type AddMembersToChannelArgs = record {
channel_id : ChannelId;
user_ids : vec UserId;
Expand Down Expand Up @@ -963,6 +985,7 @@ service : {
summary_updates : (SummaryUpdatesArgs) -> (SummaryUpdatesResponse) query;
thread_previews : (ThreadPreviewsArgs) -> (ThreadPreviewsResponse) query;

accept_p2p_trade_offer : (AcceptP2PTradeOfferArgs) -> (AcceptP2PTradeOfferResponse);
add_members_to_channel : (AddMembersToChannelArgs) -> (AddMembersToChannelResponse);
add_reaction : (AddReactionArgs) -> (AddReactionResponse);
block_user : (BlockUserArgs) -> (BlockUserResponse);
Expand Down
1 change: 1 addition & 0 deletions backend/canisters/community/api/src/lifecycle/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub struct Args {
pub local_group_index_canister_id: CanisterId,
pub notifications_canister_id: CanisterId,
pub proposals_bot_user_id: UserId,
pub escrow_canister_id: CanisterId,
pub gate: Option<AccessGate>,
pub default_channels: Vec<String>,
pub default_channel_rules: Option<Rules>,
Expand Down
1 change: 1 addition & 0 deletions backend/canisters/community/api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ fn main() {
generate_candid_method!(community, summary_updates, query);
generate_candid_method!(community, thread_previews, query);

generate_candid_method!(community, accept_p2p_trade_offer, update);
generate_candid_method!(community, add_members_to_channel, update);
generate_candid_method!(community, add_reaction, update);
generate_candid_method!(community, block_user, update);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use candid::CandidType;
use serde::{Deserialize, Serialize};
use types::{ChannelId, MessageIndex};

#[derive(CandidType, Serialize, Deserialize, Debug)]
pub struct Args {
pub channel_id: ChannelId,
pub thread_root_message_index: Option<MessageIndex>,
pub message_index: MessageIndex,
}

#[derive(CandidType, Serialize, Deserialize, Debug)]
pub enum Response {
Success,
InsufficientFunds,
AlreadyAccepted,
AlreadyCompleted,
OfferExpired,
OfferCancelled,
OfferNotFound,
ChannelNotFound,
UserNotInCommunity,
UserNotInChannel,
UserSuspended,
ChatFrozen,
InternalError(String),
}
1 change: 1 addition & 0 deletions backend/canisters/community/api/src/updates/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod accept_p2p_trade_offer;
pub mod add_members_to_channel;
pub mod add_reaction;
pub mod block_user;
Expand Down
2 changes: 2 additions & 0 deletions backend/canisters/community/impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ canister_timer_jobs = { path = "../../../libraries/canister_timer_jobs" }
canister_tracing_macros = { path = "../../../libraries/canister_tracing_macros" }
chat_events = { path = "../../../libraries/chat_events" }
community_canister = { path = "../api" }
escrow_canister = { path = "../../escrow/api" }
escrow_canister_c2c_client = { path = "../../escrow/c2c_client" }
fire_and_forget_handler = { path = "../../../libraries/fire_and_forget_handler" }
futures = { workspace = true }
gated_groups = { path = "../../../libraries/gated_groups" }
Expand Down
10 changes: 10 additions & 0 deletions backend/canisters/community/impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ impl RuntimeState {
local_group_index: self.data.local_group_index_canister_id,
notifications: self.data.notifications_canister_id,
proposals_bot: self.data.proposals_bot_user_id.into(),
escrow: self.data.escrow_canister_id,
icp_ledger: Cryptocurrency::InternetComputer.ledger_canister_id().unwrap(),
},
}
Expand Down Expand Up @@ -273,6 +274,8 @@ struct Data {
local_group_index_canister_id: CanisterId,
notifications_canister_id: CanisterId,
proposals_bot_user_id: UserId,
#[serde(default = "escrow_canister_id")]
escrow_canister_id: CanisterId,
date_created: TimestampMillis,
members: CommunityMembers,
channels: Channels,
Expand All @@ -295,6 +298,10 @@ struct Data {
pub total_payment_receipts: PaymentReceipts,
}

fn escrow_canister_id() -> CanisterId {
CanisterId::from_text("s4yi7-yiaaa-aaaar-qacpq-cai").unwrap()
megrogan marked this conversation as resolved.
Show resolved Hide resolved
}

impl Data {
#[allow(clippy::too_many_arguments)]
fn new(
Expand All @@ -314,6 +321,7 @@ impl Data {
local_group_index_canister_id: CanisterId,
notifications_canister_id: CanisterId,
proposals_bot_user_id: UserId,
escrow_canister_id: CanisterId,
gate: Option<AccessGate>,
default_channels: Vec<(ChannelId, String)>,
default_channel_rules: Option<Rules>,
Expand Down Expand Up @@ -341,6 +349,7 @@ impl Data {
local_group_index_canister_id,
notifications_canister_id,
proposals_bot_user_id,
escrow_canister_id,
date_created: now,
members,
channels,
Expand Down Expand Up @@ -469,5 +478,6 @@ pub struct CanisterIds {
pub local_group_index: CanisterId,
pub notifications: CanisterId,
pub proposals_bot: CanisterId,
pub escrow: CanisterId,
pub icp_ledger: CanisterId,
}
1 change: 1 addition & 0 deletions backend/canisters/community/impl/src/lifecycle/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ fn init(args: Args) {
args.local_group_index_canister_id,
args.notifications_canister_id,
args.proposals_bot_user_id,
args.escrow_canister_id,
args.gate,
default_channels,
args.default_channel_rules,
Expand Down
100 changes: 98 additions & 2 deletions backend/canisters/community/impl/src/timer_job_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use chat_events::MessageContentInternal;
use ledger_utils::process_transaction;
use serde::{Deserialize, Serialize};
use tracing::error;
use types::{BlobReference, CanisterId, ChannelId, ChatId, MessageId, MessageIndex, PendingCryptoTransaction};
use types::{BlobReference, CanisterId, ChannelId, ChatId, MessageId, MessageIndex, PendingCryptoTransaction, UserId};
use utils::consts::MEMO_PRIZE_REFUND;
use utils::time::MINUTE_IN_MS;
use utils::time::{MINUTE_IN_MS, SECOND_IN_MS};

#[derive(Serialize, Deserialize, Clone)]
pub enum TimerJob {
Expand All @@ -21,6 +21,7 @@ pub enum TimerJob {
MarkGroupImportComplete(MarkGroupImportCompleteJob),
RefundPrize(RefundPrizeJob),
MakeTransfer(MakeTransferJob),
NotifyEscrowCanisterOfDeposit(NotifyEscrowCanisterOfDepositJob),
}

#[derive(Serialize, Deserialize, Clone)]
Expand Down Expand Up @@ -75,6 +76,39 @@ pub struct MakeTransferJob {
pub pending_transaction: PendingCryptoTransaction,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct NotifyEscrowCanisterOfDepositJob {
pub user_id: UserId,
pub offer_id: u32,
pub channel_id: ChannelId,
pub thread_root_message_index: Option<MessageIndex>,
pub message_index: MessageIndex,
pub transaction_index: u64,
pub attempt: u32,
}

impl NotifyEscrowCanisterOfDepositJob {
pub fn run(
user_id: UserId,
offer_id: u32,
channel_id: ChannelId,
thread_root_message_index: Option<MessageIndex>,
message_index: MessageIndex,
transaction_index: u64,
) {
let job = NotifyEscrowCanisterOfDepositJob {
user_id,
offer_id,
channel_id,
thread_root_message_index,
message_index,
transaction_index,
attempt: 0,
};
job.execute();
}
}

impl Job for TimerJob {
fn execute(self) {
match self {
Expand All @@ -87,6 +121,7 @@ impl Job for TimerJob {
TimerJob::MarkGroupImportComplete(job) => job.execute(),
TimerJob::RefundPrize(job) => job.execute(),
TimerJob::MakeTransfer(job) => job.execute(),
TimerJob::NotifyEscrowCanisterOfDeposit(job) => job.execute(),
}
}
}
Expand Down Expand Up @@ -239,3 +274,64 @@ impl Job for MakeTransferJob {
}
}
}

impl Job for NotifyEscrowCanisterOfDepositJob {
fn execute(self) {
let escrow_canister_id = read_state(|state| state.data.escrow_canister_id);

ic_cdk::spawn(async move {
match escrow_canister_c2c_client::notify_deposit(
escrow_canister_id,
&escrow_canister::notify_deposit::Args {
offer_id: self.offer_id,
user_id: Some(self.user_id),
},
)
.await
{
Ok(escrow_canister::notify_deposit::Response::Success(_)) => {
mutate_state(|state| {
if let Some(channel) = state.data.channels.get_mut(&self.channel_id) {
channel.chat.events.complete_p2p_trade(
self.user_id,
self.thread_root_message_index,
self.message_index,
self.transaction_index,
state.env.now(),
);
}
});
}
Ok(escrow_canister::notify_deposit::Response::OfferExpired) => mutate_state(|state| {
if let Some(channel) = state.data.channels.get_mut(&self.channel_id) {
channel.chat.events.unreserve_p2p_trade(
self.user_id,
self.thread_root_message_index,
self.message_index,
state.env.now(),
);
}
}),
Ok(escrow_canister::notify_deposit::Response::InternalError(_)) | Err(_) if self.attempt < 20 => {
mutate_state(|state| {
let now = state.env.now();
state.data.timer_jobs.enqueue_job(
TimerJob::NotifyEscrowCanisterOfDeposit(NotifyEscrowCanisterOfDepositJob {
offer_id: self.offer_id,
user_id: self.user_id,
channel_id: self.channel_id,
thread_root_message_index: self.thread_root_message_index,
message_index: self.message_index,
transaction_index: self.transaction_index,
attempt: self.attempt + 1,
}),
now + 10 * SECOND_IN_MS,
now,
);
});
}
response => error!(?response, "Failed to notify escrow canister of deposit"),
};
})
}
}
Loading
Loading