diff --git a/apps/crepe/src/app/checkout/components/connect-wallet.tsx b/apps/crepe/src/app/checkout/components/connect-wallet.tsx index 93c0cde65..e8ad27931 100644 --- a/apps/crepe/src/app/checkout/components/connect-wallet.tsx +++ b/apps/crepe/src/app/checkout/components/connect-wallet.tsx @@ -8,8 +8,8 @@ import { ConnectMutate } from "wagmi/query"; import RightPane from "./right-pane"; import { Button } from "../../components/button"; -import { usePaymentInfo } from "../payment-info-context"; -import { trpc } from "../trpc"; +import { usePaymentInfo } from "../../payment-info-context"; +import { trpc } from "../../trpc"; interface PaymentOption { name: string; diff --git a/apps/crepe/src/app/checkout/components/payment-confirmation.tsx b/apps/crepe/src/app/checkout/components/payment-confirmation.tsx index cd750e757..2aca2c6b1 100644 --- a/apps/crepe/src/app/checkout/components/payment-confirmation.tsx +++ b/apps/crepe/src/app/checkout/components/payment-confirmation.tsx @@ -1,8 +1,8 @@ import { CrepeOrder, getChainExplorerTxUrl } from "@daimo/common"; import { useEffect, useState } from "react"; -import { usePaymentInfo } from "../payment-info-context"; -import { trpc } from "../trpc"; +import { usePaymentInfo } from "../../payment-info-context"; +import { trpc } from "../../trpc"; export default function PaymentConfirmation() { const { transferInfo, merchantToken } = usePaymentInfo(); diff --git a/apps/crepe/src/app/checkout/components/payment-method.tsx b/apps/crepe/src/app/checkout/components/payment-method.tsx index c19cad63b..094de2a62 100644 --- a/apps/crepe/src/app/checkout/components/payment-method.tsx +++ b/apps/crepe/src/app/checkout/components/payment-method.tsx @@ -1,5 +1,6 @@ "use client"; +import { getAddressContraction } from "@daimo/common"; import { erc20Abi, ForeignToken, @@ -18,16 +19,15 @@ import { useWriteContract, } from "wagmi"; -import { Button } from "../../components/button"; -import { chainToLogo } from "../constants"; -import { usePaymentInfo } from "../payment-info-context"; -import { trpc } from "../trpc"; import { Notification } from "./notification"; import RightPane from "./right-pane"; +import { trpc } from "../../trpc"; +import { chainToLogo } from "../constants"; import { SearchPaletteItem, SearchPaletteWithGroups } from "./search-palette"; import { PaymentMethodsSkeleton } from "./skeletons"; - -import { formatAmountDecimals, truncateAddress } from "@/src/utils/format"; +import { Button } from "../../components/button"; +import { usePaymentInfo } from "../../payment-info-context"; +import { formatAmountDecimals } from "../../utils/format"; interface TokenBalance { token: ForeignToken; @@ -118,7 +118,7 @@ export default function PaymentMethods() {
{(ensName || address) && (

- Pay with {ensName || truncateAddress(address!)} + Pay with {ensName || getAddressContraction(address!, 3)}

)} void; + products: PaymentItem[]; + merchantToken: ForeignToken; + amount: bigint; }) { - const { item, merchantToken, onchainOrder } = usePaymentInfo(); - const products = [item]; - - const formattedPrice = formatAmountDecimals( - BigInt(onchainOrder.destinationFinalCallTokenAmount), - merchantToken - ); + const formattedPrice = formatAmountDecimals(amount, merchantToken); return (
- Pay {item.company} + Pay {products[0].company}
{formattedPrice} {merchantToken.symbol} diff --git a/apps/crepe/src/app/checkout/layout.tsx b/apps/crepe/src/app/checkout/layout.tsx index 6ff898dcd..6d07072d9 100644 --- a/apps/crepe/src/app/checkout/layout.tsx +++ b/apps/crepe/src/app/checkout/layout.tsx @@ -4,15 +4,15 @@ import { headers } from "next/headers"; import { cookieToInitialState } from "wagmi"; import "../../styles/tailwind.css"; -import { Providers } from "./providers"; -import { config } from "./wagmi-config"; +import { Providers } from "../providers"; +import { config } from "../wagmi-config"; const inter = Inter({ subsets: ["latin"] }); export const metadata: Metadata = { title: { template: "%s - Crepe", - default: "Checkout with Crepe", + default: "Checkout", }, }; diff --git a/apps/crepe/src/app/checkout/page.tsx b/apps/crepe/src/app/checkout/page.tsx index f99586bb4..a05350b4b 100644 --- a/apps/crepe/src/app/checkout/page.tsx +++ b/apps/crepe/src/app/checkout/page.tsx @@ -3,17 +3,22 @@ import { useAccount, useDisconnect } from "wagmi"; import { GradientLight } from "../components/gradient"; +import { usePaymentInfo } from "../payment-info-context"; import ConnectWallet from "./components/connect-wallet"; import PaymentConfirmation from "./components/payment-confirmation"; import PaymentMethods from "./components/payment-method"; import SummaryPane from "./components/summary-pane"; -import { usePaymentInfo } from "./payment-info-context"; function ConnectWalletPage() { + const { item, merchantToken, onchainOrder } = usePaymentInfo(); return ( <>

Connect Wallet

- + ); @@ -21,6 +26,7 @@ function ConnectWalletPage() { function PaymentMethodPage() { const { disconnect } = useDisconnect(); + const { item, merchantToken, onchainOrder } = usePaymentInfo(); const handleBackClick = () => { disconnect(); @@ -29,17 +35,27 @@ function PaymentMethodPage() { return ( <>

Payment Method

- + ); } function PaymentConfirmationPage() { + const { item, merchantToken, onchainOrder } = usePaymentInfo(); return ( <>

Payment Confirmation

- + ); diff --git a/apps/crepe/src/app/generator/layout.tsx b/apps/crepe/src/app/generator/layout.tsx new file mode 100644 index 000000000..66563484e --- /dev/null +++ b/apps/crepe/src/app/generator/layout.tsx @@ -0,0 +1,21 @@ +import type { Metadata } from "next"; +import "../../styles/tailwind.css"; + +export const metadata: Metadata = { + title: { + template: "%s - Crepe", + default: "Generate", + }, +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + {children} + + ); +} diff --git a/apps/crepe/src/app/generator/page.tsx b/apps/crepe/src/app/generator/page.tsx new file mode 100644 index 000000000..921d0d3a8 --- /dev/null +++ b/apps/crepe/src/app/generator/page.tsx @@ -0,0 +1,306 @@ +"use client"; + +import { getViemChainById } from "@daimo/common"; +import { + ForeignToken, + baseUSDC, + baseUSDT, + baseDAI, + baseWETH, + optimismUSDC, + optimismWETH, + polygonUSDC, + polygonWETH, + arbitrumUSDC, + arbitrumWETH, + getCctpDomain, + getBridgeCoin, +} from "@daimo/contract"; +import { ArrowTopRightOnSquareIcon } from "@heroicons/react/20/solid"; +import { useState } from "react"; +import { Address, parseUnits } from "viem"; + +import SummaryPane from "../checkout/components/summary-pane"; +import { GradientLight } from "../components/gradient"; +import { OnchainOrder, PaymentItem } from "../payment-info-context"; +import { trpc } from "../trpc"; + +const availableForeignTokens: ForeignToken[] = [ + // Base + baseUSDC, + baseUSDT, + baseDAI, + baseWETH, + // Optimism + optimismUSDC, + optimismWETH, + // Arbitrum + arbitrumUSDC, + arbitrumWETH, + // Polygon + polygonUSDC, + polygonWETH, +]; + +function GeneratorContent() { + const [paymentItem, setPaymentItem] = useState({ + name: "Milk", + company: "Daimoo", + description: "Got milk?", + image: + "https://static.vecteezy.com/system/resources/thumbnails/026/677/433/small_2x/ai-generated-ai-generative-beautiful-young-tittle-calf-on-sunflower-field-at-sunset-nature-landscape-farm-cow-animal-vibe-graphic-art-photo.jpg", + }); + + const [abbreviatedOrder, setAbbreviatedOrder] = useState<{ + token: ForeignToken; + amount: string; + recipientAddress: Address; + }>({ + token: availableForeignTokens[0], + amount: "1.23", + recipientAddress: "0xF05b5f04B7a77Ca549C0dE06beaF257f40C66FDB", + }); + + const handleInputChange = ( + e: React.ChangeEvent< + HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement + > + ) => { + const { name, value } = e.target; + if (name === "token") { + const selectedToken = availableForeignTokens.find( + (t) => `${t.token}-${t.chainId}` === value + ); + if (selectedToken) { + setAbbreviatedOrder((prev) => ({ ...prev, token: selectedToken })); + } + } else if (name === "amount" || name === "recipientAddress") { + setAbbreviatedOrder((prev) => ({ ...prev, [name]: value })); + } else { + setPaymentItem((prev) => ({ ...prev, [name]: value })); + } + }; + + const handleGenerate = async (e: React.FormEvent) => { + e.preventDefault(); + + // Calculate the USD value + const usdRate = await trpc.getUSDRate.query({ + buyToken: abbreviatedOrder.token.token, + buyTokenAmount: parseUnits( + abbreviatedOrder.amount, + abbreviatedOrder.token.decimals + ).toString(), + buyTokenChainId: abbreviatedOrder.token.chainId, + }); + + const order: OnchainOrder = { + destinationChainId: abbreviatedOrder.token.chainId, + destinationDomain: getCctpDomain( + abbreviatedOrder.token.chainId + ).toString(), + destinationMintTokenAddr: getBridgeCoin(abbreviatedOrder.token.chainId) + .token, + destinationMintTokenAmount: usdRate.toString(), + destinationFinalCallTokenAddr: abbreviatedOrder.token.token, + destinationFinalCallTokenAmount: parseUnits( + abbreviatedOrder.amount, + abbreviatedOrder.token.decimals + ).toString(), + destinationFinalCallTo: abbreviatedOrder.recipientAddress, + destinationFinalCallValue: "0", + destinationFinalCallData: "0x", + destinationRefundAddr: abbreviatedOrder.recipientAddress, + destinationNonce: Math.floor(Math.random() * 1000000).toString(), + }; + + const item = paymentItem; + openInNewTab( + `${process.env.NEXT_PUBLIC_URL}/checkout?${new URLSearchParams({ + order: btoa(JSON.stringify(order)), + item: btoa(JSON.stringify(item)), + }).toString()}` + ); + }; + + const openInNewTab = (url: string) => { + window.open(url, "_blank", "noopener,noreferrer"); + }; + + return ( +
+ + + +
+
+

+ Explore Checkout +

+
+
+
+
+ + +
+
+ + +
+
+
+ +