@b3dotfun/sdk 0.1.65-alpha.2 → 0.1.65-alpha.4
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/AnySpendCollectorClubPurchase.d.ts +6 -1
- package/dist/cjs/anyspend/react/components/AnySpendCollectorClubPurchase.js +126 -9
- package/dist/cjs/anyspend/react/components/QRDeposit.js +3 -1
- package/dist/cjs/anyspend/utils/chain.d.ts +1 -1
- package/dist/cjs/anyspend/utils/chain.js +72 -62
- package/dist/cjs/global-account/react/stores/useModalStore.d.ts +2 -0
- package/dist/esm/anyspend/react/components/AnySpendCollectorClubPurchase.d.ts +6 -1
- package/dist/esm/anyspend/react/components/AnySpendCollectorClubPurchase.js +128 -11
- package/dist/esm/anyspend/react/components/QRDeposit.js +4 -2
- package/dist/esm/anyspend/utils/chain.d.ts +1 -1
- package/dist/esm/anyspend/utils/chain.js +72 -62
- package/dist/esm/global-account/react/stores/useModalStore.d.ts +2 -0
- package/dist/types/anyspend/react/components/AnySpendCollectorClubPurchase.d.ts +6 -1
- package/dist/types/anyspend/utils/chain.d.ts +1 -1
- package/dist/types/global-account/react/stores/useModalStore.d.ts +2 -0
- package/package.json +1 -1
- package/src/anyspend/react/components/AnySpendCollectorClubPurchase.tsx +169 -10
- package/src/anyspend/react/components/QRDeposit.tsx +17 -2
- package/src/anyspend/utils/chain.ts +81 -65
- package/src/global-account/react/stores/useModalStore.ts +2 -0
|
@@ -69,5 +69,10 @@ export interface AnySpendCollectorClubPurchaseProps {
|
|
|
69
69
|
* Force fiat payment
|
|
70
70
|
*/
|
|
71
71
|
forceFiatPayment?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Optional discount code to apply to the purchase.
|
|
74
|
+
* When provided, validates on-chain and adjusts the price accordingly.
|
|
75
|
+
*/
|
|
76
|
+
discountCode?: string;
|
|
72
77
|
}
|
|
73
|
-
export declare function AnySpendCollectorClubPurchase({ loadOrder, mode, activeTab, packId, packAmount, pricePerPack, paymentToken, recipientAddress, spenderAddress, isStaging, onSuccess, header, showRecipient, vendingMachineId, packType, forceFiatPayment, }: AnySpendCollectorClubPurchaseProps): import("react/jsx-runtime").JSX.Element;
|
|
78
|
+
export declare function AnySpendCollectorClubPurchase({ loadOrder, mode, activeTab, packId, packAmount, pricePerPack, paymentToken, recipientAddress, spenderAddress, isStaging, onSuccess, header, showRecipient, vendingMachineId, packType, forceFiatPayment, discountCode, }: AnySpendCollectorClubPurchaseProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -29,9 +29,11 @@ const jsx_runtime_1 = require("react/jsx-runtime");
|
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
31
|
const constants_1 = require("../../../anyspend/constants");
|
|
32
|
+
const constants_2 = require("../../../shared/constants");
|
|
32
33
|
const number_1 = require("../../../shared/utils/number");
|
|
33
34
|
const react_1 = require("react");
|
|
34
35
|
const viem_1 = require("viem");
|
|
36
|
+
const chains_1 = require("viem/chains");
|
|
35
37
|
const AnySpendCustom_1 = require("./AnySpendCustom");
|
|
36
38
|
// Collector Club Shop contract addresses on Base
|
|
37
39
|
const CC_SHOP_ADDRESS = "0x47366E64E4917dd4DdC04Fb9DC507c1dD2b87294";
|
|
@@ -49,7 +51,35 @@ const BUY_PACKS_FOR_ABI = {
|
|
|
49
51
|
stateMutability: "nonpayable",
|
|
50
52
|
type: "function",
|
|
51
53
|
};
|
|
52
|
-
|
|
54
|
+
// ABI for buyPacksForWithDiscount function (with discount code)
|
|
55
|
+
const BUY_PACKS_FOR_WITH_DISCOUNT_ABI = {
|
|
56
|
+
inputs: [
|
|
57
|
+
{ internalType: "address", name: "user", type: "address" },
|
|
58
|
+
{ internalType: "uint256", name: "packId", type: "uint256" },
|
|
59
|
+
{ internalType: "uint256", name: "amount", type: "uint256" },
|
|
60
|
+
{ internalType: "string", name: "discountCode", type: "string" },
|
|
61
|
+
],
|
|
62
|
+
name: "buyPacksForWithDiscount",
|
|
63
|
+
outputs: [],
|
|
64
|
+
stateMutability: "nonpayable",
|
|
65
|
+
type: "function",
|
|
66
|
+
};
|
|
67
|
+
// ABI for isDiscountCodeValid view function
|
|
68
|
+
const IS_DISCOUNT_CODE_VALID_ABI = {
|
|
69
|
+
inputs: [{ internalType: "string", name: "code", type: "string" }],
|
|
70
|
+
name: "isDiscountCodeValid",
|
|
71
|
+
outputs: [
|
|
72
|
+
{ internalType: "bool", name: "isValid", type: "bool" },
|
|
73
|
+
{ internalType: "uint256", name: "discountAmount", type: "uint256" },
|
|
74
|
+
],
|
|
75
|
+
stateMutability: "view",
|
|
76
|
+
type: "function",
|
|
77
|
+
};
|
|
78
|
+
const basePublicClient = (0, viem_1.createPublicClient)({
|
|
79
|
+
chain: chains_1.base,
|
|
80
|
+
transport: (0, viem_1.http)(constants_2.PUBLIC_BASE_RPC_URL),
|
|
81
|
+
});
|
|
82
|
+
function AnySpendCollectorClubPurchase({ loadOrder, mode = "modal", activeTab = "crypto", packId, packAmount, pricePerPack, paymentToken = constants_1.USDC_BASE, recipientAddress, spenderAddress, isStaging = false, onSuccess, header, showRecipient = true, vendingMachineId, packType, forceFiatPayment, discountCode, }) {
|
|
53
83
|
const ccShopAddress = isStaging ? CC_SHOP_ADDRESS_STAGING : CC_SHOP_ADDRESS;
|
|
54
84
|
// Calculate total amount needed (pricePerPack * packAmount)
|
|
55
85
|
const totalAmount = (0, react_1.useMemo)(() => {
|
|
@@ -61,15 +91,89 @@ function AnySpendCollectorClubPurchase({ loadOrder, mode = "modal", activeTab =
|
|
|
61
91
|
return "0";
|
|
62
92
|
}
|
|
63
93
|
}, [pricePerPack, packAmount]);
|
|
64
|
-
//
|
|
94
|
+
// Discount code validation state
|
|
95
|
+
const [discountInfo, setDiscountInfo] = (0, react_1.useState)({
|
|
96
|
+
isValid: false,
|
|
97
|
+
discountAmount: BigInt(0),
|
|
98
|
+
isLoading: false,
|
|
99
|
+
error: null,
|
|
100
|
+
});
|
|
101
|
+
// Validate discount code on-chain when provided
|
|
102
|
+
(0, react_1.useEffect)(() => {
|
|
103
|
+
if (!discountCode) {
|
|
104
|
+
setDiscountInfo({ isValid: false, discountAmount: BigInt(0), isLoading: false, error: null });
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
let cancelled = false;
|
|
108
|
+
const validateDiscount = async () => {
|
|
109
|
+
setDiscountInfo(prev => ({ ...prev, isLoading: true, error: null }));
|
|
110
|
+
try {
|
|
111
|
+
const result = await basePublicClient.readContract({
|
|
112
|
+
address: ccShopAddress,
|
|
113
|
+
abi: [IS_DISCOUNT_CODE_VALID_ABI],
|
|
114
|
+
functionName: "isDiscountCodeValid",
|
|
115
|
+
args: [discountCode],
|
|
116
|
+
});
|
|
117
|
+
if (cancelled)
|
|
118
|
+
return;
|
|
119
|
+
const [isValid, discountAmount] = result;
|
|
120
|
+
if (!isValid) {
|
|
121
|
+
setDiscountInfo({
|
|
122
|
+
isValid: false,
|
|
123
|
+
discountAmount: BigInt(0),
|
|
124
|
+
isLoading: false,
|
|
125
|
+
error: "Invalid or expired discount code",
|
|
126
|
+
});
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
setDiscountInfo({ isValid: true, discountAmount, isLoading: false, error: null });
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
if (cancelled)
|
|
133
|
+
return;
|
|
134
|
+
console.error("Failed to validate discount code", { discountCode, error });
|
|
135
|
+
setDiscountInfo({
|
|
136
|
+
isValid: false,
|
|
137
|
+
discountAmount: BigInt(0),
|
|
138
|
+
isLoading: false,
|
|
139
|
+
error: "Failed to validate discount code",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
validateDiscount();
|
|
144
|
+
return () => {
|
|
145
|
+
cancelled = true;
|
|
146
|
+
};
|
|
147
|
+
}, [discountCode, ccShopAddress]);
|
|
148
|
+
// Calculate effective dstAmount after discount
|
|
149
|
+
const effectiveDstAmount = (0, react_1.useMemo)(() => {
|
|
150
|
+
if (!discountCode || !discountInfo.isValid || discountInfo.discountAmount === BigInt(0)) {
|
|
151
|
+
return totalAmount;
|
|
152
|
+
}
|
|
153
|
+
const total = BigInt(totalAmount);
|
|
154
|
+
const discount = discountInfo.discountAmount;
|
|
155
|
+
if (discount >= total) {
|
|
156
|
+
console.error("Discount exceeds total price", { totalAmount, discountAmount: discount.toString() });
|
|
157
|
+
return "0";
|
|
158
|
+
}
|
|
159
|
+
return (total - discount).toString();
|
|
160
|
+
}, [totalAmount, discountCode, discountInfo.isValid, discountInfo.discountAmount]);
|
|
161
|
+
// Calculate fiat amount (effectiveDstAmount in USD, assuming USDC with 6 decimals)
|
|
65
162
|
const srcFiatAmount = (0, react_1.useMemo)(() => {
|
|
66
|
-
if (!
|
|
163
|
+
if (!effectiveDstAmount || effectiveDstAmount === "0")
|
|
67
164
|
return "0";
|
|
68
|
-
return (0, number_1.formatUnits)(
|
|
69
|
-
}, [
|
|
70
|
-
// Encode the
|
|
165
|
+
return (0, number_1.formatUnits)(effectiveDstAmount, constants_1.USDC_BASE.decimals);
|
|
166
|
+
}, [effectiveDstAmount]);
|
|
167
|
+
// Encode the contract function call (with or without discount)
|
|
71
168
|
const encodedData = (0, react_1.useMemo)(() => {
|
|
72
169
|
try {
|
|
170
|
+
if (discountCode && discountInfo.isValid) {
|
|
171
|
+
return (0, viem_1.encodeFunctionData)({
|
|
172
|
+
abi: [BUY_PACKS_FOR_WITH_DISCOUNT_ABI],
|
|
173
|
+
functionName: "buyPacksForWithDiscount",
|
|
174
|
+
args: [recipientAddress, BigInt(packId), BigInt(packAmount), discountCode],
|
|
175
|
+
});
|
|
176
|
+
}
|
|
73
177
|
return (0, viem_1.encodeFunctionData)({
|
|
74
178
|
abi: [BUY_PACKS_FOR_ABI],
|
|
75
179
|
functionName: "buyPacksFor",
|
|
@@ -77,17 +181,30 @@ function AnySpendCollectorClubPurchase({ loadOrder, mode = "modal", activeTab =
|
|
|
77
181
|
});
|
|
78
182
|
}
|
|
79
183
|
catch (error) {
|
|
80
|
-
console.error("Failed to encode function data", { recipientAddress, packId, packAmount, error });
|
|
184
|
+
console.error("Failed to encode function data", { recipientAddress, packId, packAmount, discountCode, error });
|
|
81
185
|
return "0x";
|
|
82
186
|
}
|
|
83
|
-
}, [recipientAddress, packId, packAmount]);
|
|
187
|
+
}, [recipientAddress, packId, packAmount, discountCode, discountInfo.isValid]);
|
|
84
188
|
// Default header if not provided
|
|
85
189
|
const defaultHeader = () => ((0, jsx_runtime_1.jsx)("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-as-primary text-xl font-bold", children: "Buy Collector Club Packs" }), (0, jsx_runtime_1.jsxs)("p", { className: "text-as-secondary text-sm", children: ["Purchase ", packAmount, " pack", packAmount !== 1 ? "s" : "", " using any token"] })] }) }));
|
|
86
|
-
|
|
190
|
+
// Don't render AnySpendCustom while discount is being validated (avoids showing wrong price)
|
|
191
|
+
if (discountCode && discountInfo.isLoading) {
|
|
192
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: (0, jsx_runtime_1.jsx)("p", { className: "text-as-secondary text-sm", children: "Validating discount code..." }) }));
|
|
193
|
+
}
|
|
194
|
+
if (discountCode && discountInfo.error) {
|
|
195
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-red-500", children: discountInfo.error }) }));
|
|
196
|
+
}
|
|
197
|
+
if (discountCode && discountInfo.isValid && effectiveDstAmount === "0") {
|
|
198
|
+
return ((0, jsx_runtime_1.jsx)("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-red-500", children: "Discount exceeds total price" }) }));
|
|
199
|
+
}
|
|
200
|
+
return ((0, jsx_runtime_1.jsx)(AnySpendCustom_1.AnySpendCustom, { loadOrder: loadOrder, mode: mode, activeTab: activeTab, recipientAddress: recipientAddress, spenderAddress: spenderAddress ?? ccShopAddress, orderType: "custom", dstChainId: BASE_CHAIN_ID, dstToken: paymentToken, dstAmount: effectiveDstAmount, contractAddress: ccShopAddress, encodedData: encodedData, metadata: {
|
|
87
201
|
packId,
|
|
88
202
|
packAmount,
|
|
89
203
|
pricePerPack,
|
|
90
204
|
vendingMachineId,
|
|
91
205
|
packType,
|
|
206
|
+
...(discountCode && discountInfo.isValid
|
|
207
|
+
? { discountCode, discountAmount: discountInfo.discountAmount.toString() }
|
|
208
|
+
: {}),
|
|
92
209
|
}, header: header || defaultHeader, onSuccess: onSuccess, showRecipient: showRecipient, srcFiatAmount: srcFiatAmount, forceFiatPayment: forceFiatPayment }));
|
|
93
210
|
}
|
|
@@ -131,6 +131,8 @@ function QRDeposit({ mode = "modal", recipientAddress, sourceToken: sourceTokenP
|
|
|
131
131
|
(0, useOnOrderSuccess_1.useOnOrderSuccess)({ orderData: oat, orderId, onSuccess });
|
|
132
132
|
// For pure transfers, always use recipient address; for orders, use global address
|
|
133
133
|
const displayAddress = isPureTransfer ? recipientAddress : globalAddress || recipientAddress;
|
|
134
|
+
// Generate EIP-681 payment URI for the QR code so wallets know which chain/token to use
|
|
135
|
+
const qrValue = (0, anyspend_1.getPaymentUrl)(displayAddress, undefined, sourceToken.address === anyspend_1.ZERO_ADDRESS ? "ETH" : sourceToken.address, sourceChainId, sourceToken.decimals);
|
|
134
136
|
const handleCopyAddress = async () => {
|
|
135
137
|
if (displayAddress) {
|
|
136
138
|
await navigator.clipboard.writeText(displayAddress);
|
|
@@ -163,7 +165,7 @@ function QRDeposit({ mode = "modal", recipientAddress, sourceToken: sourceTokenP
|
|
|
163
165
|
}
|
|
164
166
|
return ((0, jsx_runtime_1.jsx)("div", { className: classes?.container ||
|
|
165
167
|
(0, cn_1.cn)("anyspend-container anyspend-qr-deposit font-inter bg-as-surface-primary mx-auto w-full max-w-[460px] p-6", mode === "page" && "border-as-border-secondary overflow-hidden rounded-2xl border shadow-xl"), children: (0, jsx_runtime_1.jsxs)("div", { className: classes?.content || "anyspend-qr-deposit-content flex flex-col gap-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: classes?.header || "anyspend-qr-header flex items-center justify-between", children: [(0, jsx_runtime_1.jsx)("button", { onClick: handleBack, className: classes?.backButton || "anyspend-qr-back-button text-as-secondary hover:text-as-primary", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) }) }), (0, jsx_runtime_1.jsx)("h2", { className: classes?.title || "anyspend-qr-title text-as-primary text-base font-semibold", children: "Deposit" }), onClose ? ((0, jsx_runtime_1.jsx)("button", { onClick: handleClose, className: classes?.closeButton || "anyspend-qr-close-button text-as-secondary hover:text-as-primary", children: (0, jsx_runtime_1.jsx)("svg", { className: "h-5 w-5", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: (0, jsx_runtime_1.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "w-5" }))] }), (0, jsx_runtime_1.jsxs)("div", { className: classes?.tokenSelectorContainer || "anyspend-qr-token-selector flex flex-col gap-1.5", children: [(0, jsx_runtime_1.jsx)("label", { className: classes?.tokenSelectorLabel || "anyspend-qr-token-label text-as-secondary text-sm", children: "Send" }), (0, jsx_runtime_1.jsx)(relay_kit_ui_1.TokenSelector, { chainIdsFilter: (0, anyspend_1.getAvailableChainIds)("from"), context: "from", fromChainWalletVMSupported: true, isValidAddress: true, lockedChainIds: (0, anyspend_1.getAvailableChainIds)("from"), multiWalletSupportEnabled: true, onAnalyticEvent: undefined, setToken: handleTokenSelect, supportedWalletVMs: ["evm"], token: undefined, trigger: (0, jsx_runtime_1.jsxs)(react_1.Button, { variant: "outline", role: "combobox", className: classes?.tokenSelectorTrigger ||
|
|
166
|
-
"anyspend-qr-token-trigger border-as-stroke bg-as-surface-secondary flex h-auto w-full items-center justify-between gap-2 rounded-xl border px-3 py-2.5", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [sourceToken.metadata?.logoURI ? ((0, jsx_runtime_1.jsx)(ChainTokenIcon_1.ChainTokenIcon, { chainUrl: anyspend_1.ALL_CHAINS[sourceChainId]?.logoUrl, tokenUrl: sourceToken.metadata.logoURI, className: "h-8 min-h-8 w-8 min-w-8" })) : ((0, jsx_runtime_1.jsx)("div", { className: "h-8 w-8 rounded-full bg-gray-700" })), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-start gap-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-as-primary font-semibold", children: sourceToken.symbol }), (0, jsx_runtime_1.jsx)("div", { className: "text-as-primary/70 text-xs", children: anyspend_1.ALL_CHAINS[sourceChainId]?.name ?? "Unknown" })] })] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-70" })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: classes?.qrContent || "anyspend-qr-content border-as-stroke flex items-start gap-4 rounded-xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: classes?.qrCodeContainer || "anyspend-qr-code-container flex flex-col items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: classes?.qrCode || "anyspend-qr-code rounded-lg bg-white p-2", children: (0, jsx_runtime_1.jsx)(qrcode_react_1.QRCodeSVG, { value:
|
|
168
|
+
"anyspend-qr-token-trigger border-as-stroke bg-as-surface-secondary flex h-auto w-full items-center justify-between gap-2 rounded-xl border px-3 py-2.5", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-2", children: [sourceToken.metadata?.logoURI ? ((0, jsx_runtime_1.jsx)(ChainTokenIcon_1.ChainTokenIcon, { chainUrl: anyspend_1.ALL_CHAINS[sourceChainId]?.logoUrl, tokenUrl: sourceToken.metadata.logoURI, className: "h-8 min-h-8 w-8 min-w-8" })) : ((0, jsx_runtime_1.jsx)("div", { className: "h-8 w-8 rounded-full bg-gray-700" })), (0, jsx_runtime_1.jsxs)("div", { className: "flex flex-col items-start gap-0", children: [(0, jsx_runtime_1.jsx)("div", { className: "text-as-primary font-semibold", children: sourceToken.symbol }), (0, jsx_runtime_1.jsx)("div", { className: "text-as-primary/70 text-xs", children: anyspend_1.ALL_CHAINS[sourceChainId]?.name ?? "Unknown" })] })] }), (0, jsx_runtime_1.jsx)(lucide_react_1.ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-70" })] }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: classes?.qrContent || "anyspend-qr-content border-as-stroke flex items-start gap-4 rounded-xl border p-4", children: [(0, jsx_runtime_1.jsxs)("div", { className: classes?.qrCodeContainer || "anyspend-qr-code-container flex flex-col items-center gap-2", children: [(0, jsx_runtime_1.jsx)("div", { className: classes?.qrCode || "anyspend-qr-code rounded-lg bg-white p-2", children: (0, jsx_runtime_1.jsx)(qrcode_react_1.QRCodeSVG, { value: qrValue, size: 120, level: "M", marginSize: 0 }) }), (0, jsx_runtime_1.jsxs)("span", { className: classes?.qrScanHint || "anyspend-qr-scan-hint text-as-secondary text-xs", children: ["SCAN WITH ", (0, jsx_runtime_1.jsx)("span", { className: "inline-block", children: "\uD83E\uDD8A" })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: classes?.addressContainer || "anyspend-qr-address-container flex flex-1 flex-col gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: classes?.addressLabel || "anyspend-qr-address-label text-as-secondary text-sm", children: "Deposit address:" }), (0, jsx_runtime_1.jsxs)("div", { className: classes?.addressRow || "anyspend-qr-address-row flex items-start gap-1", children: [(0, jsx_runtime_1.jsx)("span", { className: classes?.address || "anyspend-qr-address text-as-primary break-all font-mono text-sm leading-relaxed", children: displayAddress }), (0, jsx_runtime_1.jsx)("button", { onClick: handleCopyAddress, className: classes?.addressCopyIcon ||
|
|
167
169
|
"anyspend-qr-copy-icon text-as-secondary hover:text-as-primary mt-0.5 shrink-0", children: copied ? (0, jsx_runtime_1.jsx)(lucide_react_1.Check, { className: "h-4 w-4" }) : (0, jsx_runtime_1.jsx)(lucide_react_1.Copy, { className: "h-4 w-4" }) })] })] })] }), (0, jsx_runtime_1.jsx)(WarningText_1.ChainWarningText, { chainId: destinationChainId }), (0, jsx_runtime_1.jsxs)(WarningText_1.WarningText, { children: ["Only send ", sourceToken.symbol, " on ", anyspend_1.ALL_CHAINS[sourceChainId]?.name ?? "the specified chain", ". Other tokens will not be converted."] }), isPureTransfer && isWatchingTransfer && ((0, jsx_runtime_1.jsxs)("div", { className: classes?.watchingIndicator ||
|
|
168
170
|
"anyspend-qr-watching flex items-center justify-center gap-2 rounded-lg bg-blue-500/10 p-3", children: [(0, jsx_runtime_1.jsx)(lucide_react_1.Loader2, { className: "h-4 w-4 animate-spin text-blue-500" }), (0, jsx_runtime_1.jsx)("span", { className: "text-sm text-blue-500", children: "Watching for incoming transfer..." })] })), (0, jsx_runtime_1.jsx)("button", { onClick: handleCopyAddress, className: classes?.copyButton ||
|
|
169
171
|
"anyspend-qr-copy-button flex w-full items-center justify-center gap-2 rounded-xl bg-blue-500 py-3.5 font-medium text-white transition-all hover:bg-blue-600", children: "Copy deposit address" })] }) }));
|
|
@@ -82,7 +82,7 @@ export declare function isTestnet(chainId: number): boolean;
|
|
|
82
82
|
export declare function getDefaultToken(chainId: number): components["schemas"]["Token"];
|
|
83
83
|
export declare function getChainName(chainId: number): string;
|
|
84
84
|
export declare function getCoingeckoName(chainId: number): string | null;
|
|
85
|
-
export declare function getPaymentUrl(address: string, amount: bigint, currency: string, chainId: number, decimals?: number): string;
|
|
85
|
+
export declare function getPaymentUrl(address: string, amount: bigint | undefined, currency: string, chainId: number, decimals?: number): string;
|
|
86
86
|
export declare function getExplorerTxUrl(chainId: number, txHash: string): string;
|
|
87
87
|
export declare function getExplorerAddressUrl(chainId: number, address: string): string;
|
|
88
88
|
export declare function getMulticall3Address(chainId: number): string;
|
|
@@ -392,8 +392,8 @@ function getPaymentUrl(address, amount, currency, chainId, decimals) {
|
|
|
392
392
|
// For EVM chains, follow EIP-681 format
|
|
393
393
|
// Format: ethereum:[address]@[chainId]?value=[amount]&symbol=[symbol]
|
|
394
394
|
const params = new URLSearchParams();
|
|
395
|
-
// Add value for native token transfers
|
|
396
|
-
if (currency === chain.nativeToken.symbol) {
|
|
395
|
+
// Add value for native token transfers (skip if amount not provided, e.g. deposit_first)
|
|
396
|
+
if (currency === chain.nativeToken.symbol && amount !== undefined) {
|
|
397
397
|
params.append("value", amount.toString());
|
|
398
398
|
}
|
|
399
399
|
// Handle token transfers differently from native transfers
|
|
@@ -408,28 +408,31 @@ function getPaymentUrl(address, amount, currency, chainId, decimals) {
|
|
|
408
408
|
}
|
|
409
409
|
// For ERC20 tokens, convert from smallest unit to display units using decimals
|
|
410
410
|
// For example: 2400623 (raw) with 6 decimals becomes "2.400623"
|
|
411
|
-
|
|
412
|
-
if (
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
411
|
+
// Skip amount if not provided (e.g. deposit_first orders)
|
|
412
|
+
if (amount !== undefined) {
|
|
413
|
+
let displayAmount;
|
|
414
|
+
if (decimals !== undefined && currency !== chain.nativeToken.symbol) {
|
|
415
|
+
// Convert from smallest unit to display unit for ERC20 tokens
|
|
416
|
+
const divisor = BigInt(10 ** decimals);
|
|
417
|
+
const wholePart = amount / divisor;
|
|
418
|
+
const fractionalPart = amount % divisor;
|
|
419
|
+
if (fractionalPart === BigInt(0)) {
|
|
420
|
+
displayAmount = wholePart.toString();
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
// Format fractional part with leading zeros if needed
|
|
424
|
+
const fractionalStr = fractionalPart.toString().padStart(decimals, "0");
|
|
425
|
+
// Remove trailing zeros
|
|
426
|
+
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
427
|
+
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
428
|
+
}
|
|
419
429
|
}
|
|
420
430
|
else {
|
|
421
|
-
//
|
|
422
|
-
|
|
423
|
-
// Remove trailing zeros
|
|
424
|
-
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
425
|
-
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
431
|
+
// For native tokens or when decimals not provided, use raw amount
|
|
432
|
+
displayAmount = amount.toString();
|
|
426
433
|
}
|
|
434
|
+
tokenParams.append("amount", displayAmount);
|
|
427
435
|
}
|
|
428
|
-
else {
|
|
429
|
-
// For native tokens or when decimals not provided, use raw amount
|
|
430
|
-
displayAmount = amount.toString();
|
|
431
|
-
}
|
|
432
|
-
tokenParams.append("amount", displayAmount);
|
|
433
436
|
tokenParams.append("address", address); // recipient address
|
|
434
437
|
// For Arbitrum and other L2s, try a more explicit format
|
|
435
438
|
if (chainId !== chains_1.mainnet.id) {
|
|
@@ -449,7 +452,9 @@ function getPaymentUrl(address, amount, currency, chainId, decimals) {
|
|
|
449
452
|
// to make sure wallets recognize the correct chain
|
|
450
453
|
const nativeParams = new URLSearchParams();
|
|
451
454
|
nativeParams.append("chainId", chainId.toString());
|
|
452
|
-
|
|
455
|
+
if (amount !== undefined) {
|
|
456
|
+
nativeParams.append("value", amount.toString());
|
|
457
|
+
}
|
|
453
458
|
const url = `ethereum:${address}@${chainId}?${nativeParams.toString()}`;
|
|
454
459
|
return url;
|
|
455
460
|
}
|
|
@@ -468,60 +473,65 @@ function getPaymentUrl(address, amount, currency, chainId, decimals) {
|
|
|
468
473
|
const isNativeSOL = currency === chain.nativeToken.symbol || currency === "SOL" || currency === "11111111111111111111111111111111";
|
|
469
474
|
if (isNativeSOL) {
|
|
470
475
|
// Native SOL transfers - convert from lamports to SOL
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
else {
|
|
486
|
-
// Fallback: assume SOL has 9 decimals
|
|
487
|
-
const divisor = BigInt(1000000000); // 1e9
|
|
488
|
-
const wholePart = amount / divisor;
|
|
489
|
-
const fractionalPart = amount % divisor;
|
|
490
|
-
if (fractionalPart === BigInt(0)) {
|
|
491
|
-
displayAmount = wholePart.toString();
|
|
476
|
+
if (amount !== undefined) {
|
|
477
|
+
let displayAmount;
|
|
478
|
+
if (decimals !== undefined) {
|
|
479
|
+
const divisor = BigInt(10 ** decimals);
|
|
480
|
+
const wholePart = amount / divisor;
|
|
481
|
+
const fractionalPart = amount % divisor;
|
|
482
|
+
if (fractionalPart === BigInt(0)) {
|
|
483
|
+
displayAmount = wholePart.toString();
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
const fractionalStr = fractionalPart.toString().padStart(decimals, "0");
|
|
487
|
+
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
488
|
+
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
489
|
+
}
|
|
492
490
|
}
|
|
493
491
|
else {
|
|
494
|
-
|
|
495
|
-
const
|
|
496
|
-
|
|
492
|
+
// Fallback: assume SOL has 9 decimals
|
|
493
|
+
const divisor = BigInt(1000000000); // 1e9
|
|
494
|
+
const wholePart = amount / divisor;
|
|
495
|
+
const fractionalPart = amount % divisor;
|
|
496
|
+
if (fractionalPart === BigInt(0)) {
|
|
497
|
+
displayAmount = wholePart.toString();
|
|
498
|
+
}
|
|
499
|
+
else {
|
|
500
|
+
const fractionalStr = fractionalPart.toString().padStart(9, "0");
|
|
501
|
+
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
502
|
+
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
503
|
+
}
|
|
497
504
|
}
|
|
505
|
+
// For native SOL, use simple format without spl-token parameter
|
|
506
|
+
params.append("amount", displayAmount);
|
|
498
507
|
}
|
|
499
|
-
// For native SOL, use simple format without spl-token parameter
|
|
500
|
-
params.append("amount", displayAmount);
|
|
501
508
|
}
|
|
502
509
|
else {
|
|
503
510
|
// SPL token transfers
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
+
if (amount !== undefined) {
|
|
512
|
+
let displayAmount;
|
|
513
|
+
if (decimals !== undefined) {
|
|
514
|
+
const divisor = BigInt(10 ** decimals);
|
|
515
|
+
const wholePart = amount / divisor;
|
|
516
|
+
const fractionalPart = amount % divisor;
|
|
517
|
+
if (fractionalPart === BigInt(0)) {
|
|
518
|
+
displayAmount = wholePart.toString();
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
const fractionalStr = fractionalPart.toString().padStart(decimals, "0");
|
|
522
|
+
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
523
|
+
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
524
|
+
}
|
|
511
525
|
}
|
|
512
526
|
else {
|
|
513
|
-
|
|
514
|
-
const trimmedFractional = fractionalStr.replace(/0+$/, "");
|
|
515
|
-
displayAmount = trimmedFractional ? `${wholePart}.${trimmedFractional}` : wholePart.toString();
|
|
527
|
+
displayAmount = amount.toString();
|
|
516
528
|
}
|
|
529
|
+
params.append("amount", displayAmount);
|
|
517
530
|
}
|
|
518
|
-
else {
|
|
519
|
-
displayAmount = amount.toString();
|
|
520
|
-
}
|
|
521
|
-
params.append("amount", displayAmount);
|
|
522
531
|
params.append("spl-token", currency); // token mint address
|
|
523
532
|
}
|
|
524
|
-
const
|
|
533
|
+
const queryString = params.toString();
|
|
534
|
+
const url = queryString ? `solana:${address}?${queryString}` : `solana:${address}`;
|
|
525
535
|
console.log("Solana URL (isNativeSOL:", isNativeSOL, "):", url);
|
|
526
536
|
return url;
|
|
527
537
|
}
|
|
@@ -470,6 +470,8 @@ export interface AnySpendCollectorClubPurchaseProps extends BaseModalProps {
|
|
|
470
470
|
forceFiatPayment?: boolean;
|
|
471
471
|
/** Staging environment support */
|
|
472
472
|
isStaging?: boolean;
|
|
473
|
+
/** Optional discount code to apply to the purchase */
|
|
474
|
+
discountCode?: string;
|
|
473
475
|
}
|
|
474
476
|
/**
|
|
475
477
|
* Props for the AnySpend Deposit modal
|
|
@@ -69,5 +69,10 @@ export interface AnySpendCollectorClubPurchaseProps {
|
|
|
69
69
|
* Force fiat payment
|
|
70
70
|
*/
|
|
71
71
|
forceFiatPayment?: boolean;
|
|
72
|
+
/**
|
|
73
|
+
* Optional discount code to apply to the purchase.
|
|
74
|
+
* When provided, validates on-chain and adjusts the price accordingly.
|
|
75
|
+
*/
|
|
76
|
+
discountCode?: string;
|
|
72
77
|
}
|
|
73
|
-
export declare function AnySpendCollectorClubPurchase({ loadOrder, mode, activeTab, packId, packAmount, pricePerPack, paymentToken, recipientAddress, spenderAddress, isStaging, onSuccess, header, showRecipient, vendingMachineId, packType, forceFiatPayment, }: AnySpendCollectorClubPurchaseProps): import("react/jsx-runtime").JSX.Element;
|
|
78
|
+
export declare function AnySpendCollectorClubPurchase({ loadOrder, mode, activeTab, packId, packAmount, pricePerPack, paymentToken, recipientAddress, spenderAddress, isStaging, onSuccess, header, showRecipient, vendingMachineId, packType, forceFiatPayment, discountCode, }: AnySpendCollectorClubPurchaseProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -26,9 +26,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
import { USDC_BASE } from "../../../anyspend/constants/index.js";
|
|
29
|
+
import { PUBLIC_BASE_RPC_URL } from "../../../shared/constants/index.js";
|
|
29
30
|
import { formatUnits } from "../../../shared/utils/number.js";
|
|
30
|
-
import { useMemo } from "react";
|
|
31
|
-
import { encodeFunctionData } from "viem";
|
|
31
|
+
import { useEffect, useMemo, useState } from "react";
|
|
32
|
+
import { createPublicClient, encodeFunctionData, http } from "viem";
|
|
33
|
+
import { base } from "viem/chains";
|
|
32
34
|
import { AnySpendCustom } from "./AnySpendCustom.js";
|
|
33
35
|
// Collector Club Shop contract addresses on Base
|
|
34
36
|
const CC_SHOP_ADDRESS = "0x47366E64E4917dd4DdC04Fb9DC507c1dD2b87294";
|
|
@@ -46,7 +48,35 @@ const BUY_PACKS_FOR_ABI = {
|
|
|
46
48
|
stateMutability: "nonpayable",
|
|
47
49
|
type: "function",
|
|
48
50
|
};
|
|
49
|
-
|
|
51
|
+
// ABI for buyPacksForWithDiscount function (with discount code)
|
|
52
|
+
const BUY_PACKS_FOR_WITH_DISCOUNT_ABI = {
|
|
53
|
+
inputs: [
|
|
54
|
+
{ internalType: "address", name: "user", type: "address" },
|
|
55
|
+
{ internalType: "uint256", name: "packId", type: "uint256" },
|
|
56
|
+
{ internalType: "uint256", name: "amount", type: "uint256" },
|
|
57
|
+
{ internalType: "string", name: "discountCode", type: "string" },
|
|
58
|
+
],
|
|
59
|
+
name: "buyPacksForWithDiscount",
|
|
60
|
+
outputs: [],
|
|
61
|
+
stateMutability: "nonpayable",
|
|
62
|
+
type: "function",
|
|
63
|
+
};
|
|
64
|
+
// ABI for isDiscountCodeValid view function
|
|
65
|
+
const IS_DISCOUNT_CODE_VALID_ABI = {
|
|
66
|
+
inputs: [{ internalType: "string", name: "code", type: "string" }],
|
|
67
|
+
name: "isDiscountCodeValid",
|
|
68
|
+
outputs: [
|
|
69
|
+
{ internalType: "bool", name: "isValid", type: "bool" },
|
|
70
|
+
{ internalType: "uint256", name: "discountAmount", type: "uint256" },
|
|
71
|
+
],
|
|
72
|
+
stateMutability: "view",
|
|
73
|
+
type: "function",
|
|
74
|
+
};
|
|
75
|
+
const basePublicClient = createPublicClient({
|
|
76
|
+
chain: base,
|
|
77
|
+
transport: http(PUBLIC_BASE_RPC_URL),
|
|
78
|
+
});
|
|
79
|
+
export function AnySpendCollectorClubPurchase({ loadOrder, mode = "modal", activeTab = "crypto", packId, packAmount, pricePerPack, paymentToken = USDC_BASE, recipientAddress, spenderAddress, isStaging = false, onSuccess, header, showRecipient = true, vendingMachineId, packType, forceFiatPayment, discountCode, }) {
|
|
50
80
|
const ccShopAddress = isStaging ? CC_SHOP_ADDRESS_STAGING : CC_SHOP_ADDRESS;
|
|
51
81
|
// Calculate total amount needed (pricePerPack * packAmount)
|
|
52
82
|
const totalAmount = useMemo(() => {
|
|
@@ -58,15 +88,89 @@ export function AnySpendCollectorClubPurchase({ loadOrder, mode = "modal", activ
|
|
|
58
88
|
return "0";
|
|
59
89
|
}
|
|
60
90
|
}, [pricePerPack, packAmount]);
|
|
61
|
-
//
|
|
91
|
+
// Discount code validation state
|
|
92
|
+
const [discountInfo, setDiscountInfo] = useState({
|
|
93
|
+
isValid: false,
|
|
94
|
+
discountAmount: BigInt(0),
|
|
95
|
+
isLoading: false,
|
|
96
|
+
error: null,
|
|
97
|
+
});
|
|
98
|
+
// Validate discount code on-chain when provided
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
if (!discountCode) {
|
|
101
|
+
setDiscountInfo({ isValid: false, discountAmount: BigInt(0), isLoading: false, error: null });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
let cancelled = false;
|
|
105
|
+
const validateDiscount = async () => {
|
|
106
|
+
setDiscountInfo(prev => ({ ...prev, isLoading: true, error: null }));
|
|
107
|
+
try {
|
|
108
|
+
const result = await basePublicClient.readContract({
|
|
109
|
+
address: ccShopAddress,
|
|
110
|
+
abi: [IS_DISCOUNT_CODE_VALID_ABI],
|
|
111
|
+
functionName: "isDiscountCodeValid",
|
|
112
|
+
args: [discountCode],
|
|
113
|
+
});
|
|
114
|
+
if (cancelled)
|
|
115
|
+
return;
|
|
116
|
+
const [isValid, discountAmount] = result;
|
|
117
|
+
if (!isValid) {
|
|
118
|
+
setDiscountInfo({
|
|
119
|
+
isValid: false,
|
|
120
|
+
discountAmount: BigInt(0),
|
|
121
|
+
isLoading: false,
|
|
122
|
+
error: "Invalid or expired discount code",
|
|
123
|
+
});
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
setDiscountInfo({ isValid: true, discountAmount, isLoading: false, error: null });
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (cancelled)
|
|
130
|
+
return;
|
|
131
|
+
console.error("Failed to validate discount code", { discountCode, error });
|
|
132
|
+
setDiscountInfo({
|
|
133
|
+
isValid: false,
|
|
134
|
+
discountAmount: BigInt(0),
|
|
135
|
+
isLoading: false,
|
|
136
|
+
error: "Failed to validate discount code",
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
validateDiscount();
|
|
141
|
+
return () => {
|
|
142
|
+
cancelled = true;
|
|
143
|
+
};
|
|
144
|
+
}, [discountCode, ccShopAddress]);
|
|
145
|
+
// Calculate effective dstAmount after discount
|
|
146
|
+
const effectiveDstAmount = useMemo(() => {
|
|
147
|
+
if (!discountCode || !discountInfo.isValid || discountInfo.discountAmount === BigInt(0)) {
|
|
148
|
+
return totalAmount;
|
|
149
|
+
}
|
|
150
|
+
const total = BigInt(totalAmount);
|
|
151
|
+
const discount = discountInfo.discountAmount;
|
|
152
|
+
if (discount >= total) {
|
|
153
|
+
console.error("Discount exceeds total price", { totalAmount, discountAmount: discount.toString() });
|
|
154
|
+
return "0";
|
|
155
|
+
}
|
|
156
|
+
return (total - discount).toString();
|
|
157
|
+
}, [totalAmount, discountCode, discountInfo.isValid, discountInfo.discountAmount]);
|
|
158
|
+
// Calculate fiat amount (effectiveDstAmount in USD, assuming USDC with 6 decimals)
|
|
62
159
|
const srcFiatAmount = useMemo(() => {
|
|
63
|
-
if (!
|
|
160
|
+
if (!effectiveDstAmount || effectiveDstAmount === "0")
|
|
64
161
|
return "0";
|
|
65
|
-
return formatUnits(
|
|
66
|
-
}, [
|
|
67
|
-
// Encode the
|
|
162
|
+
return formatUnits(effectiveDstAmount, USDC_BASE.decimals);
|
|
163
|
+
}, [effectiveDstAmount]);
|
|
164
|
+
// Encode the contract function call (with or without discount)
|
|
68
165
|
const encodedData = useMemo(() => {
|
|
69
166
|
try {
|
|
167
|
+
if (discountCode && discountInfo.isValid) {
|
|
168
|
+
return encodeFunctionData({
|
|
169
|
+
abi: [BUY_PACKS_FOR_WITH_DISCOUNT_ABI],
|
|
170
|
+
functionName: "buyPacksForWithDiscount",
|
|
171
|
+
args: [recipientAddress, BigInt(packId), BigInt(packAmount), discountCode],
|
|
172
|
+
});
|
|
173
|
+
}
|
|
70
174
|
return encodeFunctionData({
|
|
71
175
|
abi: [BUY_PACKS_FOR_ABI],
|
|
72
176
|
functionName: "buyPacksFor",
|
|
@@ -74,17 +178,30 @@ export function AnySpendCollectorClubPurchase({ loadOrder, mode = "modal", activ
|
|
|
74
178
|
});
|
|
75
179
|
}
|
|
76
180
|
catch (error) {
|
|
77
|
-
console.error("Failed to encode function data", { recipientAddress, packId, packAmount, error });
|
|
181
|
+
console.error("Failed to encode function data", { recipientAddress, packId, packAmount, discountCode, error });
|
|
78
182
|
return "0x";
|
|
79
183
|
}
|
|
80
|
-
}, [recipientAddress, packId, packAmount]);
|
|
184
|
+
}, [recipientAddress, packId, packAmount, discountCode, discountInfo.isValid]);
|
|
81
185
|
// Default header if not provided
|
|
82
186
|
const defaultHeader = () => (_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsxs("div", { children: [_jsx("h1", { className: "text-as-primary text-xl font-bold", children: "Buy Collector Club Packs" }), _jsxs("p", { className: "text-as-secondary text-sm", children: ["Purchase ", packAmount, " pack", packAmount !== 1 ? "s" : "", " using any token"] })] }) }));
|
|
83
|
-
|
|
187
|
+
// Don't render AnySpendCustom while discount is being validated (avoids showing wrong price)
|
|
188
|
+
if (discountCode && discountInfo.isLoading) {
|
|
189
|
+
return (_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsx("p", { className: "text-as-secondary text-sm", children: "Validating discount code..." }) }));
|
|
190
|
+
}
|
|
191
|
+
if (discountCode && discountInfo.error) {
|
|
192
|
+
return (_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsx("p", { className: "text-sm text-red-500", children: discountInfo.error }) }));
|
|
193
|
+
}
|
|
194
|
+
if (discountCode && discountInfo.isValid && effectiveDstAmount === "0") {
|
|
195
|
+
return (_jsx("div", { className: "mb-4 flex flex-col items-center gap-3 text-center", children: _jsx("p", { className: "text-sm text-red-500", children: "Discount exceeds total price" }) }));
|
|
196
|
+
}
|
|
197
|
+
return (_jsx(AnySpendCustom, { loadOrder: loadOrder, mode: mode, activeTab: activeTab, recipientAddress: recipientAddress, spenderAddress: spenderAddress ?? ccShopAddress, orderType: "custom", dstChainId: BASE_CHAIN_ID, dstToken: paymentToken, dstAmount: effectiveDstAmount, contractAddress: ccShopAddress, encodedData: encodedData, metadata: {
|
|
84
198
|
packId,
|
|
85
199
|
packAmount,
|
|
86
200
|
pricePerPack,
|
|
87
201
|
vendingMachineId,
|
|
88
202
|
packType,
|
|
203
|
+
...(discountCode && discountInfo.isValid
|
|
204
|
+
? { discountCode, discountAmount: discountInfo.discountAmount.toString() }
|
|
205
|
+
: {}),
|
|
89
206
|
}, header: header || defaultHeader, onSuccess: onSuccess, showRecipient: showRecipient, srcFiatAmount: srcFiatAmount, forceFiatPayment: forceFiatPayment }));
|
|
90
207
|
}
|