@b3dotfun/sdk 0.0.63-test.0 → 0.0.63
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/cjs/anyspend/react/components/AnySpendCustomExactIn.d.ts +34 -0
- package/dist/cjs/anyspend/react/components/AnySpendCustomExactIn.js +275 -0
- package/dist/cjs/anyspend/react/components/AnySpendStakeB3ExactIn.d.ts +9 -0
- package/dist/cjs/anyspend/react/components/AnySpendStakeB3ExactIn.js +288 -0
- package/dist/cjs/anyspend/react/components/AnySpendStakeUpsideExactIn.d.ts +11 -0
- package/dist/cjs/anyspend/react/components/AnySpendStakeUpsideExactIn.js +33 -0
- package/dist/cjs/anyspend/react/components/common/OrderDetails.js +10 -2
- package/dist/cjs/anyspend/react/components/common/OrderDetailsCollapsible.js +2 -3
- package/dist/cjs/anyspend/react/components/index.d.ts +5 -1
- package/dist/cjs/anyspend/react/components/index.js +11 -3
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.d.ts +25 -3
- package/dist/cjs/anyspend/react/hooks/useAnyspendFlow.js +30 -8
- package/dist/cjs/anyspend/react/hooks/useAnyspendOrderHistory.d.ts +116 -0
- package/dist/cjs/anyspend/react/hooks/useAnyspendQuote.js +1 -1
- package/dist/cjs/anyspend/types/api.d.ts +665 -3
- package/dist/cjs/anyspend/utils/orderPayload.js +4 -0
- package/dist/cjs/global-account/react/components/B3DynamicModal.js +10 -1
- package/dist/cjs/global-account/react/components/SignInWithB3/steps/LoginStep.js +2 -2
- package/dist/cjs/global-account/react/hooks/useAuthentication.d.ts +2 -2
- package/dist/cjs/global-account/react/hooks/useAuthentication.js +7 -2
- package/dist/cjs/global-account/react/stores/useModalStore.d.ts +31 -1
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.d.ts +34 -0
- package/dist/esm/anyspend/react/components/AnySpendCustomExactIn.js +269 -0
- package/dist/esm/anyspend/react/components/AnySpendStakeB3ExactIn.d.ts +9 -0
- package/dist/esm/anyspend/react/components/AnySpendStakeB3ExactIn.js +285 -0
- package/dist/esm/anyspend/react/components/AnySpendStakeUpsideExactIn.d.ts +11 -0
- package/dist/esm/anyspend/react/components/AnySpendStakeUpsideExactIn.js +30 -0
- package/dist/esm/anyspend/react/components/common/OrderDetails.js +10 -2
- package/dist/esm/anyspend/react/components/common/OrderDetailsCollapsible.js +2 -3
- package/dist/esm/anyspend/react/components/index.d.ts +5 -1
- package/dist/esm/anyspend/react/components/index.js +5 -1
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.d.ts +25 -3
- package/dist/esm/anyspend/react/hooks/useAnyspendFlow.js +30 -8
- package/dist/esm/anyspend/react/hooks/useAnyspendOrderHistory.d.ts +116 -0
- package/dist/esm/anyspend/react/hooks/useAnyspendQuote.js +1 -1
- package/dist/esm/anyspend/types/api.d.ts +665 -3
- package/dist/esm/anyspend/utils/orderPayload.js +4 -0
- package/dist/esm/global-account/react/components/B3DynamicModal.js +11 -2
- package/dist/esm/global-account/react/components/SignInWithB3/steps/LoginStep.js +2 -2
- package/dist/esm/global-account/react/hooks/useAuthentication.d.ts +2 -2
- package/dist/esm/global-account/react/hooks/useAuthentication.js +7 -2
- package/dist/esm/global-account/react/stores/useModalStore.d.ts +31 -1
- package/dist/types/anyspend/react/components/AnySpendCustomExactIn.d.ts +34 -0
- package/dist/types/anyspend/react/components/AnySpendStakeB3ExactIn.d.ts +9 -0
- package/dist/types/anyspend/react/components/AnySpendStakeUpsideExactIn.d.ts +11 -0
- package/dist/types/anyspend/react/components/index.d.ts +5 -1
- package/dist/types/anyspend/react/hooks/useAnyspendFlow.d.ts +25 -3
- package/dist/types/anyspend/react/hooks/useAnyspendOrderHistory.d.ts +116 -0
- package/dist/types/anyspend/types/api.d.ts +665 -3
- package/dist/types/global-account/react/hooks/useAuthentication.d.ts +2 -2
- package/dist/types/global-account/react/stores/useModalStore.d.ts +31 -1
- package/package.json +3 -3
- package/src/anyspend/react/components/AnySpendCustomExactIn.tsx +595 -0
- package/src/anyspend/react/components/AnySpendStakeB3ExactIn.tsx +522 -0
- package/src/anyspend/react/components/AnySpendStakeUpsideExactIn.tsx +73 -0
- package/src/anyspend/react/components/common/OrderDetails.tsx +10 -2
- package/src/anyspend/react/components/common/OrderDetailsCollapsible.tsx +2 -3
- package/src/anyspend/react/components/index.ts +5 -1
- package/src/anyspend/react/hooks/useAnyspendFlow.ts +38 -8
- package/src/anyspend/react/hooks/useAnyspendQuote.ts +1 -1
- package/src/anyspend/types/api.ts +669 -1
- package/src/anyspend/utils/orderPayload.ts +5 -1
- package/src/global-account/react/components/B3DynamicModal.tsx +11 -1
- package/src/global-account/react/components/SignInWithB3/steps/LoginStep.tsx +2 -2
- package/src/global-account/react/hooks/useAuthentication.ts +10 -2
- package/src/global-account/react/stores/useModalStore.ts +34 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { ABI_ERC20_STAKING, B3_TOKEN, eqci } from "../../../anyspend/index.js";
|
|
3
|
+
import { normalizeAddress } from "../../../anyspend/utils/index.js";
|
|
4
|
+
import { Button, GlareCardRounded, Input, StyleRoot, TextLoop, useHasMounted, useModalStore, useSimBalance, useUnifiedChainSwitchAndExecute, } from "../../../global-account/react/index.js";
|
|
5
|
+
import { PUBLIC_BASE_RPC_URL } from "../../../shared/constants/index.js";
|
|
6
|
+
import { formatTokenAmount } from "../../../shared/utils/number.js";
|
|
7
|
+
import { ArrowRight, Loader2 } from "lucide-react";
|
|
8
|
+
import { motion } from "motion/react";
|
|
9
|
+
import { useEffect, useState } from "react";
|
|
10
|
+
import { toast } from "sonner";
|
|
11
|
+
import { createPublicClient, encodeFunctionData, erc20Abi, http } from "viem";
|
|
12
|
+
import { base } from "viem/chains";
|
|
13
|
+
import { useAccount, useWaitForTransactionReceipt } from "wagmi";
|
|
14
|
+
import { AnySpendCustomExactIn } from "./AnySpendCustomExactIn.js";
|
|
15
|
+
import { EthIcon } from "./icons/EthIcon.js";
|
|
16
|
+
import { SolIcon } from "./icons/SolIcon.js";
|
|
17
|
+
import { UsdcIcon } from "./icons/USDCIcon.js";
|
|
18
|
+
const basePublicClient = createPublicClient({
|
|
19
|
+
chain: base,
|
|
20
|
+
transport: http(PUBLIC_BASE_RPC_URL),
|
|
21
|
+
});
|
|
22
|
+
const ERC20Staking = "0xbf04200be3cbf371467a539706393c81c470f523";
|
|
23
|
+
const STAKE_FUNCTION_ABI = JSON.stringify([
|
|
24
|
+
{
|
|
25
|
+
name: "stake",
|
|
26
|
+
type: "function",
|
|
27
|
+
stateMutability: "nonpayable",
|
|
28
|
+
inputs: [
|
|
29
|
+
{ name: "amount", type: "uint256" },
|
|
30
|
+
{ name: "beneficiary", type: "address" },
|
|
31
|
+
],
|
|
32
|
+
outputs: [],
|
|
33
|
+
},
|
|
34
|
+
]);
|
|
35
|
+
export function AnySpendStakeB3ExactIn({ loadOrder, mode = "modal", sourceTokenAddress, sourceTokenChainId, recipientAddress, stakeAmount, onSuccess, }) {
|
|
36
|
+
const hasMounted = useHasMounted();
|
|
37
|
+
const { setB3ModalOpen } = useModalStore();
|
|
38
|
+
// Wagmi hooks for direct staking
|
|
39
|
+
const { address } = useAccount();
|
|
40
|
+
const { switchChainAndExecute, isSwitchingOrExecuting } = useUnifiedChainSwitchAndExecute();
|
|
41
|
+
// Fetch B3 token balance
|
|
42
|
+
const { data: simBalance, isLoading: isBalanceLoading } = useSimBalance(address, [base.id]);
|
|
43
|
+
const b3RawBalanceStr = simBalance?.balances.find(b => eqci(b.address, B3_TOKEN.address))?.amount || "0";
|
|
44
|
+
const b3RawBalance = BigInt(b3RawBalanceStr);
|
|
45
|
+
const b3Balance = formatTokenAmount(b3RawBalance, B3_TOKEN.decimals);
|
|
46
|
+
// State for direct staking flow
|
|
47
|
+
const [isStaking, setIsStaking] = useState(false);
|
|
48
|
+
const [stakingTxHash, setStakingTxHash] = useState("");
|
|
49
|
+
const [showSuccessModal, setShowSuccessModal] = useState(false);
|
|
50
|
+
// Wait for transaction confirmation
|
|
51
|
+
const { isLoading: isTxPending, isSuccess: isTxSuccess } = useWaitForTransactionReceipt({
|
|
52
|
+
hash: stakingTxHash,
|
|
53
|
+
query: {
|
|
54
|
+
structuralSharing: false, // Disable to avoid BigInt serialization issues
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
// Show success modal when transaction is confirmed
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (isTxSuccess && stakingTxHash) {
|
|
60
|
+
setShowAmountPrompt(false);
|
|
61
|
+
setShowSuccessModal(true);
|
|
62
|
+
setIsStaking(false);
|
|
63
|
+
}
|
|
64
|
+
}, [isTxSuccess, stakingTxHash]);
|
|
65
|
+
const [userStakeAmount, setUserStakeAmount] = useState(stakeAmount || "");
|
|
66
|
+
const [showAmountPrompt, setShowAmountPrompt] = useState(!stakeAmount);
|
|
67
|
+
const [isAmountValid, setIsAmountValid] = useState(!!stakeAmount);
|
|
68
|
+
const [validationError, setValidationError] = useState("");
|
|
69
|
+
// Store display amount for UI
|
|
70
|
+
const [displayAmount, setDisplayAmount] = useState("");
|
|
71
|
+
// Debounced state for balance checks and messaging
|
|
72
|
+
const [debouncedAmount, setDebouncedAmount] = useState("");
|
|
73
|
+
const [debouncedUserStakeAmount, setDebouncedUserStakeAmount] = useState("");
|
|
74
|
+
// Debounce the amount for balance checks
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
const timer = setTimeout(() => {
|
|
77
|
+
setDebouncedAmount(displayAmount);
|
|
78
|
+
setDebouncedUserStakeAmount(userStakeAmount);
|
|
79
|
+
}, 500);
|
|
80
|
+
return () => clearTimeout(timer);
|
|
81
|
+
}, [displayAmount, userStakeAmount]);
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
if (stakeAmount) {
|
|
84
|
+
setUserStakeAmount(stakeAmount);
|
|
85
|
+
setShowAmountPrompt(false);
|
|
86
|
+
setIsAmountValid(true);
|
|
87
|
+
}
|
|
88
|
+
}, [stakeAmount]);
|
|
89
|
+
if (!recipientAddress)
|
|
90
|
+
return null;
|
|
91
|
+
const validateAndSetAmount = (value) => {
|
|
92
|
+
// Allow decimal input by validating against a pattern
|
|
93
|
+
// This regex allows numbers with up to 18 decimal places
|
|
94
|
+
const isValidFormat = /^(\d+\.?\d{0,18}|\.\d{1,18})$/.test(value) || value === "";
|
|
95
|
+
if (!isValidFormat && value !== "") {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
setDisplayAmount(value);
|
|
99
|
+
try {
|
|
100
|
+
if (value === "" || value === ".") {
|
|
101
|
+
setUserStakeAmount("");
|
|
102
|
+
setIsAmountValid(false);
|
|
103
|
+
setValidationError("");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// For UI validation - check if it's a positive number
|
|
107
|
+
const numValue = parseFloat(value);
|
|
108
|
+
if (isNaN(numValue) || numValue <= 0) {
|
|
109
|
+
setIsAmountValid(false);
|
|
110
|
+
setUserStakeAmount("");
|
|
111
|
+
setValidationError("Please enter a valid positive number");
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
// Check minimum stake amount (50 B3)
|
|
115
|
+
if (numValue < 50) {
|
|
116
|
+
setIsAmountValid(false);
|
|
117
|
+
setUserStakeAmount("");
|
|
118
|
+
setValidationError("Minimum stake amount is 50 B3");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// Convert to wei (multiply by 10^18)
|
|
122
|
+
// Handle decimal places correctly by removing the decimal point
|
|
123
|
+
let fullAmount;
|
|
124
|
+
if (value.includes(".")) {
|
|
125
|
+
const [whole, fraction = ""] = value.split(".");
|
|
126
|
+
// Pad with zeros to 18 decimal places
|
|
127
|
+
const paddedFraction = fraction.padEnd(18, "0");
|
|
128
|
+
fullAmount = whole + paddedFraction;
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
fullAmount = value + "000000000000000000"; // Add 18 zeros
|
|
132
|
+
}
|
|
133
|
+
// Remove leading zeros
|
|
134
|
+
fullAmount = fullAmount.replace(/^0+/, "") || "0";
|
|
135
|
+
// Set the full amount for the actual transaction
|
|
136
|
+
setUserStakeAmount(fullAmount);
|
|
137
|
+
setIsAmountValid(true);
|
|
138
|
+
setValidationError("");
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
setIsAmountValid(false);
|
|
142
|
+
setUserStakeAmount("");
|
|
143
|
+
setValidationError("Please enter a valid amount");
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
const handleDirectStaking = async () => {
|
|
147
|
+
if (!address || !basePublicClient || !userStakeAmount)
|
|
148
|
+
return;
|
|
149
|
+
try {
|
|
150
|
+
setIsStaking(true);
|
|
151
|
+
// Check current allowance
|
|
152
|
+
const allowance = await basePublicClient.readContract({
|
|
153
|
+
address: B3_TOKEN.address,
|
|
154
|
+
abi: erc20Abi,
|
|
155
|
+
functionName: "allowance",
|
|
156
|
+
args: [address, ERC20Staking],
|
|
157
|
+
});
|
|
158
|
+
// If allowance is insufficient, request approval first
|
|
159
|
+
if (allowance < BigInt(userStakeAmount)) {
|
|
160
|
+
toast.info("Approving B3 spending...");
|
|
161
|
+
const approvalData = encodeFunctionData({
|
|
162
|
+
abi: erc20Abi,
|
|
163
|
+
functionName: "approve",
|
|
164
|
+
args: [ERC20Staking, BigInt(userStakeAmount)],
|
|
165
|
+
});
|
|
166
|
+
const approvalHash = await switchChainAndExecute(base.id, {
|
|
167
|
+
to: B3_TOKEN.address,
|
|
168
|
+
data: approvalData,
|
|
169
|
+
value: BigInt(0),
|
|
170
|
+
});
|
|
171
|
+
if (!approvalHash) {
|
|
172
|
+
toast.error("Approval failed. Please try again.");
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const approvalReceipt = await basePublicClient.waitForTransactionReceipt({
|
|
176
|
+
hash: approvalHash,
|
|
177
|
+
confirmations: 1,
|
|
178
|
+
});
|
|
179
|
+
if (approvalReceipt?.status !== "success") {
|
|
180
|
+
toast.error("Approval failed. Please try again.");
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Execute the stake
|
|
185
|
+
toast.info("Staking B3...");
|
|
186
|
+
const stakeData = encodeFunctionData({
|
|
187
|
+
abi: ABI_ERC20_STAKING,
|
|
188
|
+
functionName: "stake",
|
|
189
|
+
args: [BigInt(userStakeAmount), recipientAddress],
|
|
190
|
+
});
|
|
191
|
+
const stakeHash = await switchChainAndExecute(base.id, {
|
|
192
|
+
to: ERC20Staking,
|
|
193
|
+
data: stakeData,
|
|
194
|
+
value: BigInt(0),
|
|
195
|
+
});
|
|
196
|
+
if (stakeHash) {
|
|
197
|
+
setStakingTxHash(stakeHash);
|
|
198
|
+
toast.success("Staking transaction submitted!");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
console.error("@@b3-stake-custom-exact-in:error:", error);
|
|
203
|
+
toast.error("Staking failed. Please try again.");
|
|
204
|
+
setShowSuccessModal(false); // Ensure modal doesn't show on error
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
setIsStaking(false);
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
const confirmAmount = () => {
|
|
211
|
+
if (!isAmountValid) {
|
|
212
|
+
toast.error("Please enter a valid amount to stake");
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
// Check if user has sufficient B3 balance for direct staking
|
|
216
|
+
const hasEnoughBalance = b3RawBalance && BigInt(userStakeAmount) <= b3RawBalance;
|
|
217
|
+
if (hasEnoughBalance) {
|
|
218
|
+
// User has enough B3, proceed with direct staking
|
|
219
|
+
handleDirectStaking();
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
// User needs more B3, proceed to AnySpend conversion flow
|
|
223
|
+
setShowAmountPrompt(false);
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const header = () => (_jsxs(_Fragment, { children: [_jsx("div", { className: "relative mx-auto size-32", children: _jsx("img", { alt: "b3 coin", className: "size-full", src: "https://cdn.b3.fun/b3-coin-3d.png" }) }), _jsxs("div", { className: "from-b3-react-background to-as-on-surface-1 mt-[-60px] w-full rounded-t-lg bg-gradient-to-t", children: [_jsx("div", { className: "h-[60px] w-full" }), _jsx("div", { className: "mb-1 flex w-full flex-col items-center gap-2 p-5", children: _jsxs("span", { className: "font-sf-rounded text-2xl font-semibold", children: ["Swap & Stake ", userStakeAmount ? formatTokenAmount(BigInt(userStakeAmount), 18) : "", " B3 (Exact In)"] }) })] })] }));
|
|
227
|
+
const onFocusStakeAmountInput = () => {
|
|
228
|
+
window.scrollTo(0, 0);
|
|
229
|
+
document.body.scrollTop = 0;
|
|
230
|
+
};
|
|
231
|
+
const customExactInConfig = {
|
|
232
|
+
functionAbi: STAKE_FUNCTION_ABI,
|
|
233
|
+
functionName: "stake",
|
|
234
|
+
functionArgs: ["{{amount_out}}", normalizeAddress(recipientAddress)],
|
|
235
|
+
to: ERC20Staking,
|
|
236
|
+
spenderAddress: ERC20Staking,
|
|
237
|
+
action: "stake B3",
|
|
238
|
+
};
|
|
239
|
+
// Render amount input prompt if no stake amount is provided
|
|
240
|
+
if (showAmountPrompt) {
|
|
241
|
+
return (_jsx(StyleRoot, { children: _jsxs("div", { className: "bg-b3-react-background flex w-full flex-col items-center", children: [_jsxs("div", { className: "w-full px-4", children: [_jsx(motion.div, { initial: false, animate: {
|
|
242
|
+
opacity: hasMounted ? 1 : 0,
|
|
243
|
+
y: hasMounted ? 0 : 20,
|
|
244
|
+
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
245
|
+
}, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, className: "relative mx-auto size-48", children: _jsx("video", { autoPlay: true, muted: true, playsInline: true, className: "size-full", src: "https://cdn.b3.fun/b3-sphere-to-coin.mp4" }) }), _jsx(motion.div, { initial: false, animate: {
|
|
246
|
+
opacity: hasMounted ? 1 : 0,
|
|
247
|
+
y: hasMounted ? 0 : 20,
|
|
248
|
+
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
249
|
+
}, transition: { duration: 0.3, delay: 0.1, ease: "easeInOut" }, children: _jsx("h2", { className: "font-sf-rounded font-neue-montreal-medium mb-1 text-center text-2xl font-semibold", children: (() => {
|
|
250
|
+
const hasEnoughBalance = b3RawBalance && BigInt(debouncedUserStakeAmount || "0") <= b3RawBalance;
|
|
251
|
+
return hasEnoughBalance || !debouncedAmount ? "Stake B3" : "Swap & Stake B3";
|
|
252
|
+
})() }) })] }), _jsxs(motion.div, { initial: false, animate: {
|
|
253
|
+
opacity: hasMounted ? 1 : 0,
|
|
254
|
+
y: hasMounted ? 0 : 20,
|
|
255
|
+
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
256
|
+
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [_jsx("div", { className: "mb-2", children: _jsxs("div", { className: "flex items-center justify-between", children: [_jsx("p", { className: "text-as-primary/70 text-sm font-medium", children: "I want to stake" }), _jsxs("span", { className: "text-as-primary/50 flex items-center gap-1 text-sm", children: ["Available: ", isBalanceLoading ? _jsx(Loader2, { className: "h-3 w-3 animate-spin" }) : `${b3Balance} B3`] })] }) }), _jsxs("div", { className: "relative", children: [_jsx(Input, { onFocus: onFocusStakeAmountInput, type: "text", placeholder: "0.00", value: displayAmount, onChange: e => validateAndSetAmount(e.target.value), className: `h-14 px-4 text-lg ${!isAmountValid && displayAmount ? "border-as-red" : "border-b3-react-border"}` }), _jsx("div", { className: "font-pack absolute right-4 top-1/2 -translate-y-1/2 text-lg font-medium text-blue-500/70", children: "B3" })] }), !isAmountValid && displayAmount && _jsx("p", { className: "text-as-red mt-2 text-sm", children: validationError }), _jsx("div", { className: "mt-4", children: (() => {
|
|
257
|
+
const hasEnoughBalance = b3RawBalance && BigInt(debouncedUserStakeAmount || "0") <= b3RawBalance;
|
|
258
|
+
if (!hasEnoughBalance || !debouncedAmount) {
|
|
259
|
+
return (_jsxs("div", { className: "bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5", children: [_jsxs("div", { className: "flex items-center justify-center gap-2", children: [_jsx("span", { className: "text-as-primary text-sm font-semibold", children: "Swap & stake from any token" }), _jsxs(TextLoop, { children: [_jsx(EthIcon, { className: "h-8 w-8" }), _jsx(SolIcon, { className: "h-8 w-8" }), _jsx(UsdcIcon, { className: "h-8 w-8" })] }), _jsx(ArrowRight, { className: "text-as-primary h-4 w-4" }), _jsx("img", { src: "https://cdn.b3.fun/b3-coin-3d.png", className: "h-7 w-7", alt: "B3 Token" })] }), _jsx("p", { className: "text-as-primary/50 text-sm font-medium", children: debouncedAmount
|
|
260
|
+
? `No problem, we'll help you swap to ${debouncedAmount} B3!`
|
|
261
|
+
: "Not enough B3? We'll help you swap from other coins." })] }));
|
|
262
|
+
}
|
|
263
|
+
})() }), _jsx(Button, { onClick: confirmAmount, disabled: !isAmountValid || !displayAmount || isStaking || isTxPending || isSwitchingOrExecuting, className: "bg-as-brand hover:bg-as-brand/90 text-as-primary mt-4 h-14 w-full rounded-xl text-lg font-medium", children: isStaking || isSwitchingOrExecuting ? "Staking..." : isTxPending ? "Confirming..." : "Continue" })] })] }) }));
|
|
264
|
+
}
|
|
265
|
+
// Success Modal for Direct Staking
|
|
266
|
+
if (showSuccessModal) {
|
|
267
|
+
return (_jsx(StyleRoot, { children: _jsxs("div", { className: "bg-b3-react-background flex w-full flex-col items-center", children: [_jsxs("div", { className: "w-full p-4", children: [_jsxs(motion.div, { initial: false, animate: {
|
|
268
|
+
opacity: hasMounted ? 1 : 0,
|
|
269
|
+
y: hasMounted ? 0 : 20,
|
|
270
|
+
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
271
|
+
}, transition: { duration: 0.3, delay: 0, ease: "easeInOut" }, className: "relative mx-auto mb-4 size-[120px]", children: [_jsx("div", { className: "absolute inset-0 scale-95 rounded-[50%] bg-black/30 blur-md" }), _jsxs(GlareCardRounded, { className: "overflow-hidden rounded-full border-none", children: [_jsx("img", { alt: "b3 coin", loading: "lazy", width: "64", height: "64", decoding: "async", "data-nimg": "1", className: "size-full shrink-0 bg-transparent text-transparent", src: "https://cdn.b3.fun/b3-coin-3d.png" }), _jsx("div", { className: "absolute inset-0 rounded-[50%] border border-white/10" })] })] }), _jsx(motion.div, { initial: false, animate: {
|
|
272
|
+
opacity: hasMounted ? 1 : 0,
|
|
273
|
+
y: hasMounted ? 0 : 20,
|
|
274
|
+
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
275
|
+
}, transition: { duration: 0.3, delay: 0.1, ease: "easeInOut" }, children: _jsxs("h2", { className: "font-sf-rounded mb-1 text-center text-2xl font-semibold", children: ["Staked ", formatTokenAmount(BigInt(userStakeAmount), 18), " B3"] }) })] }), _jsxs(motion.div, { initial: false, animate: {
|
|
276
|
+
opacity: hasMounted ? 1 : 0,
|
|
277
|
+
y: hasMounted ? 0 : 20,
|
|
278
|
+
filter: hasMounted ? "blur(0px)" : "blur(10px)",
|
|
279
|
+
}, transition: { duration: 0.3, delay: 0.2, ease: "easeInOut" }, className: "bg-b3-react-background w-full p-6", children: [_jsx("div", { className: "mb-6", children: _jsx("a", { href: `https://basescan.org/tx/${stakingTxHash}`, target: "_blank", rel: "noopener noreferrer", className: "text-as-primary/70 hover:text-as-primary block break-all text-center font-mono text-sm underline transition-colors", children: "View transaction" }) }), _jsx(Button, { onClick: () => {
|
|
280
|
+
setB3ModalOpen(false);
|
|
281
|
+
onSuccess?.(formatTokenAmount(BigInt(userStakeAmount), 18) ?? "");
|
|
282
|
+
}, className: "bg-as-brand hover:bg-as-brand/90 text-as-primary h-14 w-full rounded-xl text-lg font-medium", children: "Done" })] })] }) }));
|
|
283
|
+
}
|
|
284
|
+
return (_jsx(AnySpendCustomExactIn, { loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, sourceTokenAddress: sourceTokenAddress, sourceTokenChainId: sourceTokenChainId, destinationToken: B3_TOKEN, destinationChainId: base.id, customExactInConfig: customExactInConfig, header: header, onSuccess: onSuccess }));
|
|
285
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { components } from "../../../anyspend/types/api";
|
|
2
|
+
export declare function AnySpendStakeUpsideExactIn({ loadOrder, mode, recipientAddress, sourceTokenAddress, sourceTokenChainId, stakingContractAddress, token, onSuccess, }: {
|
|
3
|
+
loadOrder?: string;
|
|
4
|
+
mode?: "modal" | "page";
|
|
5
|
+
recipientAddress: string;
|
|
6
|
+
sourceTokenAddress?: string;
|
|
7
|
+
sourceTokenChainId?: number;
|
|
8
|
+
stakingContractAddress: string;
|
|
9
|
+
token: components["schemas"]["Token"];
|
|
10
|
+
onSuccess?: (amount: string) => void;
|
|
11
|
+
}): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { normalizeAddress } from "../../../anyspend/utils/index.js";
|
|
3
|
+
import { base } from "viem/chains";
|
|
4
|
+
import { AnySpendCustomExactIn } from "./AnySpendCustomExactIn.js";
|
|
5
|
+
const STAKE_FOR_FUNCTION_ABI = JSON.stringify([
|
|
6
|
+
{
|
|
7
|
+
name: "stakeFor",
|
|
8
|
+
type: "function",
|
|
9
|
+
stateMutability: "nonpayable",
|
|
10
|
+
inputs: [
|
|
11
|
+
{ name: "user", type: "address" },
|
|
12
|
+
{ name: "amount", type: "uint256" },
|
|
13
|
+
],
|
|
14
|
+
outputs: [],
|
|
15
|
+
},
|
|
16
|
+
]);
|
|
17
|
+
export function AnySpendStakeUpsideExactIn({ loadOrder, mode = "modal", recipientAddress, sourceTokenAddress, sourceTokenChainId, stakingContractAddress, token, onSuccess, }) {
|
|
18
|
+
if (!recipientAddress)
|
|
19
|
+
return null;
|
|
20
|
+
const header = () => (_jsx(_Fragment, { children: _jsx("div", { className: "from-b3-react-background to-as-on-surface-1 w-full rounded-t-lg bg-gradient-to-t", children: _jsx("div", { className: "mb-1 flex w-full flex-col items-center gap-2", children: _jsxs("span", { className: "font-sf-rounded text-2xl font-semibold", children: ["Swap & Stake ", token.symbol, " (Exact In)"] }) }) }) }));
|
|
21
|
+
const customExactInConfig = {
|
|
22
|
+
functionAbi: STAKE_FOR_FUNCTION_ABI,
|
|
23
|
+
functionName: "stakeFor",
|
|
24
|
+
functionArgs: [normalizeAddress(recipientAddress), "{{amount_out}}"],
|
|
25
|
+
to: stakingContractAddress,
|
|
26
|
+
spenderAddress: stakingContractAddress,
|
|
27
|
+
action: `stake ${token.symbol}`,
|
|
28
|
+
};
|
|
29
|
+
return (_jsx(AnySpendCustomExactIn, { loadOrder: loadOrder, mode: mode, recipientAddress: recipientAddress, sourceTokenAddress: sourceTokenAddress, sourceTokenChainId: sourceTokenChainId, destinationToken: token, destinationChainId: base.id, customExactInConfig: customExactInConfig, header: header, onSuccess: onSuccess }));
|
|
30
|
+
}
|
|
@@ -48,6 +48,12 @@ function getOrderSuccessText({ order, tournament, formattedActualDstAmount, form
|
|
|
48
48
|
case "custom":
|
|
49
49
|
actionText = order.metadata.action || `executed contract`;
|
|
50
50
|
return `Successfully ${actionText}`;
|
|
51
|
+
case "x402_swap":
|
|
52
|
+
actionText = `sent ${formattedActualDstAmount || "--"} ${dstToken.symbol}`;
|
|
53
|
+
return `Successfully ${actionText} to ${recipient}`;
|
|
54
|
+
case "custom_exact_in":
|
|
55
|
+
actionText = `executed contract`;
|
|
56
|
+
return `Successfully ${actionText}`;
|
|
51
57
|
default:
|
|
52
58
|
throw new Error("Invalid order type");
|
|
53
59
|
}
|
|
@@ -360,7 +366,7 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
|
|
|
360
366
|
? depositTxs.map(dTxs => (_jsx(TransactionDetails, { title: order.onrampMetadata?.vendor === "stripe-web2"
|
|
361
367
|
? `Received payment`
|
|
362
368
|
: `Received ${formatTokenAmount(BigInt(dTxs.amount), srcToken.decimals)} ${srcToken.symbol}`, chainId: order.srcChain, tx: dTxs, isProcessing: false }, dTxs.txHash)))
|
|
363
|
-
: null, relayTxs.map(relayTx => (_jsx(TransactionDetails, { title: "Processed Transaction", chainId: relayTx.chain, isProcessing: false, tx: relayTx, delay: 0.5 }))), order.status === "executing" && (_jsx(TransactionDetails, { title: order.type === "swap"
|
|
369
|
+
: null, relayTxs.map(relayTx => (_jsx(TransactionDetails, { title: "Processed Transaction", chainId: relayTx.chain, isProcessing: false, tx: relayTx, delay: 0.5 }))), order.status === "executing" && (_jsx(TransactionDetails, { title: order.type === "swap" || order.type === "x402_swap"
|
|
364
370
|
? "Processing Swap"
|
|
365
371
|
: order.type === "mint_nft"
|
|
366
372
|
? "Minting NFT"
|
|
@@ -370,7 +376,9 @@ export const OrderDetails = memo(function OrderDetails({ mode = "modal", order,
|
|
|
370
376
|
? "Funding Tournament"
|
|
371
377
|
: order.type === "hype_duel"
|
|
372
378
|
? "Depositing Hype Duel"
|
|
373
|
-
:
|
|
379
|
+
: order.type === "custom" || order.type === "custom_exact_in"
|
|
380
|
+
? "Executing Contract"
|
|
381
|
+
: "Processing Bridge", chainId: order.dstChain, isProcessing: true, tx: null, delay: 1 }))] }) })] }) }), order.type === "join_tournament" && order.status === "executed" && (_jsxs(ShinyButton, { accentColor: "hsl(var(--as-brand))", textColor: "text-white", className: "flex w-full items-center gap-2", disabled: txLoading || isSwitchingOrExecuting, onClick: handleCloseModal, children: [_jsx("span", { className: "pl-4", children: "Continue to Tournament" }), _jsx(ChevronRight, { className: "h-4 w-4" })] })), order.status === "executed" && (_jsx("button", { className: "order-close-button order-details-close-btn bg-as-brand flex w-full items-center justify-center gap-2 rounded-lg p-2 font-semibold text-white", onClick: mode === "page" ? handleBack : handleCloseModal, children: mode === "page" ? (_jsxs(_Fragment, { children: ["Return to Home ", _jsx(Home, { className: "ml-2 h-4 w-4" })] })) : ("Close") }))] }));
|
|
374
382
|
}
|
|
375
383
|
// This boolean indicates that user finish payment, and waiting for the deposit to be confirmed. We get this from query params (waitingForDeposit=true)
|
|
376
384
|
const waitingForDeposit = new URLSearchParams(window.location.search).get("waitingForDeposit") === "true";
|
|
@@ -17,8 +17,7 @@ export const OrderDetailsCollapsible = memo(function OrderDetailsCollapsible({ o
|
|
|
17
17
|
const expectedDstAmount = order.type === "mint_nft" ||
|
|
18
18
|
order.type === "join_tournament" ||
|
|
19
19
|
order.type === "fund_tournament" ||
|
|
20
|
-
order.type === "custom"
|
|
21
|
-
order.type === "hype_duel"
|
|
20
|
+
order.type === "custom"
|
|
22
21
|
? "0"
|
|
23
22
|
: order.payload.expectedDstAmount.toString();
|
|
24
23
|
const finalFormattedExpectedDstAmount = formattedExpectedDstAmount || formatTokenAmount(BigInt(expectedDstAmount), dstToken.decimals);
|
|
@@ -30,7 +29,7 @@ export const OrderDetailsCollapsible = memo(function OrderDetailsCollapsible({ o
|
|
|
30
29
|
? "Join tournament"
|
|
31
30
|
: order.type === "fund_tournament"
|
|
32
31
|
? "Fund tournament"
|
|
33
|
-
: order.type === "custom"
|
|
32
|
+
: order.type === "custom" || order.type === "custom_exact_in"
|
|
34
33
|
? order.metadata.action
|
|
35
34
|
? capitalizeFirstLetter(order.metadata.action)
|
|
36
35
|
: "Contract execution"
|
|
@@ -2,11 +2,15 @@ export { AnySpend } from "./AnySpend";
|
|
|
2
2
|
export { AnySpendBondKit } from "./AnySpendBondKit";
|
|
3
3
|
export { AnySpendBuySpin } from "./AnySpendBuySpin";
|
|
4
4
|
export { AnySpendCustom } from "./AnySpendCustom";
|
|
5
|
+
export { AnySpendCustomExactIn } from "./AnySpendCustomExactIn";
|
|
5
6
|
export * from "./AnySpendFingerprintWrapper";
|
|
6
7
|
export { AnySpendNFT } from "./AnySpendNFT";
|
|
8
|
+
export { AnyspendSignatureMint } from "./AnyspendSignatureMint";
|
|
7
9
|
export { AnySpendStakeB3 } from "./AnySpendStakeB3";
|
|
10
|
+
export { AnySpendStakeB3ExactIn } from "./AnySpendStakeB3ExactIn";
|
|
11
|
+
export { AnySpendStakeUpside } from "./AnySpendStakeUpside";
|
|
12
|
+
export { AnySpendStakeUpsideExactIn } from "./AnySpendStakeUpsideExactIn";
|
|
8
13
|
export { AnySpendTournament } from "./AnySpendTournament";
|
|
9
|
-
export { AnyspendSignatureMint } from "./AnyspendSignatureMint";
|
|
10
14
|
export { AnySpendNFTButton } from "./common/AnySpendNFTButton";
|
|
11
15
|
export { ChainTokenIcon } from "./common/ChainTokenIcon";
|
|
12
16
|
export { CryptoPaySection } from "./common/CryptoPaySection";
|
|
@@ -3,11 +3,15 @@ export { AnySpend } from "./AnySpend.js";
|
|
|
3
3
|
export { AnySpendBondKit } from "./AnySpendBondKit.js";
|
|
4
4
|
export { AnySpendBuySpin } from "./AnySpendBuySpin.js";
|
|
5
5
|
export { AnySpendCustom } from "./AnySpendCustom.js";
|
|
6
|
+
export { AnySpendCustomExactIn } from "./AnySpendCustomExactIn.js";
|
|
6
7
|
export * from "./AnySpendFingerprintWrapper.js";
|
|
7
8
|
export { AnySpendNFT } from "./AnySpendNFT.js";
|
|
9
|
+
export { AnyspendSignatureMint } from "./AnyspendSignatureMint.js";
|
|
8
10
|
export { AnySpendStakeB3 } from "./AnySpendStakeB3.js";
|
|
11
|
+
export { AnySpendStakeB3ExactIn } from "./AnySpendStakeB3ExactIn.js";
|
|
12
|
+
export { AnySpendStakeUpside } from "./AnySpendStakeUpside.js";
|
|
13
|
+
export { AnySpendStakeUpsideExactIn } from "./AnySpendStakeUpsideExactIn.js";
|
|
9
14
|
export { AnySpendTournament } from "./AnySpendTournament.js";
|
|
10
|
-
export { AnyspendSignatureMint } from "./AnyspendSignatureMint.js";
|
|
11
15
|
export { AnySpendNFTButton } from "./common/AnySpendNFTButton.js";
|
|
12
16
|
// Common Components
|
|
13
17
|
export { ChainTokenIcon } from "./common/ChainTokenIcon.js";
|
|
@@ -17,13 +17,16 @@ interface UseAnyspendFlowProps {
|
|
|
17
17
|
loadOrder?: string;
|
|
18
18
|
isDepositMode?: boolean;
|
|
19
19
|
onOrderSuccess?: (orderId: string) => void;
|
|
20
|
-
onTransactionSuccess?: (amount
|
|
20
|
+
onTransactionSuccess?: (amount: string) => void;
|
|
21
21
|
sourceTokenAddress?: string;
|
|
22
22
|
sourceTokenChainId?: number;
|
|
23
|
+
destinationTokenAddress?: string;
|
|
24
|
+
destinationTokenChainId?: number;
|
|
23
25
|
slippage?: number;
|
|
24
26
|
disableUrlParamManagement?: boolean;
|
|
27
|
+
orderType?: "hype_duel" | "custom_exact_in";
|
|
25
28
|
}
|
|
26
|
-
export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, slippage, disableUrlParamManagement, }: UseAnyspendFlowProps): {
|
|
29
|
+
export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrder, isDepositMode, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, destinationTokenAddress, destinationTokenChainId, slippage, disableUrlParamManagement, orderType, }: UseAnyspendFlowProps): {
|
|
27
30
|
activePanel: PanelView;
|
|
28
31
|
setActivePanel: import("react").Dispatch<import("react").SetStateAction<PanelView>>;
|
|
29
32
|
orderId: string | undefined;
|
|
@@ -44,7 +47,6 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
44
47
|
selectedSrcChainId: number;
|
|
45
48
|
setSelectedSrcChainId: import("react").Dispatch<import("react").SetStateAction<number>>;
|
|
46
49
|
selectedDstChainId: number;
|
|
47
|
-
setSelectedDstChainId: import("react").Dispatch<import("react").SetStateAction<number>>;
|
|
48
50
|
selectedSrcToken: {
|
|
49
51
|
chainId: number;
|
|
50
52
|
address: string;
|
|
@@ -65,6 +67,26 @@ export declare function useAnyspendFlow({ paymentType, recipientAddress, loadOrd
|
|
|
65
67
|
logoURI?: string;
|
|
66
68
|
};
|
|
67
69
|
}>>;
|
|
70
|
+
selectedDstToken: {
|
|
71
|
+
chainId: number;
|
|
72
|
+
address: string;
|
|
73
|
+
symbol: string;
|
|
74
|
+
name: string;
|
|
75
|
+
decimals: number;
|
|
76
|
+
metadata: {
|
|
77
|
+
logoURI?: string;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
setSelectedDstToken: import("react").Dispatch<import("react").SetStateAction<{
|
|
81
|
+
chainId: number;
|
|
82
|
+
address: string;
|
|
83
|
+
symbol: string;
|
|
84
|
+
name: string;
|
|
85
|
+
decimals: number;
|
|
86
|
+
metadata: {
|
|
87
|
+
logoURI?: string;
|
|
88
|
+
};
|
|
89
|
+
}>>;
|
|
68
90
|
srcAmount: string;
|
|
69
91
|
setSrcAmount: import("react").Dispatch<import("react").SetStateAction<string>>;
|
|
70
92
|
dstAmount: string;
|
|
@@ -23,21 +23,25 @@ export var PanelView;
|
|
|
23
23
|
PanelView[PanelView["POINTS_DETAIL"] = 6] = "POINTS_DETAIL";
|
|
24
24
|
PanelView[PanelView["FEE_DETAIL"] = 7] = "FEE_DETAIL";
|
|
25
25
|
})(PanelView || (PanelView = {}));
|
|
26
|
-
|
|
26
|
+
// This hook serves for order hype_duel and custom_exact_in
|
|
27
|
+
export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, loadOrder, isDepositMode = false, onOrderSuccess, onTransactionSuccess, sourceTokenAddress, sourceTokenChainId, destinationTokenAddress, destinationTokenChainId, slippage = 0, disableUrlParamManagement = false, orderType = "hype_duel", }) {
|
|
27
28
|
const searchParams = useSearchParamsSSR();
|
|
28
29
|
const router = useRouter();
|
|
29
30
|
// Panel and order state
|
|
30
31
|
const [activePanel, setActivePanel] = useState(loadOrder ? PanelView.ORDER_DETAILS : PanelView.MAIN);
|
|
31
32
|
const [orderId, setOrderId] = useState(loadOrder);
|
|
32
33
|
const { orderAndTransactions: oat } = useAnyspendOrderAndTransactions(orderId);
|
|
33
|
-
// Token selection state - use provided sourceTokenChainId if available
|
|
34
|
+
// Token selection state - use provided sourceTokenChainId and destinationTokenChainId if available
|
|
34
35
|
const [selectedSrcChainId, setSelectedSrcChainId] = useState(sourceTokenChainId || (paymentType === "fiat" ? base.id : mainnet.id));
|
|
35
|
-
const [selectedDstChainId, setSelectedDstChainId] = useState(base.id); // Default to Base for cross-chain swaps
|
|
36
36
|
const defaultSrcToken = paymentType === "fiat" ? USDC_BASE : getDefaultToken(selectedSrcChainId);
|
|
37
|
+
const defaultDstToken = B3_TOKEN; // Default destination token
|
|
37
38
|
const [selectedSrcToken, setSelectedSrcToken] = useState(defaultSrcToken);
|
|
39
|
+
const [selectedDstToken, setSelectedDstToken] = useState(defaultDstToken);
|
|
38
40
|
const [srcAmount, setSrcAmount] = useState(paymentType === "fiat" ? "5" : "0.1");
|
|
39
41
|
const [dstAmount, setDstAmount] = useState("");
|
|
40
42
|
const [isSrcInputDirty, setIsSrcInputDirty] = useState(true);
|
|
43
|
+
// Derive destination chain ID from token or prop (cannot change)
|
|
44
|
+
const selectedDstChainId = destinationTokenChainId || selectedDstToken.chainId;
|
|
41
45
|
// Payment method state
|
|
42
46
|
const [selectedCryptoPaymentMethod, setSelectedCryptoPaymentMethod] = useState(CryptoPaymentMethodType.NONE);
|
|
43
47
|
const [selectedFiatPaymentMethod, setSelectedFiatPaymentMethod] = useState(FiatPaymentMethod.NONE);
|
|
@@ -97,6 +101,23 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
97
101
|
};
|
|
98
102
|
fetchSourceToken();
|
|
99
103
|
}, [sourceTokenAddress, sourceTokenChainId]);
|
|
104
|
+
// Fetch specific token when destinationTokenAddress and destinationTokenChainId are provided
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
const fetchDestinationToken = async () => {
|
|
107
|
+
if (destinationTokenAddress && destinationTokenChainId) {
|
|
108
|
+
try {
|
|
109
|
+
const token = await anyspendService.getToken(destinationTokenChainId, destinationTokenAddress);
|
|
110
|
+
setSelectedDstToken(token);
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
console.error("Failed to fetch destination token:", error);
|
|
114
|
+
toast.error(`Failed to load token ${destinationTokenAddress} on chain ${destinationTokenChainId}`);
|
|
115
|
+
// Keep the default token on error
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
fetchDestinationToken();
|
|
120
|
+
}, [destinationTokenAddress, destinationTokenChainId]);
|
|
100
121
|
// Helper function for onramp vendor mapping
|
|
101
122
|
const getOnrampVendor = (paymentMethod) => {
|
|
102
123
|
switch (paymentMethod) {
|
|
@@ -116,8 +137,8 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
116
137
|
srcChain: paymentType === "fiat" ? base.id : selectedSrcChainId,
|
|
117
138
|
dstChain: isDepositMode ? base.id : selectedDstChainId, // For deposits, always Base; for swaps, use selected destination
|
|
118
139
|
srcTokenAddress: paymentType === "fiat" ? USDC_BASE.address : selectedSrcToken.address,
|
|
119
|
-
dstTokenAddress:
|
|
120
|
-
type:
|
|
140
|
+
dstTokenAddress: selectedDstToken.address,
|
|
141
|
+
type: orderType,
|
|
121
142
|
amount: activeInputAmountInWei,
|
|
122
143
|
recipientAddress: selectedRecipientAddress,
|
|
123
144
|
onrampVendor: paymentType === "fiat" ? getOnrampVendor(selectedFiatPaymentMethod) : undefined,
|
|
@@ -195,7 +216,7 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
195
216
|
const formattedActualDstAmount = amount
|
|
196
217
|
? formatTokenAmount(BigInt(amount), oat.data.order.metadata.dstToken.decimals)
|
|
197
218
|
: undefined;
|
|
198
|
-
onTransactionSuccess?.(formattedActualDstAmount);
|
|
219
|
+
onTransactionSuccess?.(formattedActualDstAmount ?? "");
|
|
199
220
|
}
|
|
200
221
|
}, [
|
|
201
222
|
oat?.data?.order.status,
|
|
@@ -213,10 +234,11 @@ export function useAnyspendFlow({ paymentType = "crypto", recipientAddress, load
|
|
|
213
234
|
// Token state
|
|
214
235
|
selectedSrcChainId,
|
|
215
236
|
setSelectedSrcChainId,
|
|
216
|
-
selectedDstChainId,
|
|
217
|
-
setSelectedDstChainId,
|
|
237
|
+
selectedDstChainId, // Derived, not stateful
|
|
218
238
|
selectedSrcToken,
|
|
219
239
|
setSelectedSrcToken,
|
|
240
|
+
selectedDstToken,
|
|
241
|
+
setSelectedDstToken,
|
|
220
242
|
srcAmount,
|
|
221
243
|
setSrcAmount,
|
|
222
244
|
dstAmount,
|