@b3dotfun/sdk 0.0.1-alpha.9 → 0.0.3-alpha.1
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/AnySpend.d.ts +2 -1
- package/dist/cjs/anyspend/react/components/AnySpend.js +4 -4
- package/dist/cjs/anyspend/react/components/AnySpendBuySpin.d.ts +2 -1
- package/dist/cjs/anyspend/react/components/AnySpendBuySpin.js +124 -53
- package/dist/cjs/global-account/react/components/B3DynamicModal.js +2 -2
- package/dist/cjs/global-account/react/components/{B3Provider.d.ts → B3Provider/B3Provider.d.ts} +3 -29
- package/dist/cjs/global-account/react/components/{B3Provider.js → B3Provider/B3Provider.js} +6 -34
- package/dist/{esm/global-account/react/components → cjs/global-account/react/components/B3Provider}/B3Provider.native.d.ts +2 -25
- package/dist/cjs/global-account/react/components/{B3Provider.native.js → B3Provider/B3Provider.native.js} +5 -28
- package/dist/cjs/global-account/react/components/B3Provider/types.d.ts +25 -0
- package/dist/cjs/global-account/react/components/B3Provider/types.js +20 -0
- package/dist/cjs/global-account/react/components/B3Provider/useB3.d.ts +5 -0
- package/dist/cjs/global-account/react/components/B3Provider/useB3.js +17 -0
- package/dist/cjs/global-account/react/components/StyleRoot.js +2 -2
- package/dist/cjs/global-account/react/components/index.d.ts +8 -6
- package/dist/cjs/global-account/react/components/index.js +18 -16
- package/dist/cjs/global-account/react/index.native.d.ts +5 -4
- package/dist/cjs/global-account/react/index.native.js +10 -8
- package/dist/cjs/global-account/react/stores/useModalStore.d.ts +2 -0
- package/dist/cjs/global-account/types/chain-networks.d.ts +34 -34
- package/dist/cjs/global-account/types/feature-flags.d.ts +5 -5
- package/dist/cjs/shared/constants/chains/b3Chain.d.ts +1 -1
- package/dist/cjs/shared/constants/chains/supported.d.ts +4 -3
- package/dist/cjs/shared/constants/chains/supported.js +3 -1
- package/dist/esm/anyspend/react/components/AnySpend.d.ts +2 -1
- package/dist/esm/anyspend/react/components/AnySpend.js +4 -4
- package/dist/esm/anyspend/react/components/AnySpendBuySpin.d.ts +2 -1
- package/dist/esm/anyspend/react/components/AnySpendBuySpin.js +124 -53
- package/dist/esm/global-account/react/components/B3DynamicModal.js +1 -1
- package/dist/esm/global-account/react/components/{B3Provider.d.ts → B3Provider/B3Provider.d.ts} +3 -29
- package/dist/esm/global-account/react/components/{B3Provider.js → B3Provider/B3Provider.js} +5 -32
- package/dist/{cjs/global-account/react/components → esm/global-account/react/components/B3Provider}/B3Provider.native.d.ts +2 -25
- package/dist/esm/global-account/react/components/{B3Provider.native.js → B3Provider/B3Provider.native.js} +5 -26
- package/dist/esm/global-account/react/components/B3Provider/types.d.ts +25 -0
- package/dist/esm/global-account/react/components/B3Provider/types.js +17 -0
- package/dist/esm/global-account/react/components/B3Provider/useB3.d.ts +5 -0
- package/dist/esm/global-account/react/components/B3Provider/useB3.js +14 -0
- package/dist/esm/global-account/react/components/StyleRoot.js +1 -1
- package/dist/esm/global-account/react/components/index.d.ts +8 -6
- package/dist/esm/global-account/react/components/index.js +7 -5
- package/dist/esm/global-account/react/index.native.d.ts +5 -4
- package/dist/esm/global-account/react/index.native.js +5 -4
- package/dist/esm/global-account/react/stores/useModalStore.d.ts +2 -0
- package/dist/esm/global-account/types/chain-networks.d.ts +34 -34
- package/dist/esm/global-account/types/feature-flags.d.ts +5 -5
- package/dist/esm/shared/constants/chains/b3Chain.d.ts +1 -1
- package/dist/esm/shared/constants/chains/supported.d.ts +4 -3
- package/dist/esm/shared/constants/chains/supported.js +2 -0
- package/dist/styles/index.css +1 -1
- package/dist/types/anyspend/react/components/AnySpend.d.ts +2 -1
- package/dist/types/anyspend/react/components/AnySpendBuySpin.d.ts +2 -1
- package/dist/types/global-account/react/components/{B3Provider.d.ts → B3Provider/B3Provider.d.ts} +2 -28
- package/dist/types/global-account/react/components/{B3Provider.native.d.ts → B3Provider/B3Provider.native.d.ts} +1 -24
- package/dist/types/global-account/react/components/B3Provider/types.d.ts +25 -0
- package/dist/types/global-account/react/components/B3Provider/useB3.d.ts +5 -0
- package/dist/types/global-account/react/components/index.d.ts +8 -6
- package/dist/types/global-account/react/index.native.d.ts +5 -4
- package/dist/types/global-account/react/stores/useModalStore.d.ts +2 -0
- package/dist/types/global-account/types/chain-networks.d.ts +34 -34
- package/dist/types/global-account/types/feature-flags.d.ts +5 -5
- package/dist/types/shared/constants/chains/b3Chain.d.ts +1 -1
- package/dist/types/shared/constants/chains/supported.d.ts +4 -3
- package/package.json +4 -3
- package/src/anyspend/react/components/AnySpend.tsx +6 -5
- package/src/anyspend/react/components/AnySpendBuySpin.tsx +233 -184
- package/src/global-account/react/components/B3DynamicModal.tsx +1 -1
- package/src/global-account/react/components/{B3Provider.native.tsx → B3Provider/B3Provider.native.tsx} +4 -45
- package/src/global-account/react/components/{B3Provider.tsx → B3Provider/B3Provider.tsx} +4 -53
- package/src/global-account/react/components/B3Provider/types.ts +40 -0
- package/src/global-account/react/components/B3Provider/useB3.ts +17 -0
- package/src/global-account/react/components/StyleRoot.tsx +1 -1
- package/src/global-account/react/components/index.ts +8 -6
- package/src/global-account/react/index.native.ts +5 -4
- package/src/global-account/react/stores/useModalStore.ts +2 -0
- package/src/shared/constants/chains/supported.ts +2 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { B3_TOKEN, OrderType } from "@b3dotfun/sdk/anyspend";
|
|
2
|
+
import { baseMainnet } from "@b3dotfun/sdk/shared/constants/chains/supported";
|
|
2
3
|
import { EthIcon } from "./icons/EthIcon";
|
|
3
4
|
import { SolIcon } from "./icons/SolIcon";
|
|
4
5
|
import { UsdcIcon } from "./icons/USDCIcon";
|
|
@@ -19,7 +20,6 @@ import { ArrowRight, Loader2 } from "lucide-react";
|
|
|
19
20
|
import { useCallback, useEffect, useState } from "react";
|
|
20
21
|
import { toast } from "sonner";
|
|
21
22
|
import { createPublicClient, encodeFunctionData, erc20Abi, formatUnits, http } from "viem";
|
|
22
|
-
import { base } from "viem/chains";
|
|
23
23
|
import { useAccount, useWaitForTransactionReceipt, useWriteContract } from "wagmi";
|
|
24
24
|
import { AnySpendCustom } from "./AnySpendCustom";
|
|
25
25
|
|
|
@@ -52,6 +52,20 @@ const SPIN_WHEEL_ABI = [
|
|
|
52
52
|
outputs: [],
|
|
53
53
|
stateMutability: "payable",
|
|
54
54
|
type: "function"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
inputs: [],
|
|
58
|
+
name: "getWheelInfo",
|
|
59
|
+
outputs: [
|
|
60
|
+
{ internalType: "address", name: "creator_", type: "address" },
|
|
61
|
+
{ internalType: "uint256", name: "startTime_", type: "uint256" },
|
|
62
|
+
{ internalType: "uint256", name: "endTime_", type: "uint256" },
|
|
63
|
+
{ internalType: "uint256", name: "totalPrizesAvailable_", type: "uint256" },
|
|
64
|
+
{ internalType: "uint256", name: "prizesRequestedCount_", type: "uint256" },
|
|
65
|
+
{ internalType: "enum SpinWheelV2.WheelState", name: "state_", type: "uint8" }
|
|
66
|
+
],
|
|
67
|
+
stateMutability: "view",
|
|
68
|
+
type: "function"
|
|
55
69
|
}
|
|
56
70
|
] as const;
|
|
57
71
|
|
|
@@ -62,6 +76,37 @@ interface PaymentConfig {
|
|
|
62
76
|
entryModule: string;
|
|
63
77
|
}
|
|
64
78
|
|
|
79
|
+
interface WheelInfo {
|
|
80
|
+
creator_: string;
|
|
81
|
+
startTime_: bigint;
|
|
82
|
+
endTime_: bigint;
|
|
83
|
+
totalPrizesAvailable_: bigint;
|
|
84
|
+
prizesRequestedCount_: bigint;
|
|
85
|
+
state_: number;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
type WheelStatus = "not_started" | "active" | "ended" | "sold_out";
|
|
89
|
+
|
|
90
|
+
function getWheelStatus(wheelInfo: WheelInfo): WheelStatus {
|
|
91
|
+
const now = BigInt(Math.floor(Date.now() / 1000));
|
|
92
|
+
console.log("@@anyspend-buy-spin:now:", now);
|
|
93
|
+
console.log("@@anyspend-buy-spin:wheelInfo:", wheelInfo);
|
|
94
|
+
|
|
95
|
+
if (now < wheelInfo.startTime_) {
|
|
96
|
+
return "not_started";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (now > wheelInfo.endTime_) {
|
|
100
|
+
return "ended";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (wheelInfo.totalPrizesAvailable_ <= wheelInfo.prizesRequestedCount_) {
|
|
104
|
+
return "sold_out";
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return "active";
|
|
108
|
+
}
|
|
109
|
+
|
|
65
110
|
function generateEncodedDataForBuyEntriesAndSpin(user: string, quantity: string): string {
|
|
66
111
|
invariant(BigInt(quantity) > 0, "Quantity must be greater than zero");
|
|
67
112
|
console.log("@@anyspend-buy-spin:encoded-data:", { user, quantity });
|
|
@@ -74,7 +119,7 @@ function generateEncodedDataForBuyEntriesAndSpin(user: string, quantity: string)
|
|
|
74
119
|
}
|
|
75
120
|
|
|
76
121
|
const basePublicClient = createPublicClient({
|
|
77
|
-
chain:
|
|
122
|
+
chain: baseMainnet,
|
|
78
123
|
transport: http()
|
|
79
124
|
});
|
|
80
125
|
|
|
@@ -85,6 +130,7 @@ export function AnySpendBuySpin({
|
|
|
85
130
|
spinwheelContractAddress,
|
|
86
131
|
chainId,
|
|
87
132
|
recipientAddress,
|
|
133
|
+
prefillQuantity,
|
|
88
134
|
onSuccess
|
|
89
135
|
}: {
|
|
90
136
|
isMainnet?: boolean;
|
|
@@ -93,6 +139,7 @@ export function AnySpendBuySpin({
|
|
|
93
139
|
spinwheelContractAddress: string;
|
|
94
140
|
chainId: number;
|
|
95
141
|
recipientAddress: string;
|
|
142
|
+
prefillQuantity?: string;
|
|
96
143
|
onSuccess?: (txHash?: string) => void;
|
|
97
144
|
}) {
|
|
98
145
|
const hasMounted = useHasMounted();
|
|
@@ -102,6 +149,7 @@ export function AnySpendBuySpin({
|
|
|
102
149
|
const [paymentConfig, setPaymentConfig] = useState<PaymentConfig | null>(null);
|
|
103
150
|
const [isLoadingConfig, setIsLoadingConfig] = useState(true);
|
|
104
151
|
const [configError, setConfigError] = useState<string>("");
|
|
152
|
+
const [wheelInfo, setWheelInfo] = useState<WheelInfo | null>(null);
|
|
105
153
|
|
|
106
154
|
// Fetch B3 token balance
|
|
107
155
|
const {
|
|
@@ -120,24 +168,34 @@ export function AnySpendBuySpin({
|
|
|
120
168
|
// State for direct buying flow (when user has B3 tokens)
|
|
121
169
|
const [isBuying, setIsBuying] = useState(false);
|
|
122
170
|
const [buyingTxHash, setBuyingTxHash] = useState<string>("");
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
171
|
+
const {
|
|
172
|
+
isLoading: isTxPending,
|
|
173
|
+
isSuccess: isTxSuccess,
|
|
174
|
+
isError: isTxError,
|
|
175
|
+
error: txError
|
|
176
|
+
} = useWaitForTransactionReceipt({
|
|
127
177
|
hash: buyingTxHash as `0x${string}`,
|
|
128
178
|
query: {
|
|
129
179
|
structuralSharing: false
|
|
130
180
|
}
|
|
131
181
|
});
|
|
132
182
|
|
|
133
|
-
//
|
|
183
|
+
// Handle transaction status
|
|
134
184
|
useEffect(() => {
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
185
|
+
if (!buyingTxHash) return;
|
|
186
|
+
|
|
187
|
+
if (isTxSuccess) {
|
|
188
|
+
setB3ModalOpen(false);
|
|
189
|
+
onSuccess?.(buyingTxHash);
|
|
190
|
+
toast.success("Spin purchase transaction confirmed!");
|
|
191
|
+
setIsBuying(false);
|
|
192
|
+
} else if (isTxError) {
|
|
193
|
+
console.error("@@anyspend-buy-spin:tx-error:", txError);
|
|
194
|
+
toast.error("Transaction failed. Please try again.");
|
|
195
|
+
setB3ModalOpen(false);
|
|
138
196
|
setIsBuying(false);
|
|
139
197
|
}
|
|
140
|
-
}, [isTxSuccess, buyingTxHash]);
|
|
198
|
+
}, [isTxSuccess, isTxError, buyingTxHash, onSuccess, setB3ModalOpen, txError]);
|
|
141
199
|
|
|
142
200
|
// Spin quantity state
|
|
143
201
|
const [userSpinQuantity, setUserSpinQuantity] = useState<string>("");
|
|
@@ -146,12 +204,21 @@ export function AnySpendBuySpin({
|
|
|
146
204
|
const [validationError, setValidationError] = useState<string>("");
|
|
147
205
|
const [displayQuantity, setDisplayQuantity] = useState<string>("");
|
|
148
206
|
const [debouncedQuantity, setDebouncedQuantity] = useState<string>("");
|
|
207
|
+
const [debouncedUserSpinQuantity, setDebouncedUserSpinQuantity] = useState<string>("");
|
|
208
|
+
|
|
209
|
+
useEffect(() => {
|
|
210
|
+
if (prefillQuantity && wheelInfo) {
|
|
211
|
+
const remainingSpins = wheelInfo.totalPrizesAvailable_ - wheelInfo.prizesRequestedCount_;
|
|
212
|
+
const adjustedQuantity = BigInt(prefillQuantity) > remainingSpins ? remainingSpins.toString() : prefillQuantity;
|
|
213
|
+
validateAndSetQuantity(adjustedQuantity);
|
|
214
|
+
}
|
|
215
|
+
}, [prefillQuantity, wheelInfo]);
|
|
149
216
|
|
|
150
217
|
// Calculate total cost
|
|
151
218
|
const totalCost =
|
|
152
219
|
paymentConfig && userSpinQuantity ? paymentConfig.pricePerEntry * BigInt(userSpinQuantity) : BigInt(0);
|
|
153
220
|
|
|
154
|
-
// Fetch payment configuration
|
|
221
|
+
// Fetch payment configuration and wheel info
|
|
155
222
|
const fetchPaymentConfig = useCallback(async () => {
|
|
156
223
|
if (!basePublicClient || !spinwheelContractAddress) return;
|
|
157
224
|
|
|
@@ -161,7 +228,7 @@ export function AnySpendBuySpin({
|
|
|
161
228
|
|
|
162
229
|
console.log("@@anyspend-buy-spin:fetch-config:", { spinwheelContractAddress, chainId });
|
|
163
230
|
|
|
164
|
-
const [config, entryModuleAddress] = await Promise.all([
|
|
231
|
+
const [config, entryModuleAddress, wheelInfo] = await Promise.all([
|
|
165
232
|
basePublicClient.readContract({
|
|
166
233
|
address: spinwheelContractAddress as `0x${string}`,
|
|
167
234
|
abi: SPIN_WHEEL_ABI,
|
|
@@ -171,6 +238,11 @@ export function AnySpendBuySpin({
|
|
|
171
238
|
address: spinwheelContractAddress as `0x${string}`,
|
|
172
239
|
abi: SPIN_WHEEL_ABI,
|
|
173
240
|
functionName: "entryModule"
|
|
241
|
+
}),
|
|
242
|
+
basePublicClient.readContract({
|
|
243
|
+
address: spinwheelContractAddress as `0x${string}`,
|
|
244
|
+
abi: SPIN_WHEEL_ABI,
|
|
245
|
+
functionName: "getWheelInfo"
|
|
174
246
|
})
|
|
175
247
|
]);
|
|
176
248
|
|
|
@@ -181,13 +253,17 @@ export function AnySpendBuySpin({
|
|
|
181
253
|
entryModule: entryModuleAddress
|
|
182
254
|
};
|
|
183
255
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
256
|
+
const wheelInfoData: WheelInfo = {
|
|
257
|
+
creator_: wheelInfo[0],
|
|
258
|
+
startTime_: wheelInfo[1],
|
|
259
|
+
endTime_: wheelInfo[2],
|
|
260
|
+
totalPrizesAvailable_: wheelInfo[3],
|
|
261
|
+
prizesRequestedCount_: wheelInfo[4],
|
|
262
|
+
state_: wheelInfo[5]
|
|
263
|
+
};
|
|
264
|
+
|
|
190
265
|
setPaymentConfig(paymentConfig);
|
|
266
|
+
setWheelInfo(wheelInfoData);
|
|
191
267
|
} catch (error) {
|
|
192
268
|
console.error("@@anyspend-buy-spin:config-error:", error);
|
|
193
269
|
setConfigError("Failed to load spin wheel configuration");
|
|
@@ -206,6 +282,7 @@ export function AnySpendBuySpin({
|
|
|
206
282
|
useEffect(() => {
|
|
207
283
|
const timer = setTimeout(() => {
|
|
208
284
|
setDebouncedQuantity(displayQuantity);
|
|
285
|
+
setDebouncedUserSpinQuantity(userSpinQuantity);
|
|
209
286
|
}, 500);
|
|
210
287
|
|
|
211
288
|
return () => clearTimeout(timer);
|
|
@@ -238,17 +315,23 @@ export function AnySpendBuySpin({
|
|
|
238
315
|
}
|
|
239
316
|
|
|
240
317
|
// Check maximum entries per user (0 means no limit)
|
|
241
|
-
if (
|
|
242
|
-
paymentConfig &&
|
|
243
|
-
paymentConfig.maxEntriesPerUser > BigInt(0) &&
|
|
244
|
-
BigInt(numValue) > paymentConfig.maxEntriesPerUser
|
|
245
|
-
) {
|
|
318
|
+
if (paymentConfig && paymentConfig.maxEntriesPerUser > 0n && BigInt(numValue) > paymentConfig.maxEntriesPerUser) {
|
|
246
319
|
setIsQuantityValid(false);
|
|
247
320
|
setUserSpinQuantity("");
|
|
248
321
|
setValidationError(`Maximum ${paymentConfig.maxEntriesPerUser.toString()} spins allowed`);
|
|
249
322
|
return;
|
|
250
323
|
}
|
|
251
324
|
|
|
325
|
+
// Check if quantity exceeds remaining entries
|
|
326
|
+
if (wheelInfo && BigInt(numValue) > wheelInfo.totalPrizesAvailable_ - wheelInfo.prizesRequestedCount_) {
|
|
327
|
+
setIsQuantityValid(false);
|
|
328
|
+
setUserSpinQuantity("");
|
|
329
|
+
setValidationError(
|
|
330
|
+
`Only ${(wheelInfo.totalPrizesAvailable_ - wheelInfo.prizesRequestedCount_).toString()} spins remaining`
|
|
331
|
+
);
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
252
335
|
setUserSpinQuantity(value);
|
|
253
336
|
setIsQuantityValid(true);
|
|
254
337
|
setValidationError("");
|
|
@@ -303,7 +386,7 @@ export function AnySpendBuySpin({
|
|
|
303
386
|
} catch (error) {
|
|
304
387
|
console.error("@@anyspend-buy-spin:error:", error);
|
|
305
388
|
toast.error("Spin purchase failed. Please try again.");
|
|
306
|
-
|
|
389
|
+
setB3ModalOpen(false);
|
|
307
390
|
} finally {
|
|
308
391
|
setIsBuying(false);
|
|
309
392
|
}
|
|
@@ -382,6 +465,40 @@ export function AnySpendBuySpin({
|
|
|
382
465
|
// Render quantity input prompt
|
|
383
466
|
if (showAmountPrompt) {
|
|
384
467
|
const pricePerEntry = formatUnits(paymentConfig.pricePerEntry, 18);
|
|
468
|
+
const remainingEntries = wheelInfo ? wheelInfo.totalPrizesAvailable_ - wheelInfo.prizesRequestedCount_ : 0n;
|
|
469
|
+
const wheelStatus = wheelInfo ? getWheelStatus(wheelInfo) : null;
|
|
470
|
+
const isSoldOut = wheelStatus === "sold_out";
|
|
471
|
+
const isActive = wheelStatus === "active";
|
|
472
|
+
|
|
473
|
+
const getStatusMessage = () => {
|
|
474
|
+
if (!wheelInfo) return null;
|
|
475
|
+
|
|
476
|
+
const formatDate = (timestamp: bigint) => {
|
|
477
|
+
return new Date(Number(timestamp) * 1000).toLocaleString();
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
switch (wheelStatus) {
|
|
481
|
+
case "not_started":
|
|
482
|
+
return {
|
|
483
|
+
title: "Spin Wheel Not Started",
|
|
484
|
+
message: `Starts at ${formatDate(wheelInfo.startTime_)}`
|
|
485
|
+
};
|
|
486
|
+
case "ended":
|
|
487
|
+
return {
|
|
488
|
+
title: "Spin Wheel Ended",
|
|
489
|
+
message: `Ended at ${formatDate(wheelInfo.endTime_)}`
|
|
490
|
+
};
|
|
491
|
+
case "sold_out":
|
|
492
|
+
return {
|
|
493
|
+
title: "All Spins Have Been Claimed",
|
|
494
|
+
message: "Stay tuned for the next spin wheel event!"
|
|
495
|
+
};
|
|
496
|
+
default:
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
const statusInfo = getStatusMessage();
|
|
385
502
|
|
|
386
503
|
return (
|
|
387
504
|
<StyleRoot>
|
|
@@ -395,7 +512,7 @@ export function AnySpendBuySpin({
|
|
|
395
512
|
filter: hasMounted ? "blur(0px)" : "blur(10px)"
|
|
396
513
|
}}
|
|
397
514
|
transition={{ duration: 0.3, delay: 0, ease: "easeInOut" }}
|
|
398
|
-
className="mb-4
|
|
515
|
+
className={`flex justify-center ${isActive ? "mb-4" : ""}`}
|
|
399
516
|
>
|
|
400
517
|
<img
|
|
401
518
|
alt="B3 Token"
|
|
@@ -417,15 +534,33 @@ export function AnySpendBuySpin({
|
|
|
417
534
|
transition={{ duration: 0.3, delay: 0.1, ease: "easeInOut" }}
|
|
418
535
|
className="text-center"
|
|
419
536
|
>
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
537
|
+
{isActive ? (
|
|
538
|
+
<>
|
|
539
|
+
<h2 className="font-sf-rounded text-as-primary mb-4 text-2xl font-bold">
|
|
540
|
+
{(() => {
|
|
541
|
+
const hasEnoughBalance = b3RawBalance && totalCost <= b3RawBalance;
|
|
542
|
+
return hasEnoughBalance || !debouncedQuantity ? "Buy Spins" : `Swap & Buy Spins`;
|
|
543
|
+
})()}
|
|
544
|
+
</h2>
|
|
545
|
+
{wheelInfo && (
|
|
546
|
+
<div className="inline-flex items-center gap-2">
|
|
547
|
+
<div className="bg-as-brand/10 border-as-brand/10 inline-flex items-center rounded-full border px-3 py-1">
|
|
548
|
+
<p className="text-as-brand text-sm font-medium">{pricePerEntry} $B3 per spin</p>
|
|
549
|
+
</div>
|
|
550
|
+
<div className="bg-as-brand/10 border-as-brand/10 inline-flex items-center rounded-full border px-3 py-1">
|
|
551
|
+
<p className="text-as-brand text-sm font-medium">{remainingEntries.toString()} remaining</p>
|
|
552
|
+
</div>
|
|
553
|
+
</div>
|
|
554
|
+
)}
|
|
555
|
+
</>
|
|
556
|
+
) : (
|
|
557
|
+
statusInfo && (
|
|
558
|
+
<div className="text-center">
|
|
559
|
+
<p className="text-as-primary text-lg font-semibold">{statusInfo.title}</p>
|
|
560
|
+
<p className="text-as-primary/70 mt-2 text-sm">{statusInfo.message}</p>
|
|
561
|
+
</div>
|
|
562
|
+
)
|
|
563
|
+
)}
|
|
429
564
|
</motion.div>
|
|
430
565
|
</div>
|
|
431
566
|
|
|
@@ -439,163 +574,77 @@ export function AnySpendBuySpin({
|
|
|
439
574
|
transition={{ duration: 0.3, delay: 0.2, ease: "easeInOut" }}
|
|
440
575
|
className="bg-b3-react-background w-full p-6"
|
|
441
576
|
>
|
|
442
|
-
|
|
443
|
-
<div className="
|
|
444
|
-
<
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
577
|
+
{isActive ? (
|
|
578
|
+
<div className="space-y-4">
|
|
579
|
+
<div className="flex items-center justify-between">
|
|
580
|
+
<p className="text-as-primary/70 text-sm font-medium">Number of spins</p>
|
|
581
|
+
<span className="text-as-primary/50 flex items-center gap-1 text-sm">
|
|
582
|
+
Available: {isBalanceLoading ? <Loader2 className="h-3 w-3 animate-spin" /> : `${b3Balance} B3`}
|
|
583
|
+
</span>
|
|
584
|
+
</div>
|
|
449
585
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
586
|
+
<div className="relative">
|
|
587
|
+
<Input
|
|
588
|
+
onFocus={onFocusQuantityInput}
|
|
589
|
+
type="text"
|
|
590
|
+
placeholder="1"
|
|
591
|
+
value={displayQuantity}
|
|
592
|
+
onChange={e => validateAndSetQuantity(e.target.value)}
|
|
593
|
+
className={`h-14 px-4 pr-20 text-lg ${!isQuantityValid && displayQuantity ? "border-as-red" : "border-b3-react-border"}`}
|
|
594
|
+
/>
|
|
595
|
+
<div className="font-pack absolute right-4 top-1/2 -translate-y-1/2 text-lg font-medium text-blue-500/70">
|
|
596
|
+
{displayQuantity === "1" ? "Spin" : "Spins"}
|
|
597
|
+
</div>
|
|
461
598
|
</div>
|
|
462
|
-
</div>
|
|
463
599
|
|
|
464
|
-
|
|
600
|
+
{!isQuantityValid && displayQuantity && <p className="text-as-red text-sm">{validationError}</p>}
|
|
465
601
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
602
|
+
<div className="bg-as-on-surface-2/30 rounded-lg border border-white/10 p-4 backdrop-blur-sm">
|
|
603
|
+
<div className="flex items-center justify-between">
|
|
604
|
+
<span className="text-as-primary/70 text-sm font-medium">Total Cost:</span>
|
|
605
|
+
<div className="flex items-center gap-2">
|
|
606
|
+
<span className="text-as-primary text-lg font-bold">
|
|
607
|
+
{displayQuantity && isQuantityValid ? formatUnits(totalCost, 18) : "0"} B3
|
|
608
|
+
</span>
|
|
609
|
+
</div>
|
|
473
610
|
</div>
|
|
474
611
|
</div>
|
|
475
|
-
</div>
|
|
476
|
-
</div>
|
|
477
|
-
|
|
478
|
-
<div className="mt-4">
|
|
479
|
-
{(() => {
|
|
480
|
-
const hasEnoughBalance = b3RawBalance && totalCost <= b3RawBalance;
|
|
481
|
-
|
|
482
|
-
if (!hasEnoughBalance && debouncedQuantity) {
|
|
483
|
-
return (
|
|
484
|
-
<div className="bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5">
|
|
485
|
-
<div className="flex items-center justify-center gap-2">
|
|
486
|
-
<span className="text-as-primary text-sm font-semibold">Swap & buy from any token</span>
|
|
487
|
-
<TextLoop>
|
|
488
|
-
<EthIcon className="h-8 w-8" />
|
|
489
|
-
<SolIcon className="h-8 w-8" />
|
|
490
|
-
<UsdcIcon className="h-8 w-8" />
|
|
491
|
-
</TextLoop>
|
|
492
|
-
<ArrowRight className="text-as-primary h-4 w-4" />
|
|
493
|
-
<img src="https://cdn.b3.fun/b3-coin-3d.png" className="h-7 w-7" alt="B3 Token" />
|
|
494
|
-
</div>
|
|
495
|
-
<p className="text-as-primary/50 text-sm font-medium">
|
|
496
|
-
No problem, we'll help you swap to B3 for your spins!
|
|
497
|
-
</p>
|
|
498
|
-
</div>
|
|
499
|
-
);
|
|
500
|
-
}
|
|
501
|
-
})()}
|
|
502
|
-
</div>
|
|
503
|
-
|
|
504
|
-
<Button
|
|
505
|
-
onClick={confirmQuantity}
|
|
506
|
-
disabled={!isQuantityValid || !displayQuantity || isBuying || isTxPending}
|
|
507
|
-
className="bg-as-brand hover:bg-as-brand/90 text-as-primary mt-4 h-14 w-full rounded-xl text-lg font-medium"
|
|
508
|
-
>
|
|
509
|
-
{isBuying ? "Buying..." : isTxPending ? "Confirming..." : "Continue"}
|
|
510
|
-
</Button>
|
|
511
|
-
</motion.div>
|
|
512
|
-
</div>
|
|
513
|
-
</StyleRoot>
|
|
514
|
-
);
|
|
515
|
-
}
|
|
516
612
|
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
className="size-full shrink-0 bg-transparent text-transparent"
|
|
543
|
-
src="https://cdn.b3.fun/b3-coin-3d.png"
|
|
544
|
-
/>
|
|
545
|
-
<div className="absolute inset-0 rounded-[50%] border border-white/20"></div>
|
|
546
|
-
</GlareCardRounded>
|
|
547
|
-
</motion.div>
|
|
548
|
-
<motion.div
|
|
549
|
-
initial={false}
|
|
550
|
-
animate={{
|
|
551
|
-
opacity: hasMounted ? 1 : 0,
|
|
552
|
-
y: hasMounted ? 0 : 20,
|
|
553
|
-
filter: hasMounted ? "blur(0px)" : "blur(10px)"
|
|
554
|
-
}}
|
|
555
|
-
transition={{ duration: 0.3, delay: 0.1, ease: "easeInOut" }}
|
|
556
|
-
className="text-center"
|
|
557
|
-
>
|
|
558
|
-
<h2 className="font-sf-rounded mb-3 bg-gradient-to-r from-green-400 to-blue-500 bg-clip-text text-3xl font-bold text-transparent">
|
|
559
|
-
🎉 Purchase Complete!
|
|
560
|
-
</h2>
|
|
561
|
-
<div className="bg-as-on-surface-2/50 inline-flex items-center gap-2 rounded-full border border-white/10 px-4 py-2 backdrop-blur-sm">
|
|
562
|
-
<span className="text-as-primary/80 text-sm font-medium">
|
|
563
|
-
{userSpinQuantity} Spin{userSpinQuantity !== "1" ? "s" : ""} • {formatUnits(totalCost, 18)} B3
|
|
564
|
-
</span>
|
|
565
|
-
</div>
|
|
566
|
-
</motion.div>
|
|
567
|
-
</div>
|
|
613
|
+
<div className="mt-4">
|
|
614
|
+
{(() => {
|
|
615
|
+
const hasEnoughBalance = b3RawBalance && totalCost <= b3RawBalance;
|
|
616
|
+
|
|
617
|
+
if (!hasEnoughBalance && debouncedQuantity) {
|
|
618
|
+
return (
|
|
619
|
+
<div className="bg-as-brand/10 flex flex-col items-center gap-2 rounded-lg p-4 pb-5">
|
|
620
|
+
<div className="flex items-center justify-center gap-2">
|
|
621
|
+
<span className="text-as-primary text-sm font-semibold">Swap & buy from any token</span>
|
|
622
|
+
<TextLoop>
|
|
623
|
+
<EthIcon className="h-8 w-8" />
|
|
624
|
+
<SolIcon className="h-8 w-8" />
|
|
625
|
+
<UsdcIcon className="h-8 w-8" />
|
|
626
|
+
</TextLoop>
|
|
627
|
+
<ArrowRight className="text-as-primary h-4 w-4" />
|
|
628
|
+
<img src="https://cdn.b3.fun/b3-coin-3d.png" className="h-7 w-7" alt="B3 Token" />
|
|
629
|
+
</div>
|
|
630
|
+
<p className="text-as-primary/50 text-sm font-medium">
|
|
631
|
+
No problem, we'll help you swap to B3 for your spins!
|
|
632
|
+
</p>
|
|
633
|
+
</div>
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
})()}
|
|
637
|
+
</div>
|
|
568
638
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
>
|
|
579
|
-
<div className="mb-6">
|
|
580
|
-
<a
|
|
581
|
-
href={`https://basescan.org/tx/${buyingTxHash}`}
|
|
582
|
-
target="_blank"
|
|
583
|
-
rel="noopener noreferrer"
|
|
584
|
-
className="text-as-primary/70 hover:text-as-primary block break-all text-center font-mono text-sm underline transition-colors"
|
|
585
|
-
>
|
|
586
|
-
View transaction
|
|
587
|
-
</a>
|
|
588
|
-
</div>
|
|
589
|
-
|
|
590
|
-
<Button
|
|
591
|
-
onClick={() => {
|
|
592
|
-
setB3ModalOpen(false);
|
|
593
|
-
onSuccess?.(buyingTxHash);
|
|
594
|
-
}}
|
|
595
|
-
className="bg-as-brand hover:bg-as-brand/90 text-as-primary h-14 w-full rounded-xl text-lg font-medium"
|
|
596
|
-
>
|
|
597
|
-
Done
|
|
598
|
-
</Button>
|
|
639
|
+
<Button
|
|
640
|
+
onClick={confirmQuantity}
|
|
641
|
+
disabled={!isQuantityValid || !displayQuantity || isBuying || isTxPending}
|
|
642
|
+
className="bg-as-brand hover:bg-as-brand/90 text-as-primary mt-4 h-14 w-full rounded-xl text-lg font-medium"
|
|
643
|
+
>
|
|
644
|
+
{isBuying ? "Buying..." : isTxPending ? "Confirming..." : "Continue"}
|
|
645
|
+
</Button>
|
|
646
|
+
</div>
|
|
647
|
+
) : null}
|
|
599
648
|
</motion.div>
|
|
600
649
|
</div>
|
|
601
650
|
</StyleRoot>
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "@b3dotfun/sdk/anyspend/react";
|
|
9
9
|
import { useIsMobile, useModalStore } from "@b3dotfun/sdk/global-account/react";
|
|
10
10
|
import { debugB3React } from "@b3dotfun/sdk/shared/utils/debug";
|
|
11
|
-
import { useB3 } from "./B3Provider";
|
|
11
|
+
import { useB3 } from "./B3Provider/useB3";
|
|
12
12
|
import { ManageAccount } from "./ManageAccount/ManageAccount";
|
|
13
13
|
import { RequestPermissions } from "./RequestPermissions/RequestPermissions";
|
|
14
14
|
import { SignInWithB3Flow } from "./SignInWithB3/SignInWithB3Flow";
|
|
@@ -6,6 +6,7 @@ import { Account } from "thirdweb/wallets";
|
|
|
6
6
|
// import { RelayKitProviderWrapper } from "./RelayKitProviderWrapper";
|
|
7
7
|
|
|
8
8
|
import { User } from "@b3dotfun/sdk/global-account/types/b3-api.types";
|
|
9
|
+
import { B3Context, B3ContextType } from "./types";
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Default permissions configuration for B3 provider
|
|
@@ -17,51 +18,6 @@ const DEFAULT_PERMISSIONS = {
|
|
|
17
18
|
endDate: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365) // 1 year from now
|
|
18
19
|
};
|
|
19
20
|
|
|
20
|
-
/**
|
|
21
|
-
* Context type for B3Provider
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
export interface B3ContextType {
|
|
25
|
-
account?: Account;
|
|
26
|
-
user?: User;
|
|
27
|
-
setAccount: (account: Account) => void;
|
|
28
|
-
setUser: (user?: User) => void;
|
|
29
|
-
initialized: boolean;
|
|
30
|
-
ready: boolean;
|
|
31
|
-
environment?: "development" | "production";
|
|
32
|
-
defaultPermissions?: PermissionsConfig;
|
|
33
|
-
theme: "light" | "dark";
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Context for B3 provider
|
|
38
|
-
*/
|
|
39
|
-
export const B3Context = createContext<B3ContextType>({
|
|
40
|
-
account: undefined,
|
|
41
|
-
user: undefined,
|
|
42
|
-
setAccount: () => {},
|
|
43
|
-
setUser: () => {},
|
|
44
|
-
initialized: false,
|
|
45
|
-
ready: false,
|
|
46
|
-
environment: "development",
|
|
47
|
-
theme: "light"
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Hook to access the B3 context
|
|
52
|
-
* @throws Error if used outside a B3Provider
|
|
53
|
-
*/
|
|
54
|
-
export function useB3() {
|
|
55
|
-
const context = useContext(B3Context);
|
|
56
|
-
|
|
57
|
-
if (!context.initialized) {
|
|
58
|
-
throw new Error("useB3 must be used within a B3Provider");
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Return a stable reference
|
|
62
|
-
return useMemo(() => context, [context]);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
21
|
// Create queryClient instance
|
|
66
22
|
const queryClient = new QueryClient();
|
|
67
23
|
|
|
@@ -125,6 +81,9 @@ export function InnerProvider({
|
|
|
125
81
|
<B3Context.Provider
|
|
126
82
|
value={{
|
|
127
83
|
account: effectiveAccount,
|
|
84
|
+
automaticallySetFirstEoa: false,
|
|
85
|
+
setWallet: () => {},
|
|
86
|
+
wallet: undefined,
|
|
128
87
|
setAccount,
|
|
129
88
|
user,
|
|
130
89
|
setUser,
|