@medialane/ui 0.187.0 → 0.189.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/drop/create/drop-create.d.cts +1 -1
- package/dist/components/drop/create/drop-create.d.ts +1 -1
- package/dist/components/drop/create/launch-dialog.cjs +1 -1
- package/dist/components/drop/create/launch-dialog.cjs.map +1 -1
- package/dist/components/drop/create/launch-dialog.d.cts +1 -1
- package/dist/components/drop/create/launch-dialog.d.ts +1 -1
- package/dist/components/drop/create/launch-dialog.js +1 -1
- package/dist/components/drop/create/launch-dialog.js.map +1 -1
- package/dist/components/drop/page/drop-page.cjs +3 -3
- package/dist/components/drop/page/drop-page.cjs.map +1 -1
- package/dist/components/drop/page/drop-page.d.cts +1 -1
- package/dist/components/drop/page/drop-page.d.ts +1 -1
- package/dist/components/drop/page/drop-page.js +3 -3
- package/dist/components/drop/page/drop-page.js.map +1 -1
- package/dist/components/fast-mint/fast-mint.cjs +4 -5
- package/dist/components/fast-mint/fast-mint.cjs.map +1 -1
- package/dist/components/fast-mint/fast-mint.js +4 -5
- package/dist/components/fast-mint/fast-mint.js.map +1 -1
- package/dist/components/fast-mint/types.cjs.map +1 -1
- package/dist/components/fast-mint/types.d.cts +1 -2
- package/dist/components/fast-mint/types.d.ts +1 -2
- package/dist/components/media-wallet/media-wallet-activity.d.cts +0 -1
- package/dist/components/media-wallet/media-wallet-activity.d.ts +0 -1
- package/dist/components/media-wallet/media-wallet-home.cjs +5 -5
- package/dist/components/media-wallet/media-wallet-home.cjs.map +1 -1
- package/dist/components/media-wallet/media-wallet-home.d.cts +0 -1
- package/dist/components/media-wallet/media-wallet-home.d.ts +0 -1
- package/dist/components/media-wallet/media-wallet-home.js +5 -5
- package/dist/components/media-wallet/media-wallet-home.js.map +1 -1
- package/dist/components/media-wallet/media-wallet-overlay.d.cts +0 -1
- package/dist/components/media-wallet/media-wallet-overlay.d.ts +0 -1
- package/dist/components/media-wallet/media-wallet-send.cjs +7 -7
- package/dist/components/media-wallet/media-wallet-send.cjs.map +1 -1
- package/dist/components/media-wallet/media-wallet-send.d.cts +0 -1
- package/dist/components/media-wallet/media-wallet-send.d.ts +0 -1
- package/dist/components/media-wallet/media-wallet-send.js +7 -7
- package/dist/components/media-wallet/media-wallet-send.js.map +1 -1
- package/dist/components/media-wallet/media-wallet-token-detail.cjs +2 -2
- package/dist/components/media-wallet/media-wallet-token-detail.cjs.map +1 -1
- package/dist/components/media-wallet/media-wallet-token-detail.d.cts +0 -1
- package/dist/components/media-wallet/media-wallet-token-detail.d.ts +0 -1
- package/dist/components/media-wallet/media-wallet-token-detail.js +2 -2
- package/dist/components/media-wallet/media-wallet-token-detail.js.map +1 -1
- package/dist/components/media-wallet/media-wallet.d.cts +0 -1
- package/dist/components/media-wallet/media-wallet.d.ts +0 -1
- package/dist/components/media-wallet/types.cjs.map +1 -1
- package/dist/components/media-wallet/types.d.cts +0 -2
- package/dist/components/media-wallet/types.d.ts +0 -2
- package/dist/components/media-wallet/types.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js.map +1 -1
- package/dist/utils/app-wallet.cjs +4 -3
- package/dist/utils/app-wallet.cjs.map +1 -1
- package/dist/utils/app-wallet.d.cts +2 -2
- package/dist/utils/app-wallet.d.ts +2 -2
- package/dist/utils/app-wallet.js +4 -3
- package/dist/utils/app-wallet.js.map +1 -1
- package/dist/utils/drop/actions.cjs +3 -3
- package/dist/utils/drop/actions.cjs.map +1 -1
- package/dist/utils/drop/actions.d.cts +2 -3
- package/dist/utils/drop/actions.d.ts +2 -3
- package/dist/utils/drop/actions.js +3 -3
- package/dist/utils/drop/actions.js.map +1 -1
- package/dist/utils/drop/types.cjs.map +1 -1
- package/dist/utils/drop/types.d.cts +3 -6
- package/dist/utils/drop/types.d.ts +3 -6
- package/dist/utils/media-wallet/use-erc20-balance.cjs +14 -17
- package/dist/utils/media-wallet/use-erc20-balance.cjs.map +1 -1
- package/dist/utils/media-wallet/use-erc20-balance.d.cts +5 -4
- package/dist/utils/media-wallet/use-erc20-balance.d.ts +5 -4
- package/dist/utils/media-wallet/use-erc20-balance.js +14 -18
- package/dist/utils/media-wallet/use-erc20-balance.js.map +1 -1
- package/dist/utils/use-drops.cjs +19 -10
- package/dist/utils/use-drops.cjs.map +1 -1
- package/dist/utils/use-drops.d.cts +3 -7
- package/dist/utils/use-drops.d.ts +3 -7
- package/dist/utils/use-drops.js +19 -11
- package/dist/utils/use-drops.js.map +1 -1
- package/dist/utils/use-pop.cjs +3 -2
- package/dist/utils/use-pop.cjs.map +1 -1
- package/dist/utils/use-pop.d.cts +1 -2
- package/dist/utils/use-pop.d.ts +1 -2
- package/dist/utils/use-pop.js +3 -2
- package/dist/utils/use-pop.js.map +1 -1
- package/package.json +3 -3
- package/dist/utils/drop/chain.cjs +0 -37
- package/dist/utils/drop/chain.cjs.map +0 -1
- package/dist/utils/drop/chain.d.cts +0 -5
- package/dist/utils/drop/chain.d.ts +0 -5
- package/dist/utils/drop/chain.js +0 -13
- package/dist/utils/drop/chain.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-home.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport Link from \"../link.js\";\nimport { useRouter } from \"../router.js\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { useTokenBalance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { useTokensByOwner } from \"../../utils/media-wallet/use-tokens-by-owner.js\";\nimport { ActivateCard } from \"./activate-card.js\";\nimport { QuickAction } from \"./quick-action.js\";\nimport { ReceiveCard } from \"./receive-card.js\";\nimport { ActionModal } from \"./action-modal.js\";\nimport { SectionHeader } from \"./section-header.js\";\nimport { SuccessDialog } from \"./success-dialog.js\";\nimport { MediaWalletHeader } from \"./media-wallet-header.js\";\nimport { WALLET_TOKENS, type WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { pickNftItems } from \"../../utils/media-wallet/nft-items.js\";\nimport { NftStrip } from \"./nft-strip.js\";\nimport { useUsdPrices, usdPriceFor } from \"../../utils/use-usd-prices.js\";\nimport { fmt, fmtUsd, rawToNumber } from \"../../utils/media-wallet/wallet-format.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\n\nexport function MediaWalletHome({\n onNavigate,\n onClose,\n autoOpenReceive,\n}: {\n onNavigate: (view: MediaWalletView) => void;\n onClose: () => void;\n autoOpenReceive?: boolean;\n}) {\n const { useWalletSession, useEmailStatus, provider, getClient, resolveImage, emailBanner, externalWallet } = useMediaWalletApp();\n const { address, isDeployed } = useWalletSession();\n const emailStatus = useEmailStatus();\n const router = useRouter();\n const needsEmailVerification = !!emailStatus?.email && !emailStatus.emailVerified;\n\n const balances: Record<WalletToken[\"symbol\"], ReturnType<typeof useTokenBalance>> = {\n STRK: useTokenBalance(provider, \"STRK\", address),\n ETH: useTokenBalance(provider, \"ETH\", address),\n USDC: useTokenBalance(provider, \"USDC\", address),\n WBTC: useTokenBalance(provider, \"WBTC\", address),\n };\n\n const { tokens, isLoading: loadingNfts } = useTokensByOwner(getClient, address, 1, 6);\n const nftItems = pickNftItems(tokens, 6);\n\n const usdPrices = useUsdPrices();\n const [panel, setPanel] = useState<\"receive\" | null>(autoOpenReceive ? \"receive\" : null);\n const [hideBalances, setHideBalances] = useState(false);\n const [activated, setActivated] = useState(false);\n const [pull, setPull] = useState(0);\n const startY = useRef<number | null>(null);\n const mainRef = useRef<HTMLElement>(null);\n\n useEffect(() => {\n setHideBalances(localStorage.getItem(\"mediawallet.hideBalances\") === \"1\");\n }, []);\n\n const scrollParent = () => mainRef.current?.parentElement ?? null;\n const onTouchStart = (e: React.TouchEvent) => {\n const sc = scrollParent();\n startY.current = sc && sc.scrollTop <= 0 ? e.touches[0].clientY : null;\n };\n const onTouchMove = (e: React.TouchEvent) => {\n if (startY.current == null) return;\n const dy = e.touches[0].clientY - startY.current;\n if (dy > 0) setPull(Math.min(dy * 0.5, 90));\n };\n const onTouchEnd = () => {\n setPull(0);\n startY.current = null;\n };\n\n const usd = (symbol: WalletToken[\"symbol\"]) => {\n const { rawBalance, decimals } = balances[symbol];\n return rawToNumber(rawBalance, decimals) * (usdPriceFor(usdPrices, symbol) ?? 0);\n };\n const totalUsd = WALLET_TOKENS.reduce((sum, t) => sum + usd(t.symbol), 0);\n const heldTokens = WALLET_TOKENS.filter((t) => (balances[t.symbol].rawBalance ?? 0n) > 0n);\n\n const strkBalance = balances.STRK.rawBalance;\n const funded = strkBalance != null && strkBalance > 0n;\n const canSend = isDeployed === true && funded;\n\n const goLaunch = () => {\n onClose();\n router.push(\"/launchpad\");\n };\n\n return (\n <main\n ref={mainRef}\n onTouchStart={onTouchStart}\n onTouchMove={onTouchMove}\n onTouchEnd={onTouchEnd}\n className=\"relative flex min-h-full flex-col gap-6 px-5 pb-8 pt-2\"\n style={{ transform: pull ? `translateY(${pull}px)` : undefined, transition: pull ? \"none\" : \"transform 0.2s ease\" }}\n >\n {address && (\n <div className=\"flex flex-col items-center gap-4\">\n <MediaWalletHeader address={address} onNavigate={onClose} />\n {(funded || isDeployed === false) && (\n <span className=\"font-[family-name:var(--font-display)] text-5xl font-extrabold tracking-tight tabular-nums\">\n {hideBalances ? \"••••\" : usdPrices === null ? \"…\" : fmtUsd(totalUsd)}\n </span>\n )}\n </div>\n )}\n\n {funded ? (\n <div className=\"grid grid-cols-4 gap-2\">\n <QuickAction label=\"Send\" action=\"buy\" disabled={!canSend} onClick={() => onNavigate({ name: \"send\" })} icon={<ArrowUp />} />\n <QuickAction label=\"Receive\" action=\"offer\" onClick={() => setPanel(panel === \"receive\" ? null : \"receive\")} icon={<ArrowDown />} />\n <QuickAction label=\"Launch\" action=\"remix\" onClick={goLaunch} icon={<RocketIcon />} />\n <QuickAction label=\"Activity\" action=\"submit\" onClick={() => onNavigate({ name: \"activity\" })} icon={<ActivityIcon />} />\n </div>\n ) : isDeployed === null ? (\n <div className=\"flex flex-col gap-3\">\n <div className=\"flex flex-col items-center gap-3 py-2\">\n <div className=\"h-3 w-16 animate-pulse rounded bg-foreground/[0.06]\" />\n <div className=\"h-11 w-32 animate-pulse rounded bg-foreground/[0.06]\" />\n <div className=\"h-[48px] w-40 animate-pulse rounded-[13px] bg-foreground/[0.06]\" />\n </div>\n <div className=\"h-[148px] animate-pulse rounded-[20px] bg-foreground/[0.04]\" />\n </div>\n ) : (\n isDeployed === true && (\n <div className=\"flex flex-col gap-3\">\n <div className=\"flex flex-col items-center gap-3 py-2\">\n <span className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">Balance</span>\n <span className=\"font-[family-name:var(--font-display)] text-5xl font-extrabold tracking-tight tabular-nums\">\n {hideBalances ? \"••••\" : usdPrices === null ? \"…\" : fmtUsd(totalUsd)}\n </span>\n <button\n onClick={() => setPanel(panel === \"receive\" ? null : \"receive\")}\n className=\"h-[48px] rounded-[13px] px-8 text-[15px] font-semibold text-white transition-transform active:scale-[0.99]\"\n style={{ background: \"linear-gradient(115deg,#3b7bff,#5b4ce6)\" }}\n >\n Fund your account\n </button>\n </div>\n <button\n onClick={goLaunch}\n className=\"flex flex-col items-center gap-2 rounded-[20px] border-2 border-dashed border-border px-6 py-8 text-center transition-colors hover:border-primary/50 active:scale-[0.99]\"\n >\n <div className=\"grid h-11 w-11 place-items-center rounded-full bg-foreground/[0.06]\">\n <RocketIcon />\n </div>\n <span className=\"text-[15px] font-semibold text-foreground\">Creator Launchpad</span>\n <span className=\"text-xs text-muted-foreground\">Protect and monetize your work</span>\n </button>\n </div>\n )\n )}\n\n {isDeployed === false && <ActivateCard onActivated={() => setActivated(true)} />}\n\n {needsEmailVerification && (\n <Link\n href={emailBanner.href}\n onClick={onClose}\n className=\"flex items-center gap-3 rounded-2xl px-4 py-3 transition-opacity hover:opacity-90\"\n style={{ background: \"linear-gradient(115deg, hsl(var(--brand-orange) / 0.12), hsl(var(--brand-maeve, 327 64% 67%) / 0.12))\" }}\n >\n <div className=\"grid h-9 w-9 shrink-0 place-items-center rounded-full bg-brand-orange/15\">\n <MailIcon />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">Verify your email</div>\n <div className=\"text-xs text-muted-foreground\">{emailBanner.text(emailStatus?.deadline)}</div>\n </div>\n </Link>\n )}\n\n {panel === \"receive\" && address && (\n <ActionModal onClose={() => setPanel(null)}>\n <ReceiveCard address={address} />\n </ActionModal>\n )}\n\n {heldTokens.length > 0 && (\n <section>\n <SectionHeader title=\"Tokens\" />\n <div className=\"mt-2 flex flex-col gap-2\">\n {heldTokens.map((t) => {\n const { rawBalance, decimals } = balances[t.symbol];\n return (\n <button\n key={t.symbol}\n onClick={() => onNavigate({ name: \"token\", token: t })}\n className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 text-left backdrop-blur-sm transition-colors hover:bg-card/60\"\n >\n <div className=\"grid h-11 w-11 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <CurrencyIcon symbol={t.symbol} size={24} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">{t.symbol}</div>\n <div className=\"text-xs text-muted-foreground\">{t.name}</div>\n </div>\n <div className=\"text-right\">\n <div className=\"text-sm font-semibold tabular-nums\">{hideBalances ? \"••••\" : fmt(rawBalance, decimals)}</div>\n {!hideBalances && usdPrices !== null && (\n <div className=\"text-xs text-muted-foreground tabular-nums\">{fmtUsd(usd(t.symbol))}</div>\n )}\n </div>\n </button>\n );\n })}\n </div>\n </section>\n )}\n\n {(nftItems.length > 0 || loadingNfts) && (\n <section>\n <SectionHeader title=\"NFTs\" />\n <div className=\"mt-2\">\n <NftStrip items={nftItems} isLoading={loadingNfts} onNavigate={onClose} resolveImage={resolveImage} />\n </div>\n </section>\n )}\n\n {activated && (\n <SuccessDialog\n title=\"Account activated\"\n message=\"Your account is live and ready to use\"\n onClose={() => setActivated(false)}\n />\n )}\n\n <a\n href={externalWallet.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-auto text-center text-xs text-muted-foreground/60 transition-colors hover:text-muted-foreground\"\n >\n {externalWallet.label}\n </a>\n </main>\n );\n}\n\nfunction ArrowUp() {\n return (\n <svg width=\"19\" height=\"19\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 19V5M5 12l7-7 7 7\" />\n </svg>\n );\n}\nfunction ArrowDown() {\n return (\n <svg width=\"19\" height=\"19\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 5v14M19 12l-7 7-7-7\" />\n </svg>\n );\n}\nfunction ActivityIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.1\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 12h-4l-3 9L9 3l-3 9H2\" />\n </svg>\n );\n}\nfunction MailIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"text-brand-orange\">\n <rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\" />\n <path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\" />\n </svg>\n );\n}\nfunction RocketIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.1\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 00-2.91-.09z\" />\n <path d=\"M12 15l-3-3a22 22 0 012-3.95A12.88 12.88 0 0122 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 01-4 2z\" />\n <path d=\"M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5\" />\n </svg>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-home.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport Link from \"../link.js\";\nimport { useRouter } from \"../router.js\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { useTokenBalance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { useTokensByOwner } from \"../../utils/media-wallet/use-tokens-by-owner.js\";\nimport { ActivateCard } from \"./activate-card.js\";\nimport { QuickAction } from \"./quick-action.js\";\nimport { ReceiveCard } from \"./receive-card.js\";\nimport { ActionModal } from \"./action-modal.js\";\nimport { SectionHeader } from \"./section-header.js\";\nimport { SuccessDialog } from \"./success-dialog.js\";\nimport { MediaWalletHeader } from \"./media-wallet-header.js\";\nimport { WALLET_TOKENS, type WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { pickNftItems } from \"../../utils/media-wallet/nft-items.js\";\nimport { NftStrip } from \"./nft-strip.js\";\nimport { useUsdPrices, usdPriceFor } from \"../../utils/use-usd-prices.js\";\nimport { fmt, fmtUsd, rawToNumber } from \"../../utils/media-wallet/wallet-format.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\n\nexport function MediaWalletHome({\n onNavigate,\n onClose,\n autoOpenReceive,\n}: {\n onNavigate: (view: MediaWalletView) => void;\n onClose: () => void;\n autoOpenReceive?: boolean;\n}) {\n const { useWalletSession, useEmailStatus, getClient, resolveImage, emailBanner, externalWallet } = useMediaWalletApp();\n const { address, isDeployed } = useWalletSession();\n const emailStatus = useEmailStatus();\n const router = useRouter();\n const needsEmailVerification = !!emailStatus?.email && !emailStatus.emailVerified;\n\n const balances: Record<WalletToken[\"symbol\"], ReturnType<typeof useTokenBalance>> = {\n STRK: useTokenBalance(getClient, \"STRK\", address),\n ETH: useTokenBalance(getClient, \"ETH\", address),\n USDC: useTokenBalance(getClient, \"USDC\", address),\n WBTC: useTokenBalance(getClient, \"WBTC\", address),\n };\n\n const { tokens, isLoading: loadingNfts } = useTokensByOwner(getClient, address, 1, 6);\n const nftItems = pickNftItems(tokens, 6);\n\n const usdPrices = useUsdPrices();\n const [panel, setPanel] = useState<\"receive\" | null>(autoOpenReceive ? \"receive\" : null);\n const [hideBalances, setHideBalances] = useState(false);\n const [activated, setActivated] = useState(false);\n const [pull, setPull] = useState(0);\n const startY = useRef<number | null>(null);\n const mainRef = useRef<HTMLElement>(null);\n\n useEffect(() => {\n setHideBalances(localStorage.getItem(\"mediawallet.hideBalances\") === \"1\");\n }, []);\n\n const scrollParent = () => mainRef.current?.parentElement ?? null;\n const onTouchStart = (e: React.TouchEvent) => {\n const sc = scrollParent();\n startY.current = sc && sc.scrollTop <= 0 ? e.touches[0].clientY : null;\n };\n const onTouchMove = (e: React.TouchEvent) => {\n if (startY.current == null) return;\n const dy = e.touches[0].clientY - startY.current;\n if (dy > 0) setPull(Math.min(dy * 0.5, 90));\n };\n const onTouchEnd = () => {\n setPull(0);\n startY.current = null;\n };\n\n const usd = (symbol: WalletToken[\"symbol\"]) => {\n const { rawBalance, decimals } = balances[symbol];\n return rawToNumber(rawBalance, decimals) * (usdPriceFor(usdPrices, symbol) ?? 0);\n };\n const totalUsd = WALLET_TOKENS.reduce((sum, t) => sum + usd(t.symbol), 0);\n const heldTokens = WALLET_TOKENS.filter((t) => (balances[t.symbol].rawBalance ?? 0n) > 0n);\n\n const strkBalance = balances.STRK.rawBalance;\n const funded = strkBalance != null && strkBalance > 0n;\n const canSend = isDeployed === true && funded;\n\n const goLaunch = () => {\n onClose();\n router.push(\"/launchpad\");\n };\n\n return (\n <main\n ref={mainRef}\n onTouchStart={onTouchStart}\n onTouchMove={onTouchMove}\n onTouchEnd={onTouchEnd}\n className=\"relative flex min-h-full flex-col gap-6 px-5 pb-8 pt-2\"\n style={{ transform: pull ? `translateY(${pull}px)` : undefined, transition: pull ? \"none\" : \"transform 0.2s ease\" }}\n >\n {address && (\n <div className=\"flex flex-col items-center gap-4\">\n <MediaWalletHeader address={address} onNavigate={onClose} />\n {(funded || isDeployed === false) && (\n <span className=\"font-[family-name:var(--font-display)] text-5xl font-extrabold tracking-tight tabular-nums\">\n {hideBalances ? \"••••\" : usdPrices === null ? \"…\" : fmtUsd(totalUsd)}\n </span>\n )}\n </div>\n )}\n\n {funded ? (\n <div className=\"grid grid-cols-4 gap-2\">\n <QuickAction label=\"Send\" action=\"buy\" disabled={!canSend} onClick={() => onNavigate({ name: \"send\" })} icon={<ArrowUp />} />\n <QuickAction label=\"Receive\" action=\"offer\" onClick={() => setPanel(panel === \"receive\" ? null : \"receive\")} icon={<ArrowDown />} />\n <QuickAction label=\"Launch\" action=\"remix\" onClick={goLaunch} icon={<RocketIcon />} />\n <QuickAction label=\"Activity\" action=\"submit\" onClick={() => onNavigate({ name: \"activity\" })} icon={<ActivityIcon />} />\n </div>\n ) : isDeployed === null ? (\n <div className=\"flex flex-col gap-3\">\n <div className=\"flex flex-col items-center gap-3 py-2\">\n <div className=\"h-3 w-16 animate-pulse rounded bg-foreground/[0.06]\" />\n <div className=\"h-11 w-32 animate-pulse rounded bg-foreground/[0.06]\" />\n <div className=\"h-[48px] w-40 animate-pulse rounded-[13px] bg-foreground/[0.06]\" />\n </div>\n <div className=\"h-[148px] animate-pulse rounded-[20px] bg-foreground/[0.04]\" />\n </div>\n ) : (\n isDeployed === true && (\n <div className=\"flex flex-col gap-3\">\n <div className=\"flex flex-col items-center gap-3 py-2\">\n <span className=\"text-xs font-semibold uppercase tracking-wide text-muted-foreground\">Balance</span>\n <span className=\"font-[family-name:var(--font-display)] text-5xl font-extrabold tracking-tight tabular-nums\">\n {hideBalances ? \"••••\" : usdPrices === null ? \"…\" : fmtUsd(totalUsd)}\n </span>\n <button\n onClick={() => setPanel(panel === \"receive\" ? null : \"receive\")}\n className=\"h-[48px] rounded-[13px] px-8 text-[15px] font-semibold text-white transition-transform active:scale-[0.99]\"\n style={{ background: \"linear-gradient(115deg,#3b7bff,#5b4ce6)\" }}\n >\n Fund your account\n </button>\n </div>\n <button\n onClick={goLaunch}\n className=\"flex flex-col items-center gap-2 rounded-[20px] border-2 border-dashed border-border px-6 py-8 text-center transition-colors hover:border-primary/50 active:scale-[0.99]\"\n >\n <div className=\"grid h-11 w-11 place-items-center rounded-full bg-foreground/[0.06]\">\n <RocketIcon />\n </div>\n <span className=\"text-[15px] font-semibold text-foreground\">Creator Launchpad</span>\n <span className=\"text-xs text-muted-foreground\">Protect and monetize your work</span>\n </button>\n </div>\n )\n )}\n\n {isDeployed === false && <ActivateCard onActivated={() => setActivated(true)} />}\n\n {needsEmailVerification && (\n <Link\n href={emailBanner.href}\n onClick={onClose}\n className=\"flex items-center gap-3 rounded-2xl px-4 py-3 transition-opacity hover:opacity-90\"\n style={{ background: \"linear-gradient(115deg, hsl(var(--brand-orange) / 0.12), hsl(var(--brand-maeve, 327 64% 67%) / 0.12))\" }}\n >\n <div className=\"grid h-9 w-9 shrink-0 place-items-center rounded-full bg-brand-orange/15\">\n <MailIcon />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">Verify your email</div>\n <div className=\"text-xs text-muted-foreground\">{emailBanner.text(emailStatus?.deadline)}</div>\n </div>\n </Link>\n )}\n\n {panel === \"receive\" && address && (\n <ActionModal onClose={() => setPanel(null)}>\n <ReceiveCard address={address} />\n </ActionModal>\n )}\n\n {heldTokens.length > 0 && (\n <section>\n <SectionHeader title=\"Tokens\" />\n <div className=\"mt-2 flex flex-col gap-2\">\n {heldTokens.map((t) => {\n const { rawBalance, decimals } = balances[t.symbol];\n return (\n <button\n key={t.symbol}\n onClick={() => onNavigate({ name: \"token\", token: t })}\n className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 text-left backdrop-blur-sm transition-colors hover:bg-card/60\"\n >\n <div className=\"grid h-11 w-11 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <CurrencyIcon symbol={t.symbol} size={24} />\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">{t.symbol}</div>\n <div className=\"text-xs text-muted-foreground\">{t.name}</div>\n </div>\n <div className=\"text-right\">\n <div className=\"text-sm font-semibold tabular-nums\">{hideBalances ? \"••••\" : fmt(rawBalance, decimals)}</div>\n {!hideBalances && usdPrices !== null && (\n <div className=\"text-xs text-muted-foreground tabular-nums\">{fmtUsd(usd(t.symbol))}</div>\n )}\n </div>\n </button>\n );\n })}\n </div>\n </section>\n )}\n\n {(nftItems.length > 0 || loadingNfts) && (\n <section>\n <SectionHeader title=\"NFTs\" />\n <div className=\"mt-2\">\n <NftStrip items={nftItems} isLoading={loadingNfts} onNavigate={onClose} resolveImage={resolveImage} />\n </div>\n </section>\n )}\n\n {activated && (\n <SuccessDialog\n title=\"Account activated\"\n message=\"Your account is live and ready to use\"\n onClose={() => setActivated(false)}\n />\n )}\n\n <a\n href={externalWallet.href}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"mt-auto text-center text-xs text-muted-foreground/60 transition-colors hover:text-muted-foreground\"\n >\n {externalWallet.label}\n </a>\n </main>\n );\n}\n\nfunction ArrowUp() {\n return (\n <svg width=\"19\" height=\"19\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 19V5M5 12l7-7 7 7\" />\n </svg>\n );\n}\nfunction ArrowDown() {\n return (\n <svg width=\"19\" height=\"19\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M12 5v14M19 12l-7 7-7-7\" />\n </svg>\n );\n}\nfunction ActivityIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.1\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 12h-4l-3 9L9 3l-3 9H2\" />\n </svg>\n );\n}\nfunction MailIcon() {\n return (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" className=\"text-brand-orange\">\n <rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\" />\n <path d=\"m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7\" />\n </svg>\n );\n}\nfunction RocketIcon() {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.1\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 00-2.91-.09z\" />\n <path d=\"M12 15l-3-3a22 22 0 012-3.95A12.88 12.88 0 0122 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 01-4 2z\" />\n <path d=\"M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5\" />\n </svg>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -62,22 +62,22 @@ function MediaWalletSend({
|
|
|
62
62
|
onNavigate,
|
|
63
63
|
onDone
|
|
64
64
|
}) {
|
|
65
|
-
const { useWalletSession,
|
|
65
|
+
const { useWalletSession, getClient, useWriteAction } = (0, import_types.useMediaWalletApp)();
|
|
66
66
|
const { address } = useWalletSession();
|
|
67
67
|
const { run, status, reset, error } = useWriteAction();
|
|
68
68
|
const [currency, setCurrency] = (0, import_react.useState)(initialToken ?? import_wallet_tokens.WALLET_TOKENS[0]);
|
|
69
69
|
const [pickerOpen, setPickerOpen] = (0, import_react.useState)(false);
|
|
70
|
-
const strk = (0, import_use_erc20_balance.useTokenBalance)(
|
|
71
|
-
const eth = (0, import_use_erc20_balance.useTokenBalance)(
|
|
72
|
-
const usdc = (0, import_use_erc20_balance.useTokenBalance)(
|
|
73
|
-
const wbtc = (0, import_use_erc20_balance.useTokenBalance)(
|
|
70
|
+
const strk = (0, import_use_erc20_balance.useTokenBalance)(getClient, "STRK", address);
|
|
71
|
+
const eth = (0, import_use_erc20_balance.useTokenBalance)(getClient, "ETH", address);
|
|
72
|
+
const usdc = (0, import_use_erc20_balance.useTokenBalance)(getClient, "USDC", address);
|
|
73
|
+
const wbtc = (0, import_use_erc20_balance.useTokenBalance)(getClient, "WBTC", address);
|
|
74
74
|
const pinnedBalancesBySymbol = {
|
|
75
75
|
STRK: strk.rawBalance,
|
|
76
76
|
ETH: eth.rawBalance,
|
|
77
77
|
USDC: usdc.rawBalance,
|
|
78
78
|
WBTC: wbtc.rawBalance
|
|
79
79
|
};
|
|
80
|
-
const { rawBalance: currencyBalance } = (0, import_use_erc20_balance.useErc20Balance)(
|
|
80
|
+
const { rawBalance: currencyBalance } = (0, import_use_erc20_balance.useErc20Balance)(getClient, currency.address, address);
|
|
81
81
|
const [to, setTo] = (0, import_react.useState)("");
|
|
82
82
|
const [amount, setAmount] = (0, import_react.useState)("");
|
|
83
83
|
const [txHash, setTxHash] = (0, import_react.useState)(null);
|
|
@@ -109,7 +109,7 @@ function MediaWalletSend({
|
|
|
109
109
|
setFeeError(null);
|
|
110
110
|
setFee(null);
|
|
111
111
|
setConfirmOpen(true);
|
|
112
|
-
estimateSendFee(provider, address, currency.address, to.trim(), amountRaw).then((f) => setFee({ raw: f.feeRaw, unit: f.unit })).catch((e) => setFeeError((0, import_describe_error.describeError)(e, "We couldn't estimate the network fee. Please try again.").message));
|
|
112
|
+
estimateSendFee(getClient().provider, address, currency.address, to.trim(), amountRaw).then((f) => setFee({ raw: f.feeRaw, unit: f.unit })).catch((e) => setFeeError((0, import_describe_error.describeError)(e, "We couldn't estimate the network fee. Please try again.").message));
|
|
113
113
|
};
|
|
114
114
|
const send = async () => {
|
|
115
115
|
if (!composeReady || amountRaw == null) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-send.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Account, CallData, cairo, validateAndParseAddress, type Call, type ProviderInterface } from \"starknet\";\nimport { parseAmount, formatAmount } from \"@medialane/sdk\";\nimport { ActionButton } from \"../action-button.js\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useErc20Balance, useTokenBalance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, short } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { TrustNote } from \"./action-button.js\";\nimport { ActionModal, BusyOverlay } from \"./action-modal.js\";\nimport { CurrencySheet } from \"./currency-sheet.js\";\nimport { WALLET_TOKENS, type WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { SuccessDialog } from \"./success-dialog.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { runIntentCalls } from \"../../utils/media-wallet/run-intent-calls.js\";\n\nfunction isValidStarknetAddress(address: string): boolean {\n try {\n validateAndParseAddress(address.trim());\n return true;\n } catch {\n return false;\n }\n}\n\nasync function estimateSendFee(provider: ProviderInterface, address: string, token: string, to: string, amountRaw: bigint) {\n const account = new Account({ provider, address, signer: \"0x1\", cairoVersion: \"1\" });\n const call: Call = {\n contractAddress: token,\n entrypoint: \"transfer\",\n calldata: CallData.compile({ recipient: to, amount: cairo.uint256(amountRaw) }),\n };\n const est = await account.estimateInvokeFee(call);\n return { feeRaw: est.overall_fee, unit: est.unit };\n}\n\nexport function MediaWalletSend({\n initialToken,\n onNavigate,\n onDone,\n}: {\n initialToken?: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n onDone: () => void;\n}) {\n const { useWalletSession, provider, getClient, useWriteAction } = useMediaWalletApp();\n const { address } = useWalletSession();\n const { run, status, reset, error } = useWriteAction();\n\n const [currency, setCurrency] = useState<WalletToken>(initialToken ?? WALLET_TOKENS[0]);\n const [pickerOpen, setPickerOpen] = useState(false);\n const strk = useTokenBalance(provider, \"STRK\", address);\n const eth = useTokenBalance(provider, \"ETH\", address);\n const usdc = useTokenBalance(provider, \"USDC\", address);\n const wbtc = useTokenBalance(provider, \"WBTC\", address);\n \n const pinnedBalancesBySymbol: Record<string, bigint | null> = {\n STRK: strk.rawBalance, ETH: eth.rawBalance, USDC: usdc.rawBalance, WBTC: wbtc.rawBalance,\n };\n const { rawBalance: currencyBalance } = useErc20Balance(provider, currency.address, address);\n\n const [to, setTo] = useState(\"\");\n const [amount, setAmount] = useState(\"\");\n const [txHash, setTxHash] = useState<string | null>(null);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [fee, setFee] = useState<{ raw: bigint; unit: string } | null>(null);\n const [feeError, setFeeError] = useState<string | null>(null);\n\n const recipientValid = isValidStarknetAddress(to);\n let amountRaw: bigint | null;\n try {\n amountRaw = amount.trim() ? BigInt(parseAmount(amount.trim(), currency.decimals)) : null;\n } catch {\n amountRaw = null;\n }\n const amountOverBalance = amountRaw != null && currencyBalance != null && amountRaw > currencyBalance;\n const composeReady = recipientValid && amountRaw != null && amountRaw > 0n && !amountOverBalance;\n\n const pasteRecipient = async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) setTo(text.trim());\n } catch {\n\n }\n };\n\n const setMax = () => {\n if (currencyBalance == null) return;\n setAmount(formatAmount(currencyBalance.toString(), currency.decimals));\n };\n\n const openReview = () => {\n if (!address || !composeReady || amountRaw == null) return;\n setFeeError(null);\n setFee(null);\n setConfirmOpen(true);\n estimateSendFee(provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e, \"We couldn't estimate the network fee. Please try again.\").message));\n };\n\n const send = async () => {\n if (!composeReady || amountRaw == null) return;\n setConfirmOpen(false);\n const dest = to.trim();\n const amt = amountRaw;\n await run(async (signer) => {\n const result = await runIntentCalls(signer, () =>\n getClient().api.createTransferTokenIntent({ owner: signer.address, token: currency.address, recipient: dest, amount: amt.toString() }),\n );\n setTxHash(result.txHash);\n return result;\n });\n };\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <h1 className=\"font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight\">Send</h1>\n </div>\n\n {error && (\n <div className=\"rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed\">\n <b>Something went wrong.</b> {error}\n </div>\n )}\n\n <div className=\"flex flex-col gap-3\">\n <div>\n <div className=\"flex items-center gap-2\">\n <input\n value={to}\n onChange={(e) => setTo(e.target.value)}\n placeholder=\"Recipient 0x…\"\n spellCheck={false}\n className=\"w-0 flex-1 rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 font-mono text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n {to.trim() === \"\" && (\n <button\n onClick={pasteRecipient}\n className=\"shrink-0 rounded-2xl border border-border bg-foreground/[0.05] px-3 py-3 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Paste\n </button>\n )}\n </div>\n {to.trim() !== \"\" && !recipientValid && (\n <p className=\"mt-1.5 px-1 text-xs text-destructive\">Not a valid Starknet address.</p>\n )}\n </div>\n\n <div>\n <div className=\"relative\">\n <input\n value={amount}\n onChange={(e) => setAmount(e.target.value.replace(/[^0-9.]/g, \"\"))}\n placeholder=\"0.00\"\n inputMode=\"decimal\"\n className=\"w-full rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 pr-36 text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n <div className=\"absolute right-2.5 top-1/2 flex -translate-y-1/2 items-center gap-1.5\">\n <button\n onClick={setMax}\n className=\"rounded-full bg-foreground/[0.06] px-2 py-1 text-[11px] font-bold text-muted-foreground transition-colors hover:text-foreground\"\n >\n MAX\n </button>\n <button\n onClick={() => setPickerOpen(true)}\n className=\"flex items-center gap-1.5 rounded-full bg-foreground/[0.06] px-2.5 py-1 text-xs font-semibold\"\n >\n <CurrencyIcon symbol={currency.symbol} size={16} /> {currency.symbol}\n </button>\n </div>\n </div>\n <div className=\"mt-1.5 flex items-center justify-between px-1\">\n <span className=\"text-xs text-muted-foreground\">\n Balance: {currencyBalance != null ? fmt(currencyBalance, currency.decimals) : \"…\"}\n </span>\n {amountOverBalance && <span className=\"text-xs text-destructive\">Amount exceeds balance.</span>}\n </div>\n </div>\n\n <ActionButton\n action=\"offer\"\n big\n onClick={openReview}\n disabled={status === \"processing\" || !composeReady}\n className=\"mt-1 w-full disabled:pointer-events-none disabled:opacity-40\"\n >\n Review Transfer\n </ActionButton>\n <TrustNote>Gas paid from your balance. Transfers are permanent and recorded onchain.</TrustNote>\n </div>\n\n {pickerOpen && (\n <CurrencySheet\n title=\"Choose currency\"\n tokens={WALLET_TOKENS}\n balances={pinnedBalancesBySymbol}\n onSelect={(t) => {\n setCurrency(t);\n setPickerOpen(false);\n }}\n onClose={() => setPickerOpen(false)}\n />\n )}\n\n {confirmOpen && (\n <ActionModal title=\"Review Transfer\" onClose={() => setConfirmOpen(false)}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-10 w-10 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\" />\n </svg>\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-semibold\">Send</div>\n <div className=\"truncate font-mono text-xs text-muted-foreground\">To: {short(to.trim())}</div>\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-2xl bg-foreground/[0.05] p-4\">\n <CurrencyIcon symbol={currency.symbol} size={28} />\n <div className=\"min-w-0 flex-1 font-semibold\">{currency.symbol}</div>\n <div className=\"text-right font-semibold tabular-nums\">\n −{amount.trim()} {currency.symbol}\n </div>\n </div>\n\n <div className=\"flex flex-col divide-y divide-border/40 rounded-2xl bg-foreground/[0.05] px-4\">\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Amount</span>\n <span className=\"font-medium\">{amount.trim()} {currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Recipient</span>\n <span className=\"font-mono font-medium\">{short(to.trim())}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Contract</span>\n <span className=\"font-medium\">{currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Call</span>\n <span className=\"font-medium underline\">transfer</span>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between rounded-2xl border border-border px-4 py-3 text-sm\">\n <span className=\"text-muted-foreground\">Estimated fee</span>\n <span className=\"font-medium\">\n {feeError ? \"Unavailable\" : fee ? `${fmt(fee.raw, 18, 6)} ${fee.unit === \"FRI\" ? \"STRK\" : \"ETH\"}` : \"Estimating…\"}\n </span>\n </div>\n {feeError && <p className=\"px-1 text-xs text-destructive\">Fee estimate failed: {feeError}</p>}\n\n <div className=\"flex gap-3\">\n <button\n onClick={() => setConfirmOpen(false)}\n className=\"flex-1 rounded-2xl border border-border py-3 text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Reject\n </button>\n <ActionButton action=\"offer\" big onClick={send} className=\"flex-1\">\n Confirm\n </ActionButton>\n </div>\n </div>\n </ActionModal>\n )}\n\n {status === \"processing\" && <BusyOverlay label=\"Signing & sending…\" />}\n {status === \"success\" && txHash && (\n <SuccessDialog\n title=\"Sent\"\n message={`${amount.trim()} ${currency.symbol} is on its way.`}\n txHash={txHash}\n onClose={() => {\n reset();\n onDone();\n }}\n />\n )}\n </main>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0HM;AAxHN,mBAAyB;AACzB,sBAAqG;AACrG,iBAA0C;AAC1C,2BAA6B;AAC7B,2BAA6B;AAC7B,4BAA8B;AAC9B,+BAAiD;AACjD,2BAA2B;AAC3B,yBAA2B;AAC3B,IAAAA,wBAA0B;AAC1B,0BAAyC;AACzC,4BAA8B;AAC9B,2BAAgD;AAChD,4BAA8B;AAC9B,mBAAwD;AACxD,8BAA+B;AAE/B,SAAS,uBAAuB,SAA0B;AACxD,MAAI;AACF,iDAAwB,QAAQ,KAAK,CAAC;AACtC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAe,gBAAgB,UAA6B,SAAiB,OAAe,IAAY,WAAmB;AACzH,QAAM,UAAU,IAAI,wBAAQ,EAAE,UAAU,SAAS,QAAQ,OAAO,cAAc,IAAI,CAAC;AACnF,QAAM,OAAa;AAAA,IACjB,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,UAAU,yBAAS,QAAQ,EAAE,WAAW,IAAI,QAAQ,sBAAM,QAAQ,SAAS,EAAE,CAAC;AAAA,EAChF;AACA,QAAM,MAAM,MAAM,QAAQ,kBAAkB,IAAI;AAChD,SAAO,EAAE,QAAQ,IAAI,aAAa,MAAM,IAAI,KAAK;AACnD;AAEO,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,QAAM,EAAE,kBAAkB,UAAU,WAAW,eAAe,QAAI,gCAAkB;AACpF,QAAM,EAAE,QAAQ,IAAI,iBAAiB;AACrC,QAAM,EAAE,KAAK,QAAQ,OAAO,MAAM,IAAI,eAAe;AAErD,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAsB,gBAAgB,mCAAc,CAAC,CAAC;AACtF,QAAM,CAAC,YAAY,aAAa,QAAI,uBAAS,KAAK;AAClD,QAAM,WAAO,0CAAgB,UAAU,QAAQ,OAAO;AACtD,QAAM,UAAM,0CAAgB,UAAU,OAAO,OAAO;AACpD,QAAM,WAAO,0CAAgB,UAAU,QAAQ,OAAO;AACtD,QAAM,WAAO,0CAAgB,UAAU,QAAQ,OAAO;AAEtD,QAAM,yBAAwD;AAAA,IAC5D,MAAM,KAAK;AAAA,IAAY,KAAK,IAAI;AAAA,IAAY,MAAM,KAAK;AAAA,IAAY,MAAM,KAAK;AAAA,EAChF;AACA,QAAM,EAAE,YAAY,gBAAgB,QAAI,0CAAgB,UAAU,SAAS,SAAS,OAAO;AAE3F,QAAM,CAAC,IAAI,KAAK,QAAI,uBAAS,EAAE;AAC/B,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAS,EAAE;AACvC,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAAwB,IAAI;AAExD,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AACpD,QAAM,CAAC,KAAK,MAAM,QAAI,uBAA+C,IAAI;AACzE,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAwB,IAAI;AAE5D,QAAM,iBAAiB,uBAAuB,EAAE;AAChD,MAAI;AACJ,MAAI;AACF,gBAAY,OAAO,KAAK,IAAI,WAAO,wBAAY,OAAO,KAAK,GAAG,SAAS,QAAQ,CAAC,IAAI;AAAA,EACtF,QAAQ;AACN,gBAAY;AAAA,EACd;AACA,QAAM,oBAAoB,aAAa,QAAQ,mBAAmB,QAAQ,YAAY;AACtF,QAAM,eAAe,kBAAkB,aAAa,QAAQ,YAAY,MAAM,CAAC;AAE/E,QAAM,iBAAiB,YAAY;AACjC,QAAI;AACF,YAAM,OAAO,MAAM,UAAU,UAAU,SAAS;AAChD,UAAI,KAAM,OAAM,KAAK,KAAK,CAAC;AAAA,IAC7B,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,SAAS,MAAM;AACnB,QAAI,mBAAmB,KAAM;AAC7B,kBAAU,yBAAa,gBAAgB,SAAS,GAAG,SAAS,QAAQ,CAAC;AAAA,EACvE;AAEA,QAAM,aAAa,MAAM;AACvB,QAAI,CAAC,WAAW,CAAC,gBAAgB,aAAa,KAAM;AACpD,gBAAY,IAAI;AAChB,WAAO,IAAI;AACX,mBAAe,IAAI;AACnB,oBAAgB,UAAU,SAAS,SAAS,SAAS,GAAG,KAAK,GAAG,SAAS,EACtE,KAAK,CAAC,MAAM,OAAO,EAAE,KAAK,EAAE,QAAQ,MAAM,EAAE,KAAK,CAAC,CAAC,EACnD,MAAM,CAAC,MAAM,gBAAY,qCAAc,GAAG,yDAAyD,EAAE,OAAO,CAAC;AAAA,EAClH;AAEA,QAAM,OAAO,YAAY;AACvB,QAAI,CAAC,gBAAgB,aAAa,KAAM;AACxC,mBAAe,KAAK;AACpB,UAAM,OAAO,GAAG,KAAK;AACrB,UAAM,MAAM;AACZ,UAAM,IAAI,OAAO,WAAW;AAC1B,YAAM,SAAS,UAAM;AAAA,QAAe;AAAA,QAAQ,MAC1C,UAAU,EAAE,IAAI,0BAA0B,EAAE,OAAO,OAAO,SAAS,OAAO,SAAS,SAAS,WAAW,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;AAAA,MACvI;AACA,gBAAU,OAAO,MAAM;AACvB,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SACE,6CAAC,UAAK,WAAU,sCACd;AAAA,iDAAC,SAAI,WAAU,2BACb;AAAA,kDAAC,iCAAW,QAAQ,MAAM,WAAW,EAAE,MAAM,OAAO,CAAC,GAAG;AAAA,MACxD,4CAAC,QAAG,WAAU,iFAAgF,kBAAI;AAAA,OACpG;AAAA,IAEC,SACC,6CAAC,SAAI,WAAU,0FACb;AAAA,kDAAC,OAAE,mCAAqB;AAAA,MAAI;AAAA,MAAE;AAAA,OAChC;AAAA,IAGF,6CAAC,SAAI,WAAU,uBACb;AAAA,mDAAC,SACC;AAAA,qDAAC,SAAI,WAAU,2BACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,MAAM,EAAE,OAAO,KAAK;AAAA,cACrC,aAAY;AAAA,cACZ,YAAY;AAAA,cACZ,WAAU;AAAA;AAAA,UACZ;AAAA,UACC,GAAG,KAAK,MAAM,MACb;AAAA,YAAC;AAAA;AAAA,cACC,SAAS;AAAA,cACT,WAAU;AAAA,cACX;AAAA;AAAA,UAED;AAAA,WAEJ;AAAA,QACC,GAAG,KAAK,MAAM,MAAM,CAAC,kBACpB,4CAAC,OAAE,WAAU,wCAAuC,2CAA6B;AAAA,SAErF;AAAA,MAEA,6CAAC,SACC;AAAA,qDAAC,SAAI,WAAU,YACb;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,cACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,MAAM,QAAQ,YAAY,EAAE,CAAC;AAAA,cACjE,aAAY;AAAA,cACZ,WAAU;AAAA,cACV,WAAU;AAAA;AAAA,UACZ;AAAA,UACA,6CAAC,SAAI,WAAU,yEACb;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS;AAAA,gBACT,WAAU;AAAA,gBACX;AAAA;AAAA,YAED;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS,MAAM,cAAc,IAAI;AAAA,gBACjC,WAAU;AAAA,gBAEV;AAAA,8DAAC,qCAAa,QAAQ,SAAS,QAAQ,MAAM,IAAI;AAAA,kBAAE;AAAA,kBAAE,SAAS;AAAA;AAAA;AAAA,YAChE;AAAA,aACF;AAAA,WACF;AAAA,QACA,6CAAC,SAAI,WAAU,iDACb;AAAA,uDAAC,UAAK,WAAU,iCAAgC;AAAA;AAAA,YACpC,mBAAmB,WAAO,0BAAI,iBAAiB,SAAS,QAAQ,IAAI;AAAA,aAChF;AAAA,UACC,qBAAqB,4CAAC,UAAK,WAAU,4BAA2B,qCAAuB;AAAA,WAC1F;AAAA,SACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,QAAO;AAAA,UACP,KAAG;AAAA,UACH,SAAS;AAAA,UACT,UAAU,WAAW,gBAAgB,CAAC;AAAA,UACtC,WAAU;AAAA,UACX;AAAA;AAAA,MAED;AAAA,MACA,4CAAC,mCAAU,uFAAyE;AAAA,OACtF;AAAA,IAEC,cACC;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,UAAU,CAAC,MAAM;AACf,sBAAY,CAAC;AACb,wBAAc,KAAK;AAAA,QACrB;AAAA,QACA,SAAS,MAAM,cAAc,KAAK;AAAA;AAAA,IACpC;AAAA,IAGD,eACC,4CAAC,mCAAY,OAAM,mBAAkB,SAAS,MAAM,eAAe,KAAK,GACtE,uDAAC,SAAI,WAAU,uBACb;AAAA,mDAAC,SAAI,WAAU,2BACb;AAAA,oDAAC,SAAI,WAAU,gFACb,sDAAC,SAAI,OAAM,MAAK,QAAO,MAAK,SAAQ,aAAY,MAAK,QAAO,QAAO,gBAAe,aAAY,KAAI,eAAc,SAAQ,gBAAe,SACrI,sDAAC,UAAK,GAAE,wCAAuC,GACjD,GACF;AAAA,QACA,6CAAC,SAAI,WAAU,kBACb;AAAA,sDAAC,SAAI,WAAU,iBAAgB,kBAAI;AAAA,UACnC,6CAAC,SAAI,WAAU,oDAAmD;AAAA;AAAA,gBAAK,4BAAM,GAAG,KAAK,CAAC;AAAA,aAAE;AAAA,WAC1F;AAAA,SACF;AAAA,MAEA,6CAAC,SAAI,WAAU,gEACb;AAAA,oDAAC,qCAAa,QAAQ,SAAS,QAAQ,MAAM,IAAI;AAAA,QACjD,4CAAC,SAAI,WAAU,gCAAgC,mBAAS,QAAO;AAAA,QAC/D,6CAAC,SAAI,WAAU,yCAAwC;AAAA;AAAA,UACnD,OAAO,KAAK;AAAA,UAAE;AAAA,UAAE,SAAS;AAAA,WAC7B;AAAA,SACF;AAAA,MAEA,6CAAC,SAAI,WAAU,iFACb;AAAA,qDAAC,SAAI,WAAU,kDACb;AAAA,sDAAC,UAAK,WAAU,yBAAwB,oBAAM;AAAA,UAC9C,6CAAC,UAAK,WAAU,eAAe;AAAA,mBAAO,KAAK;AAAA,YAAE;AAAA,YAAE,SAAS;AAAA,aAAO;AAAA,WACjE;AAAA,QACA,6CAAC,SAAI,WAAU,kDACb;AAAA,sDAAC,UAAK,WAAU,yBAAwB,uBAAS;AAAA,UACjD,4CAAC,UAAK,WAAU,yBAAyB,0CAAM,GAAG,KAAK,CAAC,GAAE;AAAA,WAC5D;AAAA,QACA,6CAAC,SAAI,WAAU,kDACb;AAAA,sDAAC,UAAK,WAAU,yBAAwB,sBAAQ;AAAA,UAChD,4CAAC,UAAK,WAAU,eAAe,mBAAS,QAAO;AAAA,WACjD;AAAA,QACA,6CAAC,SAAI,WAAU,kDACb;AAAA,sDAAC,UAAK,WAAU,yBAAwB,kBAAI;AAAA,UAC5C,4CAAC,UAAK,WAAU,yBAAwB,sBAAQ;AAAA,WAClD;AAAA,SACF;AAAA,MAEA,6CAAC,SAAI,WAAU,wFACb;AAAA,oDAAC,UAAK,WAAU,yBAAwB,2BAAa;AAAA,QACrD,4CAAC,UAAK,WAAU,eACb,qBAAW,gBAAgB,MAAM,OAAG,0BAAI,IAAI,KAAK,IAAI,CAAC,CAAC,IAAI,IAAI,SAAS,QAAQ,SAAS,KAAK,KAAK,oBACtG;AAAA,SACF;AAAA,MACC,YAAY,6CAAC,OAAE,WAAU,iCAAgC;AAAA;AAAA,QAAsB;AAAA,SAAS;AAAA,MAEzF,6CAAC,SAAI,WAAU,cACb;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,SAAS,MAAM,eAAe,KAAK;AAAA,YACnC,WAAU;AAAA,YACX;AAAA;AAAA,QAED;AAAA,QACA,4CAAC,qCAAa,QAAO,SAAQ,KAAG,MAAC,SAAS,MAAM,WAAU,UAAS,qBAEnE;AAAA,SACF;AAAA,OACF,GACF;AAAA,IAGD,WAAW,gBAAgB,4CAAC,mCAAY,OAAM,2BAAqB;AAAA,IACnE,WAAW,aAAa,UACvB;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,SAAS,GAAG,OAAO,KAAK,CAAC,IAAI,SAAS,MAAM;AAAA,QAC5C;AAAA,QACA,SAAS,MAAM;AACb,gBAAM;AACN,iBAAO;AAAA,QACT;AAAA;AAAA,IACF;AAAA,KAEJ;AAEJ;","names":["import_action_button"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-send.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Account, CallData, cairo, validateAndParseAddress, type Call, type ProviderInterface } from \"starknet\";\nimport { parseAmount, formatAmount } from \"@medialane/sdk\";\nimport { ActionButton } from \"../action-button.js\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useErc20Balance, useTokenBalance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, short } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { TrustNote } from \"./action-button.js\";\nimport { ActionModal, BusyOverlay } from \"./action-modal.js\";\nimport { CurrencySheet } from \"./currency-sheet.js\";\nimport { WALLET_TOKENS, type WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { SuccessDialog } from \"./success-dialog.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { runIntentCalls } from \"../../utils/media-wallet/run-intent-calls.js\";\n\nfunction isValidStarknetAddress(address: string): boolean {\n try {\n validateAndParseAddress(address.trim());\n return true;\n } catch {\n return false;\n }\n}\n\nasync function estimateSendFee(provider: ProviderInterface, address: string, token: string, to: string, amountRaw: bigint) {\n const account = new Account({ provider, address, signer: \"0x1\", cairoVersion: \"1\" });\n const call: Call = {\n contractAddress: token,\n entrypoint: \"transfer\",\n calldata: CallData.compile({ recipient: to, amount: cairo.uint256(amountRaw) }),\n };\n const est = await account.estimateInvokeFee(call);\n return { feeRaw: est.overall_fee, unit: est.unit };\n}\n\nexport function MediaWalletSend({\n initialToken,\n onNavigate,\n onDone,\n}: {\n initialToken?: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n onDone: () => void;\n}) {\n const { useWalletSession, getClient, useWriteAction } = useMediaWalletApp();\n const { address } = useWalletSession();\n const { run, status, reset, error } = useWriteAction();\n\n const [currency, setCurrency] = useState<WalletToken>(initialToken ?? WALLET_TOKENS[0]);\n const [pickerOpen, setPickerOpen] = useState(false);\n const strk = useTokenBalance(getClient, \"STRK\", address);\n const eth = useTokenBalance(getClient, \"ETH\", address);\n const usdc = useTokenBalance(getClient, \"USDC\", address);\n const wbtc = useTokenBalance(getClient, \"WBTC\", address);\n \n const pinnedBalancesBySymbol: Record<string, bigint | null> = {\n STRK: strk.rawBalance, ETH: eth.rawBalance, USDC: usdc.rawBalance, WBTC: wbtc.rawBalance,\n };\n const { rawBalance: currencyBalance } = useErc20Balance(getClient, currency.address, address);\n\n const [to, setTo] = useState(\"\");\n const [amount, setAmount] = useState(\"\");\n const [txHash, setTxHash] = useState<string | null>(null);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [fee, setFee] = useState<{ raw: bigint; unit: string } | null>(null);\n const [feeError, setFeeError] = useState<string | null>(null);\n\n const recipientValid = isValidStarknetAddress(to);\n let amountRaw: bigint | null;\n try {\n amountRaw = amount.trim() ? BigInt(parseAmount(amount.trim(), currency.decimals)) : null;\n } catch {\n amountRaw = null;\n }\n const amountOverBalance = amountRaw != null && currencyBalance != null && amountRaw > currencyBalance;\n const composeReady = recipientValid && amountRaw != null && amountRaw > 0n && !amountOverBalance;\n\n const pasteRecipient = async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) setTo(text.trim());\n } catch {\n\n }\n };\n\n const setMax = () => {\n if (currencyBalance == null) return;\n setAmount(formatAmount(currencyBalance.toString(), currency.decimals));\n };\n\n const openReview = () => {\n if (!address || !composeReady || amountRaw == null) return;\n setFeeError(null);\n setFee(null);\n setConfirmOpen(true);\n estimateSendFee(getClient().provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e, \"We couldn't estimate the network fee. Please try again.\").message));\n };\n\n const send = async () => {\n if (!composeReady || amountRaw == null) return;\n setConfirmOpen(false);\n const dest = to.trim();\n const amt = amountRaw;\n await run(async (signer) => {\n const result = await runIntentCalls(signer, () =>\n getClient().api.createTransferTokenIntent({ owner: signer.address, token: currency.address, recipient: dest, amount: amt.toString() }),\n );\n setTxHash(result.txHash);\n return result;\n });\n };\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <h1 className=\"font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight\">Send</h1>\n </div>\n\n {error && (\n <div className=\"rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed\">\n <b>Something went wrong.</b> {error}\n </div>\n )}\n\n <div className=\"flex flex-col gap-3\">\n <div>\n <div className=\"flex items-center gap-2\">\n <input\n value={to}\n onChange={(e) => setTo(e.target.value)}\n placeholder=\"Recipient 0x…\"\n spellCheck={false}\n className=\"w-0 flex-1 rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 font-mono text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n {to.trim() === \"\" && (\n <button\n onClick={pasteRecipient}\n className=\"shrink-0 rounded-2xl border border-border bg-foreground/[0.05] px-3 py-3 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Paste\n </button>\n )}\n </div>\n {to.trim() !== \"\" && !recipientValid && (\n <p className=\"mt-1.5 px-1 text-xs text-destructive\">Not a valid Starknet address.</p>\n )}\n </div>\n\n <div>\n <div className=\"relative\">\n <input\n value={amount}\n onChange={(e) => setAmount(e.target.value.replace(/[^0-9.]/g, \"\"))}\n placeholder=\"0.00\"\n inputMode=\"decimal\"\n className=\"w-full rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 pr-36 text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n <div className=\"absolute right-2.5 top-1/2 flex -translate-y-1/2 items-center gap-1.5\">\n <button\n onClick={setMax}\n className=\"rounded-full bg-foreground/[0.06] px-2 py-1 text-[11px] font-bold text-muted-foreground transition-colors hover:text-foreground\"\n >\n MAX\n </button>\n <button\n onClick={() => setPickerOpen(true)}\n className=\"flex items-center gap-1.5 rounded-full bg-foreground/[0.06] px-2.5 py-1 text-xs font-semibold\"\n >\n <CurrencyIcon symbol={currency.symbol} size={16} /> {currency.symbol}\n </button>\n </div>\n </div>\n <div className=\"mt-1.5 flex items-center justify-between px-1\">\n <span className=\"text-xs text-muted-foreground\">\n Balance: {currencyBalance != null ? fmt(currencyBalance, currency.decimals) : \"…\"}\n </span>\n {amountOverBalance && <span className=\"text-xs text-destructive\">Amount exceeds balance.</span>}\n </div>\n </div>\n\n <ActionButton\n action=\"offer\"\n big\n onClick={openReview}\n disabled={status === \"processing\" || !composeReady}\n className=\"mt-1 w-full disabled:pointer-events-none disabled:opacity-40\"\n >\n Review Transfer\n </ActionButton>\n <TrustNote>Gas paid from your balance. Transfers are permanent and recorded onchain.</TrustNote>\n </div>\n\n {pickerOpen && (\n <CurrencySheet\n title=\"Choose currency\"\n tokens={WALLET_TOKENS}\n balances={pinnedBalancesBySymbol}\n onSelect={(t) => {\n setCurrency(t);\n setPickerOpen(false);\n }}\n onClose={() => setPickerOpen(false)}\n />\n )}\n\n {confirmOpen && (\n <ActionModal title=\"Review Transfer\" onClose={() => setConfirmOpen(false)}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-10 w-10 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\" />\n </svg>\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-semibold\">Send</div>\n <div className=\"truncate font-mono text-xs text-muted-foreground\">To: {short(to.trim())}</div>\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-2xl bg-foreground/[0.05] p-4\">\n <CurrencyIcon symbol={currency.symbol} size={28} />\n <div className=\"min-w-0 flex-1 font-semibold\">{currency.symbol}</div>\n <div className=\"text-right font-semibold tabular-nums\">\n −{amount.trim()} {currency.symbol}\n </div>\n </div>\n\n <div className=\"flex flex-col divide-y divide-border/40 rounded-2xl bg-foreground/[0.05] px-4\">\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Amount</span>\n <span className=\"font-medium\">{amount.trim()} {currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Recipient</span>\n <span className=\"font-mono font-medium\">{short(to.trim())}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Contract</span>\n <span className=\"font-medium\">{currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Call</span>\n <span className=\"font-medium underline\">transfer</span>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between rounded-2xl border border-border px-4 py-3 text-sm\">\n <span className=\"text-muted-foreground\">Estimated fee</span>\n <span className=\"font-medium\">\n {feeError ? \"Unavailable\" : fee ? `${fmt(fee.raw, 18, 6)} ${fee.unit === \"FRI\" ? \"STRK\" : \"ETH\"}` : \"Estimating…\"}\n </span>\n </div>\n {feeError && <p className=\"px-1 text-xs text-destructive\">Fee estimate failed: {feeError}</p>}\n\n <div className=\"flex gap-3\">\n <button\n onClick={() => setConfirmOpen(false)}\n className=\"flex-1 rounded-2xl border border-border py-3 text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Reject\n </button>\n <ActionButton action=\"offer\" big onClick={send} className=\"flex-1\">\n Confirm\n </ActionButton>\n </div>\n </div>\n </ActionModal>\n )}\n\n {status === \"processing\" && <BusyOverlay label=\"Signing & sending…\" />}\n {status === \"success\" && txHash && (\n <SuccessDialog\n title=\"Sent\"\n message={`${amount.trim()} ${currency.symbol} is on its way.`}\n txHash={txHash}\n onClose={() => {\n reset();\n onDone();\n }}\n />\n )}\n </main>\n );\n}\n"],"mappings":"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","names":["import_action_button"]}
|
|
@@ -2,7 +2,6 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { WalletToken } from '../../utils/media-wallet/wallet-tokens.cjs';
|
|
3
3
|
import { MediaWalletView } from './types.cjs';
|
|
4
4
|
import 'react';
|
|
5
|
-
import 'starknet';
|
|
6
5
|
import '@medialane/sdk/starknet';
|
|
7
6
|
|
|
8
7
|
declare function MediaWalletSend({ initialToken, onNavigate, onDone, }: {
|
|
@@ -2,7 +2,6 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { WalletToken } from '../../utils/media-wallet/wallet-tokens.js';
|
|
3
3
|
import { MediaWalletView } from './types.js';
|
|
4
4
|
import 'react';
|
|
5
|
-
import 'starknet';
|
|
6
5
|
import '@medialane/sdk/starknet';
|
|
7
6
|
|
|
8
7
|
declare function MediaWalletSend({ initialToken, onNavigate, onDone, }: {
|
|
@@ -39,22 +39,22 @@ function MediaWalletSend({
|
|
|
39
39
|
onNavigate,
|
|
40
40
|
onDone
|
|
41
41
|
}) {
|
|
42
|
-
const { useWalletSession,
|
|
42
|
+
const { useWalletSession, getClient, useWriteAction } = useMediaWalletApp();
|
|
43
43
|
const { address } = useWalletSession();
|
|
44
44
|
const { run, status, reset, error } = useWriteAction();
|
|
45
45
|
const [currency, setCurrency] = useState(initialToken ?? WALLET_TOKENS[0]);
|
|
46
46
|
const [pickerOpen, setPickerOpen] = useState(false);
|
|
47
|
-
const strk = useTokenBalance(
|
|
48
|
-
const eth = useTokenBalance(
|
|
49
|
-
const usdc = useTokenBalance(
|
|
50
|
-
const wbtc = useTokenBalance(
|
|
47
|
+
const strk = useTokenBalance(getClient, "STRK", address);
|
|
48
|
+
const eth = useTokenBalance(getClient, "ETH", address);
|
|
49
|
+
const usdc = useTokenBalance(getClient, "USDC", address);
|
|
50
|
+
const wbtc = useTokenBalance(getClient, "WBTC", address);
|
|
51
51
|
const pinnedBalancesBySymbol = {
|
|
52
52
|
STRK: strk.rawBalance,
|
|
53
53
|
ETH: eth.rawBalance,
|
|
54
54
|
USDC: usdc.rawBalance,
|
|
55
55
|
WBTC: wbtc.rawBalance
|
|
56
56
|
};
|
|
57
|
-
const { rawBalance: currencyBalance } = useErc20Balance(
|
|
57
|
+
const { rawBalance: currencyBalance } = useErc20Balance(getClient, currency.address, address);
|
|
58
58
|
const [to, setTo] = useState("");
|
|
59
59
|
const [amount, setAmount] = useState("");
|
|
60
60
|
const [txHash, setTxHash] = useState(null);
|
|
@@ -86,7 +86,7 @@ function MediaWalletSend({
|
|
|
86
86
|
setFeeError(null);
|
|
87
87
|
setFee(null);
|
|
88
88
|
setConfirmOpen(true);
|
|
89
|
-
estimateSendFee(provider, address, currency.address, to.trim(), amountRaw).then((f) => setFee({ raw: f.feeRaw, unit: f.unit })).catch((e) => setFeeError(describeError(e, "We couldn't estimate the network fee. Please try again.").message));
|
|
89
|
+
estimateSendFee(getClient().provider, address, currency.address, to.trim(), amountRaw).then((f) => setFee({ raw: f.feeRaw, unit: f.unit })).catch((e) => setFeeError(describeError(e, "We couldn't estimate the network fee. Please try again.").message));
|
|
90
90
|
};
|
|
91
91
|
const send = async () => {
|
|
92
92
|
if (!composeReady || amountRaw == null) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-send.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Account, CallData, cairo, validateAndParseAddress, type Call, type ProviderInterface } from \"starknet\";\nimport { parseAmount, formatAmount } from \"@medialane/sdk\";\nimport { ActionButton } from \"../action-button.js\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useErc20Balance, useTokenBalance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, short } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { TrustNote } from \"./action-button.js\";\nimport { ActionModal, BusyOverlay } from \"./action-modal.js\";\nimport { CurrencySheet } from \"./currency-sheet.js\";\nimport { WALLET_TOKENS, type WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { SuccessDialog } from \"./success-dialog.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { runIntentCalls } from \"../../utils/media-wallet/run-intent-calls.js\";\n\nfunction isValidStarknetAddress(address: string): boolean {\n try {\n validateAndParseAddress(address.trim());\n return true;\n } catch {\n return false;\n }\n}\n\nasync function estimateSendFee(provider: ProviderInterface, address: string, token: string, to: string, amountRaw: bigint) {\n const account = new Account({ provider, address, signer: \"0x1\", cairoVersion: \"1\" });\n const call: Call = {\n contractAddress: token,\n entrypoint: \"transfer\",\n calldata: CallData.compile({ recipient: to, amount: cairo.uint256(amountRaw) }),\n };\n const est = await account.estimateInvokeFee(call);\n return { feeRaw: est.overall_fee, unit: est.unit };\n}\n\nexport function MediaWalletSend({\n initialToken,\n onNavigate,\n onDone,\n}: {\n initialToken?: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n onDone: () => void;\n}) {\n const { useWalletSession, provider, getClient, useWriteAction } = useMediaWalletApp();\n const { address } = useWalletSession();\n const { run, status, reset, error } = useWriteAction();\n\n const [currency, setCurrency] = useState<WalletToken>(initialToken ?? WALLET_TOKENS[0]);\n const [pickerOpen, setPickerOpen] = useState(false);\n const strk = useTokenBalance(provider, \"STRK\", address);\n const eth = useTokenBalance(provider, \"ETH\", address);\n const usdc = useTokenBalance(provider, \"USDC\", address);\n const wbtc = useTokenBalance(provider, \"WBTC\", address);\n \n const pinnedBalancesBySymbol: Record<string, bigint | null> = {\n STRK: strk.rawBalance, ETH: eth.rawBalance, USDC: usdc.rawBalance, WBTC: wbtc.rawBalance,\n };\n const { rawBalance: currencyBalance } = useErc20Balance(provider, currency.address, address);\n\n const [to, setTo] = useState(\"\");\n const [amount, setAmount] = useState(\"\");\n const [txHash, setTxHash] = useState<string | null>(null);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [fee, setFee] = useState<{ raw: bigint; unit: string } | null>(null);\n const [feeError, setFeeError] = useState<string | null>(null);\n\n const recipientValid = isValidStarknetAddress(to);\n let amountRaw: bigint | null;\n try {\n amountRaw = amount.trim() ? BigInt(parseAmount(amount.trim(), currency.decimals)) : null;\n } catch {\n amountRaw = null;\n }\n const amountOverBalance = amountRaw != null && currencyBalance != null && amountRaw > currencyBalance;\n const composeReady = recipientValid && amountRaw != null && amountRaw > 0n && !amountOverBalance;\n\n const pasteRecipient = async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) setTo(text.trim());\n } catch {\n\n }\n };\n\n const setMax = () => {\n if (currencyBalance == null) return;\n setAmount(formatAmount(currencyBalance.toString(), currency.decimals));\n };\n\n const openReview = () => {\n if (!address || !composeReady || amountRaw == null) return;\n setFeeError(null);\n setFee(null);\n setConfirmOpen(true);\n estimateSendFee(provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e, \"We couldn't estimate the network fee. Please try again.\").message));\n };\n\n const send = async () => {\n if (!composeReady || amountRaw == null) return;\n setConfirmOpen(false);\n const dest = to.trim();\n const amt = amountRaw;\n await run(async (signer) => {\n const result = await runIntentCalls(signer, () =>\n getClient().api.createTransferTokenIntent({ owner: signer.address, token: currency.address, recipient: dest, amount: amt.toString() }),\n );\n setTxHash(result.txHash);\n return result;\n });\n };\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <h1 className=\"font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight\">Send</h1>\n </div>\n\n {error && (\n <div className=\"rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed\">\n <b>Something went wrong.</b> {error}\n </div>\n )}\n\n <div className=\"flex flex-col gap-3\">\n <div>\n <div className=\"flex items-center gap-2\">\n <input\n value={to}\n onChange={(e) => setTo(e.target.value)}\n placeholder=\"Recipient 0x…\"\n spellCheck={false}\n className=\"w-0 flex-1 rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 font-mono text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n {to.trim() === \"\" && (\n <button\n onClick={pasteRecipient}\n className=\"shrink-0 rounded-2xl border border-border bg-foreground/[0.05] px-3 py-3 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Paste\n </button>\n )}\n </div>\n {to.trim() !== \"\" && !recipientValid && (\n <p className=\"mt-1.5 px-1 text-xs text-destructive\">Not a valid Starknet address.</p>\n )}\n </div>\n\n <div>\n <div className=\"relative\">\n <input\n value={amount}\n onChange={(e) => setAmount(e.target.value.replace(/[^0-9.]/g, \"\"))}\n placeholder=\"0.00\"\n inputMode=\"decimal\"\n className=\"w-full rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 pr-36 text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n <div className=\"absolute right-2.5 top-1/2 flex -translate-y-1/2 items-center gap-1.5\">\n <button\n onClick={setMax}\n className=\"rounded-full bg-foreground/[0.06] px-2 py-1 text-[11px] font-bold text-muted-foreground transition-colors hover:text-foreground\"\n >\n MAX\n </button>\n <button\n onClick={() => setPickerOpen(true)}\n className=\"flex items-center gap-1.5 rounded-full bg-foreground/[0.06] px-2.5 py-1 text-xs font-semibold\"\n >\n <CurrencyIcon symbol={currency.symbol} size={16} /> {currency.symbol}\n </button>\n </div>\n </div>\n <div className=\"mt-1.5 flex items-center justify-between px-1\">\n <span className=\"text-xs text-muted-foreground\">\n Balance: {currencyBalance != null ? fmt(currencyBalance, currency.decimals) : \"…\"}\n </span>\n {amountOverBalance && <span className=\"text-xs text-destructive\">Amount exceeds balance.</span>}\n </div>\n </div>\n\n <ActionButton\n action=\"offer\"\n big\n onClick={openReview}\n disabled={status === \"processing\" || !composeReady}\n className=\"mt-1 w-full disabled:pointer-events-none disabled:opacity-40\"\n >\n Review Transfer\n </ActionButton>\n <TrustNote>Gas paid from your balance. Transfers are permanent and recorded onchain.</TrustNote>\n </div>\n\n {pickerOpen && (\n <CurrencySheet\n title=\"Choose currency\"\n tokens={WALLET_TOKENS}\n balances={pinnedBalancesBySymbol}\n onSelect={(t) => {\n setCurrency(t);\n setPickerOpen(false);\n }}\n onClose={() => setPickerOpen(false)}\n />\n )}\n\n {confirmOpen && (\n <ActionModal title=\"Review Transfer\" onClose={() => setConfirmOpen(false)}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-10 w-10 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\" />\n </svg>\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-semibold\">Send</div>\n <div className=\"truncate font-mono text-xs text-muted-foreground\">To: {short(to.trim())}</div>\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-2xl bg-foreground/[0.05] p-4\">\n <CurrencyIcon symbol={currency.symbol} size={28} />\n <div className=\"min-w-0 flex-1 font-semibold\">{currency.symbol}</div>\n <div className=\"text-right font-semibold tabular-nums\">\n −{amount.trim()} {currency.symbol}\n </div>\n </div>\n\n <div className=\"flex flex-col divide-y divide-border/40 rounded-2xl bg-foreground/[0.05] px-4\">\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Amount</span>\n <span className=\"font-medium\">{amount.trim()} {currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Recipient</span>\n <span className=\"font-mono font-medium\">{short(to.trim())}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Contract</span>\n <span className=\"font-medium\">{currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Call</span>\n <span className=\"font-medium underline\">transfer</span>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between rounded-2xl border border-border px-4 py-3 text-sm\">\n <span className=\"text-muted-foreground\">Estimated fee</span>\n <span className=\"font-medium\">\n {feeError ? \"Unavailable\" : fee ? `${fmt(fee.raw, 18, 6)} ${fee.unit === \"FRI\" ? \"STRK\" : \"ETH\"}` : \"Estimating…\"}\n </span>\n </div>\n {feeError && <p className=\"px-1 text-xs text-destructive\">Fee estimate failed: {feeError}</p>}\n\n <div className=\"flex gap-3\">\n <button\n onClick={() => setConfirmOpen(false)}\n className=\"flex-1 rounded-2xl border border-border py-3 text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Reject\n </button>\n <ActionButton action=\"offer\" big onClick={send} className=\"flex-1\">\n Confirm\n </ActionButton>\n </div>\n </div>\n </ActionModal>\n )}\n\n {status === \"processing\" && <BusyOverlay label=\"Signing & sending…\" />}\n {status === \"success\" && txHash && (\n <SuccessDialog\n title=\"Sent\"\n message={`${amount.trim()} ${currency.symbol} is on its way.`}\n txHash={txHash}\n onClose={() => {\n reset();\n onDone();\n }}\n />\n )}\n </main>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-send.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\nimport { Account, CallData, cairo, validateAndParseAddress, type Call, type ProviderInterface } from \"starknet\";\nimport { parseAmount, formatAmount } from \"@medialane/sdk\";\nimport { ActionButton } from \"../action-button.js\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { describeError } from \"../../utils/describe-error.js\";\nimport { useErc20Balance, useTokenBalance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, short } from \"../../utils/media-wallet/wallet-format.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { TrustNote } from \"./action-button.js\";\nimport { ActionModal, BusyOverlay } from \"./action-modal.js\";\nimport { CurrencySheet } from \"./currency-sheet.js\";\nimport { WALLET_TOKENS, type WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { SuccessDialog } from \"./success-dialog.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\nimport { runIntentCalls } from \"../../utils/media-wallet/run-intent-calls.js\";\n\nfunction isValidStarknetAddress(address: string): boolean {\n try {\n validateAndParseAddress(address.trim());\n return true;\n } catch {\n return false;\n }\n}\n\nasync function estimateSendFee(provider: ProviderInterface, address: string, token: string, to: string, amountRaw: bigint) {\n const account = new Account({ provider, address, signer: \"0x1\", cairoVersion: \"1\" });\n const call: Call = {\n contractAddress: token,\n entrypoint: \"transfer\",\n calldata: CallData.compile({ recipient: to, amount: cairo.uint256(amountRaw) }),\n };\n const est = await account.estimateInvokeFee(call);\n return { feeRaw: est.overall_fee, unit: est.unit };\n}\n\nexport function MediaWalletSend({\n initialToken,\n onNavigate,\n onDone,\n}: {\n initialToken?: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n onDone: () => void;\n}) {\n const { useWalletSession, getClient, useWriteAction } = useMediaWalletApp();\n const { address } = useWalletSession();\n const { run, status, reset, error } = useWriteAction();\n\n const [currency, setCurrency] = useState<WalletToken>(initialToken ?? WALLET_TOKENS[0]);\n const [pickerOpen, setPickerOpen] = useState(false);\n const strk = useTokenBalance(getClient, \"STRK\", address);\n const eth = useTokenBalance(getClient, \"ETH\", address);\n const usdc = useTokenBalance(getClient, \"USDC\", address);\n const wbtc = useTokenBalance(getClient, \"WBTC\", address);\n \n const pinnedBalancesBySymbol: Record<string, bigint | null> = {\n STRK: strk.rawBalance, ETH: eth.rawBalance, USDC: usdc.rawBalance, WBTC: wbtc.rawBalance,\n };\n const { rawBalance: currencyBalance } = useErc20Balance(getClient, currency.address, address);\n\n const [to, setTo] = useState(\"\");\n const [amount, setAmount] = useState(\"\");\n const [txHash, setTxHash] = useState<string | null>(null);\n\n const [confirmOpen, setConfirmOpen] = useState(false);\n const [fee, setFee] = useState<{ raw: bigint; unit: string } | null>(null);\n const [feeError, setFeeError] = useState<string | null>(null);\n\n const recipientValid = isValidStarknetAddress(to);\n let amountRaw: bigint | null;\n try {\n amountRaw = amount.trim() ? BigInt(parseAmount(amount.trim(), currency.decimals)) : null;\n } catch {\n amountRaw = null;\n }\n const amountOverBalance = amountRaw != null && currencyBalance != null && amountRaw > currencyBalance;\n const composeReady = recipientValid && amountRaw != null && amountRaw > 0n && !amountOverBalance;\n\n const pasteRecipient = async () => {\n try {\n const text = await navigator.clipboard.readText();\n if (text) setTo(text.trim());\n } catch {\n\n }\n };\n\n const setMax = () => {\n if (currencyBalance == null) return;\n setAmount(formatAmount(currencyBalance.toString(), currency.decimals));\n };\n\n const openReview = () => {\n if (!address || !composeReady || amountRaw == null) return;\n setFeeError(null);\n setFee(null);\n setConfirmOpen(true);\n estimateSendFee(getClient().provider, address, currency.address, to.trim(), amountRaw)\n .then((f) => setFee({ raw: f.feeRaw, unit: f.unit }))\n .catch((e) => setFeeError(describeError(e, \"We couldn't estimate the network fee. Please try again.\").message));\n };\n\n const send = async () => {\n if (!composeReady || amountRaw == null) return;\n setConfirmOpen(false);\n const dest = to.trim();\n const amt = amountRaw;\n await run(async (signer) => {\n const result = await runIntentCalls(signer, () =>\n getClient().api.createTransferTokenIntent({ owner: signer.address, token: currency.address, recipient: dest, amount: amt.toString() }),\n );\n setTxHash(result.txHash);\n return result;\n });\n };\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <h1 className=\"font-[family-name:var(--font-display)] text-2xl font-extrabold tracking-tight\">Send</h1>\n </div>\n\n {error && (\n <div className=\"rounded-2xl border border-destructive/40 bg-destructive/10 p-3 text-xs leading-relaxed\">\n <b>Something went wrong.</b> {error}\n </div>\n )}\n\n <div className=\"flex flex-col gap-3\">\n <div>\n <div className=\"flex items-center gap-2\">\n <input\n value={to}\n onChange={(e) => setTo(e.target.value)}\n placeholder=\"Recipient 0x…\"\n spellCheck={false}\n className=\"w-0 flex-1 rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 font-mono text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n {to.trim() === \"\" && (\n <button\n onClick={pasteRecipient}\n className=\"shrink-0 rounded-2xl border border-border bg-foreground/[0.05] px-3 py-3 text-xs font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Paste\n </button>\n )}\n </div>\n {to.trim() !== \"\" && !recipientValid && (\n <p className=\"mt-1.5 px-1 text-xs text-destructive\">Not a valid Starknet address.</p>\n )}\n </div>\n\n <div>\n <div className=\"relative\">\n <input\n value={amount}\n onChange={(e) => setAmount(e.target.value.replace(/[^0-9.]/g, \"\"))}\n placeholder=\"0.00\"\n inputMode=\"decimal\"\n className=\"w-full rounded-2xl border border-border bg-foreground/[0.05] px-4 py-3 pr-36 text-sm outline-none transition-colors focus:border-brand-purple\"\n />\n <div className=\"absolute right-2.5 top-1/2 flex -translate-y-1/2 items-center gap-1.5\">\n <button\n onClick={setMax}\n className=\"rounded-full bg-foreground/[0.06] px-2 py-1 text-[11px] font-bold text-muted-foreground transition-colors hover:text-foreground\"\n >\n MAX\n </button>\n <button\n onClick={() => setPickerOpen(true)}\n className=\"flex items-center gap-1.5 rounded-full bg-foreground/[0.06] px-2.5 py-1 text-xs font-semibold\"\n >\n <CurrencyIcon symbol={currency.symbol} size={16} /> {currency.symbol}\n </button>\n </div>\n </div>\n <div className=\"mt-1.5 flex items-center justify-between px-1\">\n <span className=\"text-xs text-muted-foreground\">\n Balance: {currencyBalance != null ? fmt(currencyBalance, currency.decimals) : \"…\"}\n </span>\n {amountOverBalance && <span className=\"text-xs text-destructive\">Amount exceeds balance.</span>}\n </div>\n </div>\n\n <ActionButton\n action=\"offer\"\n big\n onClick={openReview}\n disabled={status === \"processing\" || !composeReady}\n className=\"mt-1 w-full disabled:pointer-events-none disabled:opacity-40\"\n >\n Review Transfer\n </ActionButton>\n <TrustNote>Gas paid from your balance. Transfers are permanent and recorded onchain.</TrustNote>\n </div>\n\n {pickerOpen && (\n <CurrencySheet\n title=\"Choose currency\"\n tokens={WALLET_TOKENS}\n balances={pinnedBalancesBySymbol}\n onSelect={(t) => {\n setCurrency(t);\n setPickerOpen(false);\n }}\n onClose={() => setPickerOpen(false)}\n />\n )}\n\n {confirmOpen && (\n <ActionModal title=\"Review Transfer\" onClose={() => setConfirmOpen(false)}>\n <div className=\"flex flex-col gap-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-10 w-10 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\" />\n </svg>\n </div>\n <div className=\"min-w-0 flex-1\">\n <div className=\"font-semibold\">Send</div>\n <div className=\"truncate font-mono text-xs text-muted-foreground\">To: {short(to.trim())}</div>\n </div>\n </div>\n\n <div className=\"flex items-center gap-3 rounded-2xl bg-foreground/[0.05] p-4\">\n <CurrencyIcon symbol={currency.symbol} size={28} />\n <div className=\"min-w-0 flex-1 font-semibold\">{currency.symbol}</div>\n <div className=\"text-right font-semibold tabular-nums\">\n −{amount.trim()} {currency.symbol}\n </div>\n </div>\n\n <div className=\"flex flex-col divide-y divide-border/40 rounded-2xl bg-foreground/[0.05] px-4\">\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Amount</span>\n <span className=\"font-medium\">{amount.trim()} {currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Recipient</span>\n <span className=\"font-mono font-medium\">{short(to.trim())}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Contract</span>\n <span className=\"font-medium\">{currency.symbol}</span>\n </div>\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">Call</span>\n <span className=\"font-medium underline\">transfer</span>\n </div>\n </div>\n\n <div className=\"flex items-center justify-between rounded-2xl border border-border px-4 py-3 text-sm\">\n <span className=\"text-muted-foreground\">Estimated fee</span>\n <span className=\"font-medium\">\n {feeError ? \"Unavailable\" : fee ? `${fmt(fee.raw, 18, 6)} ${fee.unit === \"FRI\" ? \"STRK\" : \"ETH\"}` : \"Estimating…\"}\n </span>\n </div>\n {feeError && <p className=\"px-1 text-xs text-destructive\">Fee estimate failed: {feeError}</p>}\n\n <div className=\"flex gap-3\">\n <button\n onClick={() => setConfirmOpen(false)}\n className=\"flex-1 rounded-2xl border border-border py-3 text-sm font-semibold text-muted-foreground transition-colors hover:text-foreground\"\n >\n Reject\n </button>\n <ActionButton action=\"offer\" big onClick={send} className=\"flex-1\">\n Confirm\n </ActionButton>\n </div>\n </div>\n </ActionModal>\n )}\n\n {status === \"processing\" && <BusyOverlay label=\"Signing & sending…\" />}\n {status === \"success\" && txHash && (\n <SuccessDialog\n title=\"Sent\"\n message={`${amount.trim()} ${currency.symbol} is on its way.`}\n txHash={txHash}\n onClose={() => {\n reset();\n onDone();\n }}\n />\n )}\n </main>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -39,9 +39,9 @@ function MediaWalletTokenDetail({
|
|
|
39
39
|
token,
|
|
40
40
|
onNavigate
|
|
41
41
|
}) {
|
|
42
|
-
const { useWalletSession,
|
|
42
|
+
const { useWalletSession, getClient, explorerUrl } = (0, import_types.useMediaWalletApp)();
|
|
43
43
|
const { address: walletAddress } = useWalletSession();
|
|
44
|
-
const { rawBalance: bal } = (0, import_use_erc20_balance.useErc20Balance)(
|
|
44
|
+
const { rawBalance: bal } = (0, import_use_erc20_balance.useErc20Balance)(getClient, token.address, walletAddress);
|
|
45
45
|
const usdPrices = (0, import_use_usd_prices.useUsdPrices)();
|
|
46
46
|
const price = (0, import_use_usd_prices.usdPriceFor)(usdPrices, token.symbol) ?? null;
|
|
47
47
|
const voyager = (0, import_react.useMemo)(() => (0, import_wallet_format.explorerTokenUrl)(explorerUrl, token.address), [explorerUrl, token.address]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-token-detail.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { ApiWalletActivity } from \"@medialane/sdk\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { normalizeAddress } from \"@medialane/sdk\";\nimport { useErc20Balance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, fmtUsd, rawToNumber, short, when, explorerTokenUrl } from \"../../utils/media-wallet/wallet-format.js\";\nimport { walletActivityTitle, walletActivitySubtitle, walletActivityAmount } from \"../../utils/media-wallet/wallet-activity.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { QuickAction } from \"./quick-action.js\";\nimport { SectionHeader } from \"./section-header.js\";\nimport { WalletActivityIcon } from \"./wallet-activity-icon.js\";\nimport { useUsdPrices, usdPriceFor } from \"../../utils/use-usd-prices.js\";\nimport type { WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\n\nexport function MediaWalletTokenDetail({\n token,\n onNavigate,\n}: {\n token: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n}) {\n const { useWalletSession, provider, explorerUrl } = useMediaWalletApp();\n const { address: walletAddress } = useWalletSession();\n const { rawBalance: bal } = useErc20Balance(provider, token.address, walletAddress);\n const usdPrices = useUsdPrices();\n const price = usdPriceFor(usdPrices, token.symbol) ?? null;\n\n const voyager = useMemo(() => explorerTokenUrl(explorerUrl, token.address), [explorerUrl, token.address]);\n const heldValue = bal != null && price != null ? rawToNumber(bal, token.decimals) * price : null;\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-11 w-11 shrink-0 place-items-center overflow-hidden rounded-full bg-foreground/[0.06]\">\n <CurrencyIcon symbol={token.symbol} size={26} />\n </div>\n <div>\n <div className=\"font-[family-name:var(--font-display)] text-lg font-bold leading-none\">{token.name}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{token.symbol}</div>\n </div>\n </div>\n </div>\n\n <section className=\"py-2 text-center\">\n <div className=\"font-[family-name:var(--font-display)] text-5xl font-extrabold tracking-tight tabular-nums\">\n {bal === undefined ? \"…\" : bal === null ? \"—\" : fmt(bal, token.decimals, 6)}\n </div>\n <div className=\"mt-2 text-sm text-muted-foreground\">\n {token.symbol}\n {\" · \"}\n {heldValue != null ? fmtUsd(heldValue) : \"—\"}\n </div>\n {price != null && <div className=\"mt-0.5 text-xs text-muted-foreground\">{fmtUsd(price)} per {token.symbol}</div>}\n </section>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <QuickAction\n label=\"Send\"\n action=\"offer\"\n onClick={() => onNavigate({ name: \"send\", token })}\n icon={<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M12 19V5M5 12l7-7 7 7\" /></svg>}\n />\n <QuickAction\n label=\"Receive\"\n action=\"buy\"\n onClick={() => onNavigate({ name: \"home\" })}\n icon={<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M12 5v14M19 12l-7 7-7-7\" /></svg>}\n />\n </div>\n\n <TokenActivity tokenAddress={token.address} walletAddress={walletAddress} />\n\n <section>\n <SectionHeader title=\"Details\" />\n <div className=\"mt-2 flex flex-col divide-y divide-border/40 rounded-2xl bg-card/40 px-4 backdrop-blur-sm\">\n <InfoRow\n label=\"Network\"\n value={\n <span className=\"flex items-center gap-2\">\n <span className=\"grid h-6 w-6 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <CurrencyIcon symbol=\"STRK\" size={14} />\n </span>\n Starknet\n </span>\n }\n />\n <InfoRow label=\"Standard\" value=\"ERC-20\" />\n <InfoRow\n label=\"Contract\"\n value={\n <a href={voyager} target=\"_blank\" rel=\"noopener noreferrer\" className=\"font-mono text-brand-blue hover:underline\">\n {short(token.address)} ↗\n </a>\n }\n />\n </div>\n </section>\n </main>\n );\n}\n\nfunction TokenActivity({ tokenAddress, walletAddress }: { tokenAddress: string; walletAddress: string | null }) {\n const { getClient } = useMediaWalletApp();\n const [items, setItems] = useState<ApiWalletActivity[] | null>(null);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n if (!walletAddress) return;\n const normalizedToken = normalizeAddress(\"STARKNET\", tokenAddress);\n getClient()\n .api.getWalletActivity(walletAddress)\n .then((res) => {\n const filtered = res.data\n .filter((a) => (a.type === \"SEND\" || a.type === \"RECEIVE\") && a.tokenAddress && normalizeAddress(\"STARKNET\", a.tokenAddress) === normalizedToken)\n .slice(0, 5);\n setItems(filtered);\n })\n .catch(() => setError(true));\n }, [walletAddress, tokenAddress, getClient]);\n\n if (error || (items && items.length === 0)) return null;\n\n return (\n <section>\n <SectionHeader title=\"Activity\" />\n <div className=\"mt-2\">\n {items === null ? (\n <div className=\"flex flex-col gap-2\">\n {[0, 1].map((i) => (\n <div key={i} className=\"h-16 animate-pulse rounded-2xl bg-foreground/[0.04]\" />\n ))}\n </div>\n ) : (\n <div className=\"flex flex-col gap-2\">\n {items.map((a) => {\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n return (\n <div key={a.id} className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 backdrop-blur-sm\">\n <WalletActivityIcon a={a} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">{walletActivityTitle(a)}</div>\n {subtitle && <div className=\"truncate text-xs text-muted-foreground\">{subtitle}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {amount && <div className=\"text-sm font-semibold tabular-nums\">{amount}</div>}\n <div className=\"text-xs text-muted-foreground\">{when(a.timestamp)}</div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n </section>\n );\n}\n\nfunction InfoRow({ label, value }: { label: string; value: React.ReactNode }) {\n return (\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">{label}</span>\n <span className=\"font-medium\">{value}</span>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/media-wallet/media-wallet-token-detail.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport type { ApiWalletActivity } from \"@medialane/sdk\";\nimport { CurrencyIcon } from \"../currency-icon.js\";\nimport { normalizeAddress } from \"@medialane/sdk\";\nimport { useErc20Balance } from \"../../utils/media-wallet/use-erc20-balance.js\";\nimport { fmt, fmtUsd, rawToNumber, short, when, explorerTokenUrl } from \"../../utils/media-wallet/wallet-format.js\";\nimport { walletActivityTitle, walletActivitySubtitle, walletActivityAmount } from \"../../utils/media-wallet/wallet-activity.js\";\nimport { BackButton } from \"./back-button.js\";\nimport { QuickAction } from \"./quick-action.js\";\nimport { SectionHeader } from \"./section-header.js\";\nimport { WalletActivityIcon } from \"./wallet-activity-icon.js\";\nimport { useUsdPrices, usdPriceFor } from \"../../utils/use-usd-prices.js\";\nimport type { WalletToken } from \"../../utils/media-wallet/wallet-tokens.js\";\nimport { useMediaWalletApp, type MediaWalletView } from \"./types.js\";\n\nexport function MediaWalletTokenDetail({\n token,\n onNavigate,\n}: {\n token: WalletToken;\n onNavigate: (view: MediaWalletView) => void;\n}) {\n const { useWalletSession, getClient, explorerUrl } = useMediaWalletApp();\n const { address: walletAddress } = useWalletSession();\n const { rawBalance: bal } = useErc20Balance(getClient, token.address, walletAddress);\n const usdPrices = useUsdPrices();\n const price = usdPriceFor(usdPrices, token.symbol) ?? null;\n\n const voyager = useMemo(() => explorerTokenUrl(explorerUrl, token.address), [explorerUrl, token.address]);\n const heldValue = bal != null && price != null ? rawToNumber(bal, token.decimals) * price : null;\n\n return (\n <main className=\"flex flex-col gap-6 px-5 pb-8 pt-2\">\n <div className=\"flex items-center gap-3\">\n <BackButton onBack={() => onNavigate({ name: \"home\" })} />\n <div className=\"flex items-center gap-3\">\n <div className=\"grid h-11 w-11 shrink-0 place-items-center overflow-hidden rounded-full bg-foreground/[0.06]\">\n <CurrencyIcon symbol={token.symbol} size={26} />\n </div>\n <div>\n <div className=\"font-[family-name:var(--font-display)] text-lg font-bold leading-none\">{token.name}</div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">{token.symbol}</div>\n </div>\n </div>\n </div>\n\n <section className=\"py-2 text-center\">\n <div className=\"font-[family-name:var(--font-display)] text-5xl font-extrabold tracking-tight tabular-nums\">\n {bal === undefined ? \"…\" : bal === null ? \"—\" : fmt(bal, token.decimals, 6)}\n </div>\n <div className=\"mt-2 text-sm text-muted-foreground\">\n {token.symbol}\n {\" · \"}\n {heldValue != null ? fmtUsd(heldValue) : \"—\"}\n </div>\n {price != null && <div className=\"mt-0.5 text-xs text-muted-foreground\">{fmtUsd(price)} per {token.symbol}</div>}\n </section>\n\n <div className=\"grid grid-cols-2 gap-2\">\n <QuickAction\n label=\"Send\"\n action=\"offer\"\n onClick={() => onNavigate({ name: \"send\", token })}\n icon={<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M12 19V5M5 12l7-7 7 7\" /></svg>}\n />\n <QuickAction\n label=\"Receive\"\n action=\"buy\"\n onClick={() => onNavigate({ name: \"home\" })}\n icon={<svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.3\" strokeLinecap=\"round\" strokeLinejoin=\"round\"><path d=\"M12 5v14M19 12l-7 7-7-7\" /></svg>}\n />\n </div>\n\n <TokenActivity tokenAddress={token.address} walletAddress={walletAddress} />\n\n <section>\n <SectionHeader title=\"Details\" />\n <div className=\"mt-2 flex flex-col divide-y divide-border/40 rounded-2xl bg-card/40 px-4 backdrop-blur-sm\">\n <InfoRow\n label=\"Network\"\n value={\n <span className=\"flex items-center gap-2\">\n <span className=\"grid h-6 w-6 shrink-0 place-items-center rounded-full bg-foreground/[0.06]\">\n <CurrencyIcon symbol=\"STRK\" size={14} />\n </span>\n Starknet\n </span>\n }\n />\n <InfoRow label=\"Standard\" value=\"ERC-20\" />\n <InfoRow\n label=\"Contract\"\n value={\n <a href={voyager} target=\"_blank\" rel=\"noopener noreferrer\" className=\"font-mono text-brand-blue hover:underline\">\n {short(token.address)} ↗\n </a>\n }\n />\n </div>\n </section>\n </main>\n );\n}\n\nfunction TokenActivity({ tokenAddress, walletAddress }: { tokenAddress: string; walletAddress: string | null }) {\n const { getClient } = useMediaWalletApp();\n const [items, setItems] = useState<ApiWalletActivity[] | null>(null);\n const [error, setError] = useState(false);\n\n useEffect(() => {\n if (!walletAddress) return;\n const normalizedToken = normalizeAddress(\"STARKNET\", tokenAddress);\n getClient()\n .api.getWalletActivity(walletAddress)\n .then((res) => {\n const filtered = res.data\n .filter((a) => (a.type === \"SEND\" || a.type === \"RECEIVE\") && a.tokenAddress && normalizeAddress(\"STARKNET\", a.tokenAddress) === normalizedToken)\n .slice(0, 5);\n setItems(filtered);\n })\n .catch(() => setError(true));\n }, [walletAddress, tokenAddress, getClient]);\n\n if (error || (items && items.length === 0)) return null;\n\n return (\n <section>\n <SectionHeader title=\"Activity\" />\n <div className=\"mt-2\">\n {items === null ? (\n <div className=\"flex flex-col gap-2\">\n {[0, 1].map((i) => (\n <div key={i} className=\"h-16 animate-pulse rounded-2xl bg-foreground/[0.04]\" />\n ))}\n </div>\n ) : (\n <div className=\"flex flex-col gap-2\">\n {items.map((a) => {\n const subtitle = walletActivitySubtitle(a);\n const amount = walletActivityAmount(a);\n return (\n <div key={a.id} className=\"flex items-center gap-3 rounded-2xl bg-card/40 px-4 py-3 backdrop-blur-sm\">\n <WalletActivityIcon a={a} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"text-sm font-semibold\">{walletActivityTitle(a)}</div>\n {subtitle && <div className=\"truncate text-xs text-muted-foreground\">{subtitle}</div>}\n </div>\n <div className=\"shrink-0 text-right\">\n {amount && <div className=\"text-sm font-semibold tabular-nums\">{amount}</div>}\n <div className=\"text-xs text-muted-foreground\">{when(a.timestamp)}</div>\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n </section>\n );\n}\n\nfunction InfoRow({ label, value }: { label: string; value: React.ReactNode }) {\n return (\n <div className=\"flex items-center justify-between py-3 text-sm\">\n <span className=\"text-muted-foreground\">{label}</span>\n <span className=\"font-medium\">{value}</span>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,6 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { WalletToken } from '../../utils/media-wallet/wallet-tokens.cjs';
|
|
3
3
|
import { MediaWalletView } from './types.cjs';
|
|
4
4
|
import 'react';
|
|
5
|
-
import 'starknet';
|
|
6
5
|
import '@medialane/sdk/starknet';
|
|
7
6
|
|
|
8
7
|
declare function MediaWalletTokenDetail({ token, onNavigate, }: {
|
|
@@ -2,7 +2,6 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
|
2
2
|
import { WalletToken } from '../../utils/media-wallet/wallet-tokens.js';
|
|
3
3
|
import { MediaWalletView } from './types.js';
|
|
4
4
|
import 'react';
|
|
5
|
-
import 'starknet';
|
|
6
5
|
import '@medialane/sdk/starknet';
|
|
7
6
|
|
|
8
7
|
declare function MediaWalletTokenDetail({ token, onNavigate, }: {
|
|
@@ -16,9 +16,9 @@ function MediaWalletTokenDetail({
|
|
|
16
16
|
token,
|
|
17
17
|
onNavigate
|
|
18
18
|
}) {
|
|
19
|
-
const { useWalletSession,
|
|
19
|
+
const { useWalletSession, getClient, explorerUrl } = useMediaWalletApp();
|
|
20
20
|
const { address: walletAddress } = useWalletSession();
|
|
21
|
-
const { rawBalance: bal } = useErc20Balance(
|
|
21
|
+
const { rawBalance: bal } = useErc20Balance(getClient, token.address, walletAddress);
|
|
22
22
|
const usdPrices = useUsdPrices();
|
|
23
23
|
const price = usdPriceFor(usdPrices, token.symbol) ?? null;
|
|
24
24
|
const voyager = useMemo(() => explorerTokenUrl(explorerUrl, token.address), [explorerUrl, token.address]);
|