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

Credits funding for slot #1272

Merged
merged 5 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions packages/keychain/src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Success } from "./success";
import { Pending } from "./pending";
import { Consent, Slot } from "./slot";
import { OcclusionDetector } from "./OcclusionDetector";
import { Fund } from "./slot/fund";

export function App() {
return (
Expand All @@ -19,6 +20,7 @@ export function App() {
<Route path="session" element={<Session />} />
<Route path="slot" element={<Slot />}>
<Route path="consent" element={<Consent />} />
<Route path="fund" element={<Fund />} />
</Route>
<Route path="success" element={<Success />} />
<Route path="failure" element={<Failure />} />
Expand Down
5 changes: 4 additions & 1 deletion packages/keychain/src/components/funding/Balance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ import {
} from "@cartridge/utils";
import { useController } from "@/hooks/controller";

export type BalanceType = "credits" | "eth" | "strk";

type BalanceProps = {
showBalances: ("credits" | "eth" | "strk")[];
showBalances: BalanceType[];
};

export function Balance({ showBalances }: BalanceProps) {
Expand All @@ -26,6 +28,7 @@ export function Balance({ showBalances }: BalanceProps) {
username: controller?.username(),
interval: 3000,
});

const {
data: [eth],
} = useERC20Balance({
Expand Down
31 changes: 10 additions & 21 deletions packages/keychain/src/components/funding/PurchaseCredits.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Elements } from "@stripe/react-stripe-js";
import { Appearance, loadStripe } from "@stripe/stripe-js";
import { Balance } from "./Balance";
import CheckoutForm from "./StripeCheckout";
import { isIframe } from "@cartridge/utils";

const STRIPE_API_PUBKEY =
"pk_test_51Kr6IXIS6lliDpf33KnwWDtIjRPWt3eAI9CuSLR6Vvc3GxHEwmSU0iszYbUlgUadSRluGKAFphe3JzltyjPAKiBK00al4RAFQu";
Expand All @@ -25,10 +26,11 @@ enum PurchaseState {
}

type PurchaseCreditsProps = {
isSlot?: boolean;
onBack?: () => void;
};

export function PurchaseCredits({ onBack }: PurchaseCreditsProps) {
export function PurchaseCredits({ isSlot, onBack }: PurchaseCreditsProps) {
const { controller, closeModal } = useConnection();

const [clientSecret, setClientSecret] = useState("");
Expand Down Expand Up @@ -82,24 +84,6 @@ export function PurchaseCredits({ onBack }: PurchaseCreditsProps) {
},
} as Appearance;

// For when we need to support Payment Links
// useStripePaymentQuery(
// { referenceId },
// {
// enabled: !!referenceId && !error,
// refetchInterval: REFETCH_INTERVAL,
// retry: MAX_RETRIES,
// onSuccess: () => setState(PurchaseState.SUCCESS),
// onError: () => {
// setError(
// new Error(
// `Payment not received. Please try again. Reference ID: ${referenceId}`,
// ),
// );
// },
// },
// );

if (state === PurchaseState.STRIPE_CHECKOUT) {
return (
<Elements
Expand Down Expand Up @@ -130,13 +114,18 @@ export function PurchaseCredits({ onBack }: PurchaseCreditsProps) {
)
}
onBack={state === PurchaseState.SELECTION ? onBack : undefined}
hideNetwork
>
<Content className="gap-6">
<Balance showBalances={["credits"]} />
<ErrorAlert
variant=""
title="WHAT ARE CREDITS"
description="Credits can be used to play games. They are not tokens and cannot be transferred or refunded."
description={
"Credits can be used " +
(isSlot ? "for slot deployments" : "to play games") +
". They are not tokens and cannot be transferred or refunded."
}
isExpanded
/>
</Content>
Expand All @@ -150,7 +139,7 @@ export function PurchaseCredits({ onBack }: PurchaseCreditsProps) {
/>
)}

{state === PurchaseState.SUCCESS && (
{state === PurchaseState.SUCCESS && isIframe() && (
<Button variant="secondary" onClick={closeModal}>
Close
</Button>
Expand Down
33 changes: 21 additions & 12 deletions packages/keychain/src/components/funding/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from "@cartridge/ui-next";
import { DepositEth } from "./DepositEth";
import { PurchaseCredits } from "./PurchaseCredits";
import { Balance } from "./Balance";
import { Balance, BalanceType } from "./Balance";

const enum FundingState {
SHOW_OPTIONS,
Expand All @@ -19,15 +19,18 @@ const enum FundingState {
}

export type FundingProps = {
title?: React.ReactElement;
title?: React.ReactElement | string;
isSlot?: boolean;
onComplete?: (deployHash?: string) => void;
};

export function Funding({ onComplete, title }: FundingProps) {
export function Funding({ title, isSlot, onComplete }: FundingProps) {
const { controller } = useConnection();
const [state, setState] = useState<FundingState>(FundingState.SHOW_OPTIONS);
const showBalances: BalanceType[] = isSlot ? ["credits"] : ["credits", "eth"];
const showCredits =
typeof document !== "undefined" && document.cookie.includes("credits=");
(typeof document !== "undefined" && document.cookie.includes("credits=")) ||
isSlot;

if (state === FundingState.FUND_ETH) {
return (
Expand All @@ -40,7 +43,10 @@ export function Funding({ onComplete, title }: FundingProps) {

if (state === FundingState.FUND_CREDITS) {
return (
<PurchaseCredits onBack={() => setState(FundingState.SHOW_OPTIONS)} />
<PurchaseCredits
isSlot={isSlot}
onBack={() => setState(FundingState.SHOW_OPTIONS)}
/>
);
}

Expand All @@ -49,22 +55,25 @@ export function Funding({ onComplete, title }: FundingProps) {
title={title || (controller ? `Fund ${controller.username()}` : "")}
description={controller && <CopyAddress address={controller.address} />}
icon={<ArrowIcon variant="down" />}
hideNetwork
>
<Content className="gap-6">
<Balance showBalances={["credits", "eth"]} />
<Balance showBalances={showBalances} />
</Content>
<Footer>
{showCredits && (
<Button onClick={() => setState(FundingState.FUND_CREDITS)}>
<CoinsIcon variant="line" size="sm" /> Purchase Credits
</Button>
)}
<Button
onClick={() => setState(FundingState.FUND_ETH)}
variant="secondary"
>
<EthereumIcon size="sm" className="mr-1" /> Deposit Eth
</Button>
{!isSlot && (
<Button
onClick={() => setState(FundingState.FUND_ETH)}
variant="secondary"
>
<EthereumIcon size="sm" className="mr-1" /> Deposit Eth
</Button>
)}
</Footer>
</Container>
);
Expand Down
16 changes: 13 additions & 3 deletions packages/keychain/src/components/slot/consent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import Controller from "@/utils/controller";
import { Button } from "@cartridge/ui-next";
import { Container, Footer } from "@/components/layout";
import { useCallback, useEffect } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import { useLocation, useNavigate, useSearchParams } from "react-router-dom";

export function Consent() {
const navigate = useNavigate();
const { pathname } = useLocation();
const [searchParams] = useSearchParams();
const callback_uri = searchParams.get("callback_uri")!;

Expand All @@ -25,9 +26,18 @@ export function Consent() {

useEffect(() => {
if (!Controller.fromStore(import.meta.env.VITE_ORIGIN!)) {
navigate("/slot", { replace: true });
navigate(
`/slot?returnTo=${encodeURIComponent(pathname)}${
callback_uri
? `&callback_uri=${encodeURIComponent(callback_uri)}`
: ""
}`,
{
replace: true,
},
);
}
}, [navigate]);
}, [navigate, callback_uri, pathname]);

return (
<Container
Expand Down
19 changes: 19 additions & 0 deletions packages/keychain/src/components/slot/fund.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { useEffect } from "react";
import { Funding } from "../funding";
import Controller from "@/utils/controller";
import { useLocation, useNavigate } from "react-router-dom";

export function Fund() {
const navigate = useNavigate();
const { pathname } = useLocation();

useEffect(() => {
if (!Controller.fromStore(import.meta.env.VITE_ORIGIN!)) {
navigate(`/slot?returnTo=${encodeURIComponent(pathname)}`, {
replace: true,
});
}
}, [navigate, pathname]);

return <Funding title="Fund Credits for Slot" isSlot />;
}
17 changes: 11 additions & 6 deletions packages/keychain/src/components/slot/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export function Slot() {
case "/slot/auth/failure":
return <Navigate to="/failure" replace />;
case "/slot/consent":
case "/slot/fund":
return <Outlet />;
default:
return <Auth />;
Expand All @@ -37,13 +38,17 @@ function Auth() {

useEffect(() => {
if (user && controller) {
const query = Array.from(searchParams.entries()).reduce(
(prev, [key, val], i) =>
i === 0 ? `?${key}=${val}` : `${prev}&${key}=${val}`,
"",
);
const returnTo = searchParams.get("returnTo");
const otherParams = Array.from(searchParams.entries())
.filter(([key]) => key !== "returnTo")
.reduce(
(prev, [key, val], i) =>
i === 0 ? `?${key}=${val}` : `${prev}&${key}=${val}`,
"",
);

navigate(`/slot/consent${query}`, { replace: true });
const target = returnTo ? `${returnTo}${otherParams}` : "/slot";
navigate(target, { replace: true });
}
}, [user, controller, navigate, searchParams]);

Expand Down
7 changes: 6 additions & 1 deletion packages/keychain/src/hooks/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,13 @@ export function useConnectionValue() {
useEffect(() => {
const urlParams = new URLSearchParams(window.location.search);

// Set rpc and origin if we're not embedded (eg Slot auth/session)
// if we're not embedded (eg Slot auth/session) load controller from store and set origin/rpcUrl
if (!isIframe()) {
const controller = Controller.fromStore(import.meta.env.VITE_ORIGIN!);
if (controller) {
setController(controller);
}

setOrigin(urlParams.get("origin") || import.meta.env.VITE_ORIGIN);
const rpcUrl = urlParams.get("rpc_url");
if (rpcUrl) {
Expand Down
Loading