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

Gifting #421

Merged
merged 5 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
7 changes: 6 additions & 1 deletion src/i18n/en/translations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -465,13 +465,16 @@ export default {
already_claimed: "This gift has already been claimed",
sender_is_poor:
"The sender doesn't have enough balance to pay this gift.",
sender_timed_out:
"Gift payment timed out. The sender may be offline, or this gift has already been claimed.",
sender_generic_error: "Sender sent error: {{error}}",
receive_header: "You've been gifted some sats!",
receive_description:
"You must be pretty special. To claim your money just hit the big button. Funds will be added to your balance the next time your gifter is online.",
"You must be pretty special. To claim your money just hit the big button. Funds will be added to this wallet the next time your gifter is online.",
receive_claimed:
"Gift claimed! You should see the gift hit your balance shortly.",
receive_cta: "Claim Gift",
receive_try_again: "Try Again",
send_header: "Create Gift",
send_explainer:
"Give the gift of sats. Create a Mutiny gift URL that can be claimed by anyone with a web browser.",
Expand All @@ -489,6 +492,8 @@ export default {
send_delete_button: "Delete Gift",
send_delete_confirm:
"Are you sure you want to delete this gift? Is this your rugpull moment?",
send_tip:
"Your copy of Mutiny Wallet needs to be open for the gift to be redeemed.",
need_plus:
"Upgrade to Mutiny+ to enable gifting. Gifting allows you to create a Mutiny gift URL that can be claimed by anyone with a web browser."
}
Expand Down
93 changes: 68 additions & 25 deletions src/routes/Gift.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { createResource, createSignal, Match, Show, Switch } from "solid-js";
import {
createMemo,
createResource,
createSignal,
Match,
Show,
Suspense,
Switch
} from "solid-js";
import { useSearchParams } from "solid-start";

import treasureClosed from "~/assets/treasure-closed.png";
import treasure from "~/assets/treasure.gif";
import {
AmountFiat,
AmountSats,
BackLink,
Button,
ButtonLink,
DefaultMain,
Expand All @@ -24,39 +33,37 @@ import { Network } from "~/logic/mutinyWalletSetup";
import { useMegaStore } from "~/state/megaStore";
import { eify } from "~/utils";

export default function GiftPage() {
function InboundWarning() {
const [state, _] = useMegaStore();
const i18n = useI18n();

const [claimSuccess, setClaimSuccess] = createSignal(false);
const [error, setError] = createSignal<Error>();
const [loading, setLoading] = createSignal(false);

const [searchParams] = useSearchParams();

const [inboundCapacity] = createResource(async () => {
try {
const channels = await state.mutiny_wallet?.list_channels();
let inbound = 0;
let inbound = 0n;

for (const channel of channels) {
inbound += channel.size - (channel.balance + channel.reserve);
inbound =
inbound +
BigInt(channel.size) -
BigInt(channel.balance + channel.reserve);
}

return inbound;
} catch (e) {
console.error(e);
return 0;
return 0n;
}
});

const warningText = () => {
const amount = Number(searchParams.amount);

if (isNaN(amount)) {
const warningText = createMemo(() => {
if (isNaN(Number(searchParams.amount))) {
return undefined;
}

const amount = BigInt(searchParams.amount);

const network = state.mutiny_wallet?.get_network() as Network;

const threshold = network === "bitcoin" ? 50000 : 10000;
Expand All @@ -68,12 +75,31 @@ export default function GiftPage() {
});
}

if (amount > (inboundCapacity() || 0)) {
if (inboundCapacity() && inboundCapacity()! > amount) {
return undefined;
} else {
return i18n.t("settings.gift.setup_fee_lightning");
}
});

return (
<Show when={warningText()}>
<InfoBox accent="blue">
{warningText()} <FeesModal />
</InfoBox>
</Show>
);
}

export default function GiftPage() {
const [state, _] = useMegaStore();
const i18n = useI18n();

return undefined;
};
const [claimSuccess, setClaimSuccess] = createSignal(false);
const [error, setError] = createSignal<Error>();
const [loading, setLoading] = createSignal(false);

const [searchParams] = useSearchParams();

async function claim() {
const amount = Number(searchParams.amount);
Expand All @@ -84,7 +110,6 @@ export default function GiftPage() {
BigInt(amount),
nwc
);
console.log("claim result", claimResult);
if (claimResult === "Already Claimed") {
throw new Error(i18n.t("settings.gift.already_claimed"));
}
Expand All @@ -105,16 +130,27 @@ export default function GiftPage() {
setClaimSuccess(true);
} catch (e) {
console.error(e);
setError(eify(e));
const err = eify(e);
if (err.message === "Payment timed out.") {
setError(new Error(i18n.t("settings.gift.sender_timed_out")));
} else {
setError(err);
}
} finally {
setLoading(false);
}
}

async function tryAgain() {
setError(undefined);
await claim();
}

return (
<MutinyWalletGuard>
<SafeArea>
<DefaultMain>
<BackLink />
<Show when={searchParams.nwc_uri && searchParams.amount}>
<VStack>
<FancyCard>
Expand Down Expand Up @@ -173,12 +209,10 @@ export default function GiftPage() {
"settings.gift.receive_description"
)}
</NiceP>
<Show
when={warningText() && !claimSuccess()}
>
<InfoBox accent="blue">
{warningText()} <FeesModal />
</InfoBox>
<Show when={!claimSuccess()}>
<Suspense>
<InboundWarning />
</Suspense>
</Show>
<Switch>
<Match when={error()}>
Expand All @@ -188,6 +222,15 @@ export default function GiftPage() {
<ButtonLink href="/" intent="red">
{i18n.t("common.dangit")}
</ButtonLink>
<Button
intent="inactive"
onClick={tryAgain}
loading={loading()}
>
{i18n.t(
"settings.gift.receive_try_again"
)}
</Button>
</Match>
<Match when={claimSuccess()}>
<InfoBox accent="green">
Expand Down
18 changes: 15 additions & 3 deletions src/routes/settings/Gift.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,13 @@ export function SingleGift(props: {
const i18n = useI18n();
const [state, _actions] = useMegaStore();

const baseUrl = window.location.origin;
const network = state.mutiny_wallet?.get_network();

const baseUrl =
network === "bitcoin"
? "https://app.mutinywallet.com"
: "https://signet-app.mutinywallet.com";

const sharableUrl = () => baseUrl.concat(props.profile.url_suffix || "");
TonyGiorgio marked this conversation as resolved.
Show resolved Hide resolved
const amount = () => props.profile.budget_amount?.toString() || "0";

Expand Down Expand Up @@ -198,12 +204,15 @@ export default function GiftPage() {
return Number(getValue(giftForm, "amount")) < 50000;
};

const selfHosted = state.mutiny_wallet?.get_network() === "signet";
benthecarman marked this conversation as resolved.
Show resolved Hide resolved
const canGift = state.mutiny_plus || selfHosted;

return (
<MutinyWalletGuard>
<SafeArea>
<DefaultMain>
<BackPop />
<Show when={!state.mutiny_plus}>
<Show when={!canGift}>
<VStack>
<LargeHeader>
{i18n.t("settings.gift.send_header")}
Expand Down Expand Up @@ -236,6 +245,9 @@ export default function GiftPage() {
"settings.gift.send_instructions"
)}
</NiceP>
<InfoBox accent="green">
{i18n.t("settings.gift.send_tip")}
</InfoBox>
<SingleGift
profile={freshProfile()!}
onDelete={resetGifting}
Expand All @@ -247,7 +259,7 @@ export default function GiftPage() {
</Button>
</VStack>
</Show>
<Show when={!giftResult() && state.mutiny_plus}>
<Show when={!giftResult() && canGift}>
<LargeHeader>
{i18n.t("settings.gift.send_header")}
</LargeHeader>
Expand Down
9 changes: 5 additions & 4 deletions src/routes/settings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,15 @@ export default function Settings() {
// @ts-ignore
const COMMIT_HASH = import.meta.env.__COMMIT_HASH__;

const selfHosted = state.settings?.selfhosted === "true";

return (
<SafeArea>
<DefaultMain>
<BackLink />
<LargeHeader>{i18n.t("settings.header")}</LargeHeader>
<VStack biggap>
<Show when={state.settings?.selfhosted !== "true"}>
<Show when={!selfHosted}>
<MutinyPlusCta />
</Show>
<SettingsLinkList
Expand Down Expand Up @@ -127,10 +129,9 @@ export default function Settings() {
},
{
href: "/settings/gift",
disabled: !state.mutiny_plus,

disabled: !(state.mutiny_plus || selfHosted),
text: i18n.t("settings.gift.title"),
caption: !state.mutiny_plus
caption: !(state.mutiny_plus || selfHosted)
? "Upgrade to Mutiny+ to enabled gifting"
: undefined
},
Expand Down