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

P2P swap FE #5181

Merged
merged 47 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
0ce1cb3
Offer P2P trades FE WIP
megrogan Jan 10, 2024
52959b8
Wire-up p2pTrade permission + prevent thread prize
megrogan Jan 10, 2024
3c6847c
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 11, 2024
62ecc83
Use messageId instead of messageIndex
megrogan Jan 11, 2024
3eefad0
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 15, 2024
829d6f0
codegen
megrogan Jan 15, 2024
7b527be
Wire-up changes
megrogan Jan 15, 2024
e4f065f
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 15, 2024
6ab1284
WIP
megrogan Jan 15, 2024
9a3ec0d
Merge branch 'master' into p2p-swap
megrogan Jan 15, 2024
98425e6
Remove `local_user_index_canister_id` from updates
megrogan Jan 15, 2024
92fcfa1
Fixes
megrogan Jan 16, 2024
18397dc
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 16, 2024
182cff8
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 16, 2024
0d77faf
codegen again
megrogan Jan 16, 2024
c0f1892
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 17, 2024
7cd9498
Wire up based on latest codegen
megrogan Jan 17, 2024
340dea8
codegen
megrogan Jan 17, 2024
02a48c9
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 17, 2024
7740c81
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 17, 2024
b4a3ae0
Latest codegen
megrogan Jan 17, 2024
117de90
wire up cancel
megrogan Jan 17, 2024
9cbe57d
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 17, 2024
347c574
Handle send message failures better
megrogan Jan 18, 2024
06542fb
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 18, 2024
d13a436
Latest codegen
megrogan Jan 18, 2024
876fa7e
Add missing candid for `cancel_p2p_swap`
megrogan Jan 19, 2024
507b676
Various stuff
megrogan Jan 19, 2024
974fa1f
Missing candid part2
megrogan Jan 19, 2024
116b92f
Codegen again
megrogan Jan 19, 2024
61508aa
Wire up cancel for groups and communities
megrogan Jan 19, 2024
e2ea4d0
More stuff
megrogan Jan 19, 2024
2d5ce48
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 19, 2024
a0fd509
Finishing touches
megrogan Jan 22, 2024
ca8b0d5
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 22, 2024
bcaec87
sync_lang
megrogan Jan 22, 2024
09d1936
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 22, 2024
cb8f7c9
Remove some commented out code
megrogan Jan 22, 2024
062be86
Address some PR comments
megrogan Jan 22, 2024
682c524
Support creating p2p swap messages in threads
megrogan Jan 23, 2024
b4f121f
Merge branch 'master' into p2p-swap
megrogan Jan 23, 2024
fb92fa8
Address more PR comments
megrogan Jan 23, 2024
997c4f5
Merge branch 'p2p-swap' of github.com:dfinity-lab/open-chat into p2p-…
megrogan Jan 23, 2024
4d531a1
Merge remote-tracking branch 'origin/master' into p2p-swap
megrogan Jan 23, 2024
cf38c2d
Merge branch 'master' into p2p-swap
megrogan Jan 23, 2024
4882139
Handle all accept/cancel error types
megrogan Jan 23, 2024
e41d3af
Merge branch 'p2p-swap' of github.com:dfinity-lab/open-chat into p2p-…
megrogan Jan 23, 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
17 changes: 17 additions & 0 deletions backend/canisters/community/api/can.did
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,22 @@ type AcceptP2PSwapResponse = variant {
InternalError : text;
};

type CancelP2PSwapArgs = record {
channel_id : ChannelId;
thread_root_message_index : opt MessageIndex;
message_id : MessageId;
};

type CancelP2PSwapResponse = variant {
Success;
StatusError : SwapStatusError;
SwapNotFound;
ChannelNotFound;
UserNotInCommunity;
UserNotInChannel;
ChatFrozen;
};

