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

[WIP] Project intergalactic - Fiat flow #4714

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
5 changes: 5 additions & 0 deletions apps/playground-web/src/components/pay/embed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ export function StyledPayEmbedPreview() {
return (
<PayEmbed
client={THIRDWEB_CLIENT}
payOptions={{
buyWithFiat: {
preferredProvider: "STRIPE",
},
}}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove before merging

theme={theme === "light" ? "light" : "dark"}
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ export function FiatFlow(props: {
props.openedWindow,
);

// Not sure how to do this better
const [onRampLinkOverride, setOnRampLinkOverride] = useState<string | null>(
null,
);

const onPostOnrampSuccess = useCallback(() => {
// report the status of fiat status instead of post onramp swap status when post onramp swap is successful
getBuyWithFiatStatus({
Expand All @@ -87,14 +92,19 @@ export function FiatFlow(props: {
onBack={props.onBack}
partialQuote={fiatQuoteToPartialQuote(props.quote)}
step={1}
setOnRampLinkOverride={setOnRampLinkOverride}
onContinue={() => {
const popup = openOnrampPopup(props.quote.onRampLink, props.theme);
const popup = openOnrampPopup(
onRampLinkOverride || props.quote.onRampLink,
props.theme,
);
trackPayEvent({
event: "open_onramp_popup",
client: props.client,
walletAddress: props.payer.account.address,
walletType: props.payer.wallet.id,
});

addPendingTx({
type: "fiat",
intentId: props.quote.intentId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@ import {
TriangleDownIcon,
} from "@radix-ui/react-icons";
import { useMemo } from "react";
import type { Chain } from "../../../../../../../chains/types.js";
import { getCachedChain } from "../../../../../../../chains/utils.js";
import type { ThirdwebClient } from "../../../../../../../client/client.js";
import { NATIVE_TOKEN_ADDRESS } from "../../../../../../../constants/addresses.js";
import { getContract } from "../../../../../../../contract/contract.js";
import { addSessionKey } from "../../../../../../../extensions/erc4337/account/addSessionKey.js";
import type { BuyWithFiatQuote } from "../../../../../../../pay/buyWithFiat/getQuote.js";
import type { BuyWithFiatStatus } from "../../../../../../../pay/buyWithFiat/getStatus.js";
import { getPayBaseUrl } from "../../../../../../../pay/utils/definitions.js";
import { formatNumber } from "../../../../../../../utils/formatNumber.js";
import { createAndSignUserOp } from "../../../../../../../wallets/smart/lib/userop.js";
import { hexlifyUserOp } from "../../../../../../../wallets/smart/lib/utils.js";
import { smartWallet } from "../../../../../../../wallets/smart/smart-wallet.js";
import {
type Theme,
fontSize,
Expand All @@ -21,6 +28,8 @@ import {
useChainExplorers,
useChainName,
} from "../../../../../../core/hooks/others/useChainQuery.js";
import { useActiveAccount } from "../../../../../../core/hooks/wallets/useActiveAccount.js";
import { useSwitchActiveWalletChain } from "../../../../../../core/hooks/wallets/useSwitchActiveWalletChain.js";
import type { TokenInfo } from "../../../../../../core/utils/defaultTokens.js";
import { Spacer } from "../../../../components/Spacer.js";
import { Spinner } from "../../../../components/Spinner.js";
Expand All @@ -38,6 +47,7 @@ import {
import { getCurrencyMeta } from "./currencies.js";

export type BuyWithFiatPartialQuote = {
intentId: string;
fromCurrencySymbol: string;
fromCurrencyAmount: string;
onRampTokenAmount: string;
Expand Down Expand Up @@ -77,6 +87,7 @@ export function fiatQuoteToPartialQuote(
name: quote.toToken.name,
symbol: quote.toToken.symbol,
},
intentId: quote.intentId,
};

return data;
Expand All @@ -90,6 +101,7 @@ export function FiatSteps(props: {
client: ThirdwebClient;
step: number;
onContinue: () => void;
setOnRampLinkOverride?: (link: string) => void;
}) {
const statusMeta = props.status
? getBuyWithFiatStatusMeta(props.status)
Expand All @@ -102,8 +114,100 @@ export function FiatSteps(props: {
fromCurrencySymbol,
fromCurrencyAmount,
toTokenAmount,
intentId,
} = props.partialQuote;

const account = useActiveAccount();
const switchChain = useSwitchActiveWalletChain();

const deploySmartWallet = async ({ chain }: { chain: Chain }) => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs to be better organized

if (!account) return;

await switchChain(chain);

const smartWalletHandle = smartWallet({
chain,
sponsorGas: true,
});

const smartAccount = await smartWalletHandle.connect({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now, this creates a smart wallet that is deterministic to the account, but not per intent. How can I send in an intentId as the string to be deterministic by?

client: props.client,
personalAccount: account,
});
console.log("smartAccount", smartAccount);

const smartAccountContract = getContract({
client: props.client,
chain,
address: smartAccount.address,
});

console.log("onRampTokenAmount", props.partialQuote.onRampTokenAmount);
const sessionKeyTx = addSessionKey({
contract: smartAccountContract,
account: account,
// TODO: Env var this.
// // prod
// sessionKeyAddress: "0x1629Ce9Df01B10E7CF8837f559037A49d983aA10", // pay engine backend wallet
// dev
sessionKeyAddress: "0x32DC86f866e9F5Ed59A60b18c3B0f9b972a928F0", // dev engine backend wallet
permissions: {
approvedTargets: "*", // the addresses of allowed contracts, or '*' for any contract
permissionStartTimestamp: new Date(), // the date when the session key becomes active
permissionEndTimestamp: new Date(Date.now() + 24 * 60 * 60 * 1000), // the date when the session key expires
// TODO: Perhaps add a buffer here to be safe?
nativeTokenLimitPerTransaction: props.partialQuote.onRampTokenAmount,
},
});

const signedUserOp = await createAndSignUserOp({
transactions: [sessionKeyTx],
adminAccount: account,
client: props.client,
smartWalletOptions: {
chain,
sponsorGas: true,
},
});

const hexlifiedUserOp = hexlifyUserOp(signedUserOp);
console.log("signedUserOp", signedUserOp);
console.log("hexlifiedUserOp", hexlifiedUserOp);
console.log("sessionKeyTx", sessionKeyTx);

console.log("chainId", chain.id);
console.log("intentId", intentId);
console.log("toAddress", account.address);
const response = await fetch(
`${getPayBaseUrl()}/v2/intent-wallets/deploy`,
{
method: "POST",
body: JSON.stringify({
chainId: chain.id,
intentId: intentId,
intentType: "buyWithFiat",
signedUserOps: [hexlifiedUserOp],
toAddress: account.address,
smartWalletAddress: smartAccount.address,
}),
headers: {
"Content-Type": "application/json",
"x-client-id": process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID as string,
},
},
);

const data = await response.json();
console.log("response from server", data);

props.setOnRampLinkOverride?.(data.onRampLink);

return {
smartWalletAddress: smartAccount.address,
userAddress: account.address,
};
};

const currency = getCurrencyMeta(fromCurrencySymbol);
const isPartialSuccess = statusMeta?.progressStatus === "partialSuccess";

Expand Down Expand Up @@ -313,6 +417,10 @@ export function FiatSteps(props: {
<Spacer y="lg" />

{/* Step 1 */}
<button onClick={() => deploySmartWallet({ chain: onRampChain })}>
Deploy smart wallet with session key
</button>

<PaymentStep
title={
<Text color="primaryText" size="md">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export function FiatDetailsScreen(props: {
transactionMode={props.transactionMode}
isEmbed={props.isEmbed}
quote={{
intentId: status.intentId,
fromCurrencyAmount: fiatQuote.fromCurrencyWithFees.amount,
fromCurrencySymbol: fiatQuote.fromCurrencyWithFees.currencySymbol,
onRampTokenAmount: fiatQuote.estimatedOnRampAmount,
Expand Down
2 changes: 1 addition & 1 deletion packages/thirdweb/src/utils/domains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type DomainOverrides = {
bundler?: string;
};

export const DEFAULT_RPC_URL = "rpc.thirdweb.com";
export const DEFAULT_RPC_URL = "rpc.thirdweb-dev.com";
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change back

const DEFAULT_SOCIAL_URL = "social.thirdweb.com";
const DEFAULT_IN_APP_WALLET_URL = "embedded-wallet.thirdweb.com";
const DEFAULT_PAY_URL = "pay.thirdweb.com";
Expand Down
Loading