Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const STAKING_CONTRACT = "0xEf80AafFbf4cF5c8a5e1D4c61838987D5973DAab";
type DepositType = "simple" | "contract" | "hyperliquid" | "eth-base";

export function CustomDepositButton() {
const { address } = useAccountWallet();
const { address = "0x0000000000000000000000000000000000000000" } = useAccountWallet();
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Providing a default value for address here makes it a truthy string (the zero address) even when no user is signed in. This causes the check !address on line 126 to always evaluate to false, preventing the 'Please sign in' message from being displayed. A similar issue exists in the new FixedAmountDepositButton component. To fix this, the condition on line 126 should be changed to check for the zero address, for example: address === '0x0000000000000000000000000000000000000000'. It would be best to import and use the ZERO_ADDRESS constant for both the default value and the check.

const [isModalOpen, setIsModalOpen] = useState(false);
const [depositType, setDepositType] = useState<DepositType>("simple");

Expand All @@ -70,7 +70,7 @@ export function CustomDepositButton() {
const customExactInConfig = {
functionAbi: STAKE_FOR_FUNCTION_ABI,
functionName: "stakeFor",
functionArgs: [normalizeAddress(address || ""), "{{amount_out}}"],
functionArgs: [normalizeAddress(address), "{{amount_out}}"],
to: STAKING_CONTRACT,
spenderAddress: STAKING_CONTRACT,
action: `stake USDC`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"use client";

import { AnySpendDeposit } from "@b3dotfun/sdk/anyspend/react";
import { useAccountWallet } from "@b3dotfun/sdk/global-account/react";
import { useState } from "react";
import { parseUnits } from "viem";
import { base } from "viem/chains";

// USDC on Base (6 decimals)
const USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";

export function FixedAmountDepositButton() {
const { address = "0x0000000000000000000000000000000000000000" } = useAccountWallet();
const [isModalOpen, setIsModalOpen] = useState(false);

const handleClose = () => setIsModalOpen(false);

const handleSuccess = (amount: string) => {
console.log(`Fixed amount deposit successful! Amount: ${amount}`);
handleClose();
};

// Fixed amount: 10 USDC (in wei/smallest unit)
const fixedAmount = parseUnits("10", 6).toString();

return (
<>
<button
onClick={() => setIsModalOpen(true)}
className="group flex h-40 w-full flex-col justify-between overflow-hidden rounded-lg border border-gray-100 bg-white p-6 text-left shadow-sm transition-all hover:border-green-100 hover:shadow-md"
>
<div>
<h3 className="text-lg font-medium text-gray-900">Fixed Amount Deposit</h3>
<p className="mt-1 text-sm text-gray-500">Deposit exactly 10 USDC with locked amount inputs</p>
</div>
<div className="flex items-center gap-2">
<span className="rounded-full bg-green-100 px-2 py-1 text-xs font-medium text-green-700">Fixed Amount</span>
<span className="rounded-full bg-blue-100 px-2 py-1 text-xs font-medium text-blue-700">10 USDC</span>
</div>
</button>

{isModalOpen && (
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50">
<div className="relative w-full max-w-md overflow-y-auto overflow-x-hidden rounded-2xl bg-white shadow-xl">
{!address ? (
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Since address is given a default value of the zero address on line 13, this check !address will always evaluate to false. To correctly check if a user is not signed in, you should compare address to the zero address. It's also a good practice to import and use the ZERO_ADDRESS constant for this check and the default value.

Suggested change
{!address ? (
{address === "0x0000000000000000000000000000000000000000" ? (

<div className="relative p-6">
<button onClick={handleClose} className="absolute right-4 top-4 text-gray-400 hover:text-gray-600">
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
<div className="rounded-lg bg-yellow-50 p-4 text-center">
<p className="text-yellow-800">Please sign in first to use the deposit feature.</p>
</div>
</div>
) : (
<AnySpendDeposit
mode="modal"
recipientAddress={address}
destinationTokenAddress={USDC_ADDRESS}
destinationTokenChainId={base.id}
destinationTokenAmount={fixedAmount}
onSuccess={handleSuccess}
onClose={handleClose}
allowDirectTransfer
/>
)}
</div>
</div>
)}
</>
);
}
2 changes: 2 additions & 0 deletions apps/anyspend-demo-nextjs/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { CollectorClubPurchaseButton } from "./components/CollectorClubPurchaseB
import { CustomClassesDepositButton } from "./components/CustomClassesDepositButton";
import { CustomDepositButton } from "./components/CustomDepositButton";
import { DepositHypeButton } from "./components/DepositHypeButton";
import { FixedAmountDepositButton } from "./components/FixedAmountDepositButton";
import { GetB3TokenButton } from "./components/GetB3TokenButton";
import { MintNftButton } from "./components/MintNftButton";
import { OrderDetailsButton } from "./components/OrderDetailsButton";
Expand Down Expand Up @@ -61,6 +62,7 @@ export default function Home() {
<CollectorClubPurchaseButton />
<OrderDetailsButton />
<CustomClassesDepositButton />
<FixedAmountDepositButton />
</div>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/src/anyspend/react/components/AnySpend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1215,6 +1215,7 @@ function AnySpendInner({
onTokenSelect={onTokenSelect}
onShowFeeDetail={() => navigateToPanel(PanelView.FEE_DETAIL, "forward")}
skipAutoMaxOnTokenChange={!!destinationTokenAmount}
disableAmountInput={!!destinationTokenAmount}
/>
) : (
<motion.div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,6 +419,7 @@ function AnySpendCustomExactInInner({
anyspendQuote={anyspendQuote}
onTokenSelect={onTokenSelect}
skipAutoMaxOnTokenChange={!!destinationTokenAmount}
disableAmountInput={!!destinationTokenAmount}
/>
) : (
<motion.div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ interface CryptoPaySectionProps {
classes?: CryptoPaySectionClasses;
/** When true, skip auto-setting max balance when token changes (used for fixed destination amount mode) */
skipAutoMaxOnTokenChange?: boolean;
/** When true, disables the source amount input and hides the MAX button (used for fixed destination amount mode) */
disableAmountInput?: boolean;
}

export function CryptoPaySection({
Expand All @@ -52,6 +54,7 @@ export function CryptoPaySection({
onShowFeeDetail,
classes,
skipAutoMaxOnTokenChange = false,
disableAmountInput = false,
}: CryptoPaySectionProps) {
const { data: srcTokenMetadata } = useTokenData(selectedSrcToken?.chainId, selectedSrcToken?.address);

Expand Down Expand Up @@ -138,6 +141,7 @@ export function CryptoPaySection({
setToken={setSelectedSrcToken}
onTokenSelect={onTokenSelect}
skipAutoMaxOnTokenChange={skipAutoMaxOnTokenChange}
disabled={disableAmountInput}
/>
</div>
<div className={classes?.balanceRow || "flex items-center justify-between"}>
Expand All @@ -154,6 +158,7 @@ export function CryptoPaySection({
setIsSrcInputDirty(true);
setSrcAmount(value);
}}
hideMaxButton={disableAmountInput}
/>
</div>
</motion.div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ export function TokenBalance({
token,
walletAddress,
onChangeInput,
hideMaxButton = false,
}: {
token: components["schemas"]["Token"];
walletAddress: string | undefined;
onChangeInput: (value: string) => void;
hideMaxButton?: boolean;
}) {
const tokenAddress = isNativeToken(token.address) ? "native" : token.address;
const { data, isLoading } = useSimTokenBalance(walletAddress, tokenAddress, token.chainId);
Expand Down Expand Up @@ -62,7 +64,7 @@ export function TokenBalance({
{rawBalance ? `Balance: ${formattedBalance}` : `Balance: 0`}
</div>

{!!rawBalance && (
{!!rawBalance && !hideMaxButton && (
<>
{/* <button
onClick={() => handlePercentageClick(20)}
Expand Down
Loading