type AddMembersToChannelArgs = record {
channel_id : ChannelId;
user_ids : vec UserId;
Expand Down Expand Up @@ -992,6 +1008,7 @@ service : {
add_members_to_channel : (AddMembersToChannelArgs) -> (AddMembersToChannelResponse);
add_reaction : (AddReactionArgs) -> (AddReactionResponse);
block_user : (BlockUserArgs) -> (BlockUserResponse);
cancel_p2p_swap : (CancelP2PSwapArgs) -> (CancelP2PSwapResponse);
change_channel_role : (ChangeChannelRoleArgs) -> (ChangeChannelRoleResponse);
change_role : (ChangeRoleArgs) -> (ChangeRoleResponse);
claim_prize : (ClaimPrizeArgs) -> (ClaimPrizeResponse);
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 @@ -27,6 +27,7 @@ fn main() {
generate_candid_method!(community, add_members_to_channel, update);
generate_candid_method!(community, add_reaction, update);
generate_candid_method!(community, block_user, update);
generate_candid_method!(community, cancel_p2p_swap, update);
generate_candid_method!(community, change_channel_role, update);
generate_candid_method!(community, change_role, update);
generate_candid_method!(community, claim_prize, update);
Expand Down
14 changes: 14 additions & 0 deletions backend/canisters/group/api/can.did
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,19 @@ type AcceptP2PSwapResponse = variant {
InternalError : text;
};

type CancelP2PSwapArgs = record {
thread_root_message_index : opt MessageIndex;
message_id : MessageId;
};

type CancelP2PSwapResponse = variant {
Success;
StatusError : SwapStatusError;
SwapNotFound;
UserNotInGroup;
ChatFrozen;
};

type AddReactionArgs = record {
thread_root_message_index : opt MessageIndex;
message_id : MessageId;
Expand Down Expand Up @@ -645,6 +658,7 @@ service : {
undelete_messages : (UndeleteMessagesArgs) -> (UndeleteMessagesResponse);
register_poll_vote : (RegisterPollVoteArgs) -> (RegisterPollVoteResponse);
accept_p2p_swap : (AcceptP2PSwapArgs) -> (AcceptP2PSwapResponse);
cancel_p2p_swap : (CancelP2PSwapArgs) -> (CancelP2PSwapResponse);
add_reaction : (AddReactionArgs) -> (AddReactionResponse);
remove_reaction : (RemoveReactionArgs) -> (RemoveReactionResponse);
report_message : (ReportMessageArgs) -> (ReportMessageResponse);
Expand Down
1 change: 1 addition & 0 deletions backend/canisters/group/api/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ fn main() {
generate_candid_method!(group, accept_p2p_swap, update);
generate_candid_method!(group, add_reaction, update);
generate_candid_method!(group, block_user, update);
generate_candid_method!(group, cancel_p2p_swap, update);
generate_candid_method!(group, change_role, update);
generate_candid_method!(group, claim_prize, update);
generate_candid_method!(group, convert_into_community, update);
Expand Down
140 changes: 140 additions & 0 deletions frontend/app/src/components/home/AcceptP2PSwapModal.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<script lang="ts">
import Button from "../Button.svelte";
import ButtonGroup from "../ButtonGroup.svelte";
import type { OpenChat } from "openchat-client";
import Overlay from "../Overlay.svelte";
import AccountInfo from "./AccountInfo.svelte";
import ModalContent from "../ModalContent.svelte";
import { _ } from "svelte-i18n";
import { createEventDispatcher, getContext } from "svelte";
import { mobileWidth } from "../../stores/screenDimensions";
import BalanceWithRefresh from "./BalanceWithRefresh.svelte";
import { i18nKey } from "../../i18n/i18n";
import Translatable from "../Translatable.svelte";

const client = getContext<OpenChat>("client");
const dispatch = createEventDispatcher();

export let ledger0: string;
export let ledger1: string;
export let amount0: bigint;
export let amount1: bigint;

let refreshing = false;
let error: string | undefined = undefined;
let balanceWithRefresh: BalanceWithRefresh;

$: user = client.user;
$: cryptoBalanceStore = client.cryptoBalance;
$: cryptoBalance = $cryptoBalanceStore[ledger1] ?? BigInt(0);
$: cryptoLookup = client.enhancedCryptoLookup;
$: tokenDetails0 = $cryptoLookup[ledger0];
$: tokenDetails1 = $cryptoLookup[ledger1];
$: symbol0 = tokenDetails0.symbol;
$: symbol1 = tokenDetails1.symbol;
$: howToBuyUrl = tokenDetails1.howToBuyUrl;
$: transferFees = BigInt(2) * tokenDetails1.transferFee;
$: valid = error === undefined && !insufficient;
$: insufficient = cryptoBalance <= amount1 + transferFees;
$: amount0Text = client.formatTokens(amount0, tokenDetails0.decimals);
$: amount1Text = client.formatTokens(amount1 + transferFees, tokenDetails1.decimals);

function reset() {
balanceWithRefresh.refresh();
}

function cancel() {
dispatch("close");
}

function accept() {
dispatch("accept");
}
</script>

<Overlay dismissible>
<ModalContent>
<span class="header" slot="header">
<div>
<Translatable
resourceKey={i18nKey(
insufficient ? "p2pSwap.insufficientBalance" : "areYouSure",
)} />
</div>
<BalanceWithRefresh
bind:this={balanceWithRefresh}
ledger={ledger1}
value={cryptoBalance}
label={i18nKey("p2pSwap.tokenBalance", { token: symbol1 })}
bold />
</span>
<form slot="body">
<div class="body" class:insufficient>
{#if insufficient}
<p class="info">
<Translatable
resourceKey={i18nKey("p2pSwap.insufficientBalanceMessage", {
amount: amount1Text,
token: symbol1,
})} />
</p>
<AccountInfo ledger={ledger1} user={$user} />
<p><Translatable resourceKey={i18nKey("tokenTransfer.makeDeposit")} /></p>
<a rel="noreferrer" class="how-to" href={howToBuyUrl} target="_blank">
<Translatable resourceKey={i18nKey("howToBuyToken", { token: symbol1 })} />
</a>
{:else}
<Translatable
resourceKey={i18nKey("p2pSwap.confirmAccept", {
amount: amount1Text,
token: symbol1,
amountOther: amount0Text,
tokenOther: symbol0,
})} />
{/if}
</div>
</form>
<span slot="footer">
<ButtonGroup>
<Button small={!$mobileWidth} tiny={$mobileWidth} secondary on:click={cancel}
><Translatable resourceKey={i18nKey("cancel")} /></Button>
{#if insufficient}
<Button
small={!$mobileWidth}
disabled={refreshing}
loading={refreshing}
tiny={$mobileWidth}
on:click={reset}><Translatable resourceKey={i18nKey("refresh")} /></Button>
{:else}
<Button
small={!$mobileWidth}
disabled={!valid}
tiny={$mobileWidth}
on:click={accept}><Translatable resourceKey={i18nKey("yes")} /></Button>
{/if}
</ButtonGroup>
</span>
</ModalContent>
</Overlay>

<style lang="scss">
.header {
display: flex;
align-items: center;
justify-content: space-between;
gap: $sp2;
}

.body {
transition: background-color 100ms ease-in-out;
@include font(book, normal, fs-100, 28);
}

.how-to {
margin-top: $sp4;
}

.info {
margin-bottom: $sp3;
}
</style>
10 changes: 7 additions & 3 deletions frontend/app/src/components/home/ChatMessage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@
let multiUserChat = chatType === "group_chat" || chatType === "channel";
let showEmojiPicker = false;
let debug = false;
let crypto = msg.content.kind === "crypto_content" || msg.content.kind === "prize_content";
let crypto =
msg.content.kind === "crypto_content" ||
msg.content.kind === "prize_content" ||
msg.content.kind === "p2p_swap_content";
let poll = msg.content.kind === "poll_content";
let canRevealDeleted = false;
let showRemindMe = false;
Expand Down Expand Up @@ -202,7 +205,7 @@
messageIndex: msg.messageIndex,
edited: msg.edited,
isThreadRoot: msg.thread !== undefined,
sourceContext: { chatId, threadRootMessageIndex: threadRootMessage?.messageIndex },
sourceContext: messageContext,
};
}

Expand Down Expand Up @@ -528,10 +531,11 @@
{readonly}
{fill}
{me}
{chatId}
{messageContext}
{collapsed}
{undeleting}
{intersecting}
{failed}
messageIndex={msg.messageIndex}
messageId={msg.messageId}
myUserId={user.userId}
Expand Down
22 changes: 16 additions & 6 deletions frontend/app/src/components/home/ChatMessageContent.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
import MessageReminderContent from "./MessageReminderContent.svelte";
import MessageReminderCreatedContent from "./MessageReminderCreatedContent.svelte";
import ProposalContent from "./proposals/ProposalContent.svelte";
import type { ChatIdentifier, MessageContent } from "openchat-client";
import PrizeContentInitial from "./PrizeContentInitial.svelte";
import type { MessageContent, MessageContext } from "openchat-client";
import { _ } from "svelte-i18n";
import MessageContentInitial from "./MessageContentInitial.svelte";
import P2PSwapContent from "./P2PSwapContent.svelte";
import { i18nKey } from "../../i18n/i18n";

export let content: MessageContent;
export let me: boolean = false;
Expand All @@ -34,11 +37,12 @@
export let myUserId: string | undefined;
export let messageId: bigint;
export let edited: boolean;
export let chatId: ChatIdentifier;
export let messageContext: MessageContext;
export let messageIndex: number;
export let collapsed = false;
export let undeleting: boolean = false;
export let intersecting: boolean;
export let failed: boolean;
</script>

{#if content.kind === "text_content"}
Expand All @@ -60,9 +64,15 @@
{:else if content.kind === "placeholder_content"}
<PlaceholderContent />
{:else if content.kind === "prize_content_initial"}
<PrizeContentInitial {me} />
<MessageContentInitial text={i18nKey("prizes.creatingYourPrizeMessage")} {failed} />
{:else if content.kind === "p2p_swap_content_initial"}
<MessageContentInitial
text={i18nKey(failed ? "p2pSwap.failedToCreateMessage" : "p2pSwap.creatingYourMessage")}
{failed} />
{:else if content.kind === "prize_content"}
<PrizeContent on:upgrade {chatId} {messageId} {content} {me} />
<PrizeContent on:upgrade chatId={messageContext.chatId} {messageId} {content} {me} />
{:else if content.kind === "p2p_swap_content"}
<P2PSwapContent {messageContext} {messageId} {content} {me} {reply} {pinned} />
{:else if content.kind === "prize_winner_content"}
<PrizeWinnerContent on:goToMessageIndex {content} />
{:else if content.kind === "poll_content"}
Expand All @@ -72,7 +82,7 @@
{:else if content.kind === "proposal_content"}
<ProposalContent
{content}
{chatId}
chatId={messageContext.chatId}
{messageIndex}
{messageId}
{collapsed}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
let balanceWithRefresh: BalanceWithRefresh;
let receiver: UserSummary | undefined = undefined;
let validAmount: boolean = false;
$: cryptoLookup = client.cryptoLookup;
$: cryptoLookup = client.enhancedCryptoLookup;
$: tokenDetails = $cryptoLookup[ledger];
$: symbol = tokenDetails.symbol;
$: howToBuyUrl = tokenDetails.howToBuyUrl;
Expand Down
14 changes: 14 additions & 0 deletions frontend/app/src/components/home/CurrentChat.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import { rightPanelHistory } from "../../stores/rightPanel";
import { mobileWidth } from "../../stores/screenDimensions";
import PrizeContentBuilder from "./PrizeContentBuilder.svelte";
import P2PSwapContentBuilder from "./P2PSwapContentBuilder.svelte";
import AreYouSure from "../AreYouSure.svelte";
import { i18nKey } from "../../i18n/i18n";

Expand All @@ -53,6 +54,7 @@
let creatingPoll = false;
let creatingCryptoTransfer: { ledger: string; amount: bigint } | undefined = undefined;
let creatingPrizeMessage = false;
let creatingP2PSwapMessage = false;
let selectingGif = false;
let buildingMeme = false;
let pollBuilder: PollBuilder;
Expand Down Expand Up @@ -154,6 +156,10 @@
creatingPrizeMessage = true;
}

function createP2PSwapMessage() {
creatingP2PSwapMessage = true;
}

function fileSelected(ev: CustomEvent<AttachmentContent>) {
draftMessagesStore.setAttachment({ chatId: chat.id }, ev.detail);
}
Expand Down Expand Up @@ -298,6 +304,13 @@
on:close={() => (creatingPrizeMessage = false)} />
{/if}

{#if creatingP2PSwapMessage}
<P2PSwapContentBuilder
fromLedger={$lastCryptoSent ?? LEDGER_CANISTER_ICP}
on:sendMessageWithContent
on:close={() => (creatingP2PSwapMessage = false)} />
{/if}

<GiphySelector on:sendMessageWithContent bind:this={giphySelector} bind:open={selectingGif} />

<MemeBuilder on:sendMessageWithContent bind:this={memeBuilder} bind:open={buildingMeme} />
Expand Down Expand Up @@ -380,6 +393,7 @@
on:makeMeme={makeMeme}
on:tokenTransfer={tokenTransfer}
on:createPrizeMessage={createPrizeMessage}
on:createP2PSwapMessage={createP2PSwapMessage}
on:searchChat={searchChat}
on:createPoll={createPoll} />
{/if}
Expand Down
Loading
Loading