create-stylus 0.1.5 → 0.1.7
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/cli.js +7 -8
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/src/main.ts +2 -4
- package/src/tasks/copy-template-files.ts +7 -4
- package/src/utils/prompt-for-missing-options.ts +1 -1
- package/templates/base/package.json +1 -1
- package/templates/base/packages/nextjs/app/blockexplorer/_components/TransactionsTable.tsx +11 -9
- package/templates/base/packages/nextjs/app/debug/_components/contract/ContractUI.tsx +2 -2
- package/templates/base/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx +8 -4
- package/templates/base/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx +1 -9
- package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/AddressInfoDropdown.tsx +138 -24
- package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/RevealBurnerPKModal.tsx +59 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/index.tsx +3 -2
- package/templates/base/packages/nextjs/eslint.config.mjs +6 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldEventHistory.ts +107 -28
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldWriteContract.ts +5 -1
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useTransactor.tsx +7 -5
- package/templates/base/packages/nextjs/icons/LightBugAntIcon.tsx +7 -7
- package/templates/base/packages/nextjs/next-env.d.ts +1 -0
- package/templates/base/packages/nextjs/package.json +4 -5
- package/templates/base/packages/nextjs/services/web3/wagmiConnectors.tsx +1 -0
- package/templates/base/packages/nextjs/styles/globals.css +28 -22
- package/templates/base/packages/nextjs/tailwind.config.js +1 -1
- package/templates/base/packages/nextjs/utils/scaffold-eth/contract.ts +74 -2
- package/templates/base/packages/stylus/scripts/deploy.ts +0 -8
- package/templates/base/packages/stylus/your-contract/Cargo.lock +4 -4
- package/templates/base/packages/stylus/your-contract/Cargo.toml +1 -1
- package/templates/base/packages/stylus/your-contract/src/lib.rs +3 -7
- package/templates/base/readme.md +56 -174
- package/templates/base/yarn.lock +239 -297
- package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/AngularWalletAddress.tsx +0 -223
- package/templates/base/packages/stylus/counter/.cargo/config.toml +0 -18
- package/templates/base/packages/stylus/counter/Cargo.lock +0 -5788
- package/templates/base/packages/stylus/counter/Cargo.toml +0 -46
- package/templates/base/packages/stylus/counter/rust-toolchain.toml +0 -2
- package/templates/base/packages/stylus/counter/src/lib.rs +0 -121
- package/templates/base/packages/stylus/counter/src/main.rs +0 -10
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
import { rainbowkitBurnerWallet } from "burner-connector";
|
|
3
|
+
import { ShieldExclamationIcon } from "@heroicons/react/24/outline";
|
|
4
|
+
import { useCopyToClipboard } from "~~/hooks/scaffold-eth";
|
|
5
|
+
import { getParsedError, notification } from "~~/utils/scaffold-eth";
|
|
6
|
+
|
|
7
|
+
const BURNER_WALLET_PK_KEY = "burnerWallet.pk";
|
|
8
|
+
|
|
9
|
+
export const RevealBurnerPKModal = () => {
|
|
10
|
+
const { copyToClipboard, isCopiedToClipboard } = useCopyToClipboard();
|
|
11
|
+
const modalCheckboxRef = useRef<HTMLInputElement>(null);
|
|
12
|
+
|
|
13
|
+
const handleCopyPK = async () => {
|
|
14
|
+
try {
|
|
15
|
+
const storage = rainbowkitBurnerWallet.useSessionStorage ? sessionStorage : localStorage;
|
|
16
|
+
const burnerPK = storage?.getItem(BURNER_WALLET_PK_KEY);
|
|
17
|
+
if (!burnerPK) throw new Error("Burner wallet private key not found");
|
|
18
|
+
await copyToClipboard(burnerPK);
|
|
19
|
+
notification.success("Burner wallet private key copied to clipboard");
|
|
20
|
+
} catch (e) {
|
|
21
|
+
const parsedError = getParsedError(e);
|
|
22
|
+
notification.error(parsedError);
|
|
23
|
+
if (modalCheckboxRef.current) modalCheckboxRef.current.checked = false;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<>
|
|
29
|
+
<div>
|
|
30
|
+
<input type="checkbox" id="reveal-burner-pk-modal" className="modal-toggle" ref={modalCheckboxRef} />
|
|
31
|
+
<label htmlFor="reveal-burner-pk-modal" className="modal cursor-pointer">
|
|
32
|
+
<label className="modal-box relative">
|
|
33
|
+
{/* dummy input to capture event onclick on modal box */}
|
|
34
|
+
<input className="h-0 w-0 absolute top-0 left-0" />
|
|
35
|
+
<label htmlFor="reveal-burner-pk-modal" className="btn btn-ghost btn-sm btn-circle absolute right-3 top-3">
|
|
36
|
+
✕
|
|
37
|
+
</label>
|
|
38
|
+
<div>
|
|
39
|
+
<p className="text-lg font-semibold m-0 p-0">Copy Burner Wallet Private Key</p>
|
|
40
|
+
<div role="alert" className="alert alert-warning mt-4">
|
|
41
|
+
<ShieldExclamationIcon className="h-6 w-6" />
|
|
42
|
+
<span className="font-semibold">
|
|
43
|
+
Burner wallets are intended for local development only and are not safe for storing real funds.
|
|
44
|
+
</span>
|
|
45
|
+
</div>
|
|
46
|
+
<p>
|
|
47
|
+
Your Private Key provides <strong>full access</strong> to your entire wallet and funds. This is
|
|
48
|
+
currently stored <strong>temporarily</strong> in your browser.
|
|
49
|
+
</p>
|
|
50
|
+
<button className="btn btn-outline btn-error" onClick={handleCopyPK} disabled={isCopiedToClipboard}>
|
|
51
|
+
Copy Private Key To Clipboard
|
|
52
|
+
</button>
|
|
53
|
+
</div>
|
|
54
|
+
</label>
|
|
55
|
+
</label>
|
|
56
|
+
</div>
|
|
57
|
+
</>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import { Balance } from "../Balance";
|
|
6
6
|
import { AddressInfoDropdown } from "./AddressInfoDropdown";
|
|
7
|
-
import { AngularWalletAddress } from "./AngularWalletAddress";
|
|
8
7
|
import { AddressQRCodeModal } from "./AddressQRCodeModal";
|
|
9
8
|
import { BurnerWalletModal } from "./BurnerWalletModal";
|
|
9
|
+
import { RevealBurnerPKModal } from "./RevealBurnerPKModal";
|
|
10
10
|
import { WrongNetworkDropdown } from "./WrongNetworkDropdown";
|
|
11
11
|
import { ConnectButton } from "@rainbow-me/rainbowkit";
|
|
12
12
|
import { Address } from "viem";
|
|
@@ -65,13 +65,14 @@ export const RainbowKitCustomConnectButton = () => {
|
|
|
65
65
|
{chain.name}
|
|
66
66
|
</span>
|
|
67
67
|
</div>
|
|
68
|
-
<
|
|
68
|
+
<AddressInfoDropdown
|
|
69
69
|
address={account.address as Address}
|
|
70
70
|
displayName={account.displayName}
|
|
71
71
|
ensAvatar={account.ensAvatar}
|
|
72
72
|
onSwitchAccount={() => setIsBurnerModalOpen(true)}
|
|
73
73
|
/>
|
|
74
74
|
<AddressQRCodeModal address={account.address as Address} modalId="qrcode-modal" />
|
|
75
|
+
<RevealBurnerPKModal />
|
|
75
76
|
</>
|
|
76
77
|
);
|
|
77
78
|
})()}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
|
-
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
2
|
+
import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
|
|
3
3
|
import { Abi, AbiEvent, ExtractAbiEventNames } from "abitype";
|
|
4
4
|
import { BlockNumber, GetLogsParameters } from "viem";
|
|
5
|
+
import { arbitrumNitro } from "~~/utils/scaffold-stylus/supportedChains";
|
|
5
6
|
import { Config, UsePublicClientReturnType, useBlockNumber, usePublicClient } from "wagmi";
|
|
6
7
|
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
|
|
7
8
|
import { useDeployedContractInfo } from "~~/hooks/scaffold-eth";
|
|
@@ -54,11 +55,15 @@ const getEvents = async (
|
|
|
54
55
|
};
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
|
-
*
|
|
58
|
+
* @deprecated **Recommended only for local (arbitrum nitro) chains and development.**
|
|
59
|
+
* It uses getLogs which can overload RPC endpoints (especially on L2s with short block times).
|
|
60
|
+
* For production, use an indexer such as ponder.sh or similar to query contract events efficiently.
|
|
61
|
+
*
|
|
62
|
+
* Reads events from a deployed contract.
|
|
58
63
|
* @param config - The config settings
|
|
59
64
|
* @param config.contractName - deployed contract name
|
|
60
65
|
* @param config.eventName - name of the event to listen for
|
|
61
|
-
* @param config.fromBlock -
|
|
66
|
+
* @param config.fromBlock - optional block number to start reading events from (defaults to `deployedOnBlock` in deployedContracts.ts if set for contract, otherwise defaults to 0)
|
|
62
67
|
* @param config.toBlock - optional block number to stop reading events at (if not provided, reads until current block)
|
|
63
68
|
* @param config.chainId - optional chainId that is configured with the scaffold project to make use for multi-chain interactions.
|
|
64
69
|
* @param config.filters - filters to be applied to the event (parameterName: value)
|
|
@@ -91,10 +96,21 @@ export const useScaffoldEventHistory = <
|
|
|
91
96
|
}: UseScaffoldEventHistoryConfig<TContractName, TEventName, TBlockData, TTransactionData, TReceiptData>) => {
|
|
92
97
|
const selectedNetwork = useSelectedNetwork(chainId);
|
|
93
98
|
|
|
99
|
+
// Runtime warning for non-local chains
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (selectedNetwork.id !== arbitrumNitro.id) {
|
|
102
|
+
console.log(
|
|
103
|
+
"⚠️ useScaffoldEventHistory is not optimized for production use. It can overload RPC endpoints (especially on L2s)",
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
}, [selectedNetwork.id]);
|
|
107
|
+
|
|
94
108
|
const publicClient = usePublicClient({
|
|
95
109
|
chainId: selectedNetwork.id,
|
|
96
110
|
});
|
|
97
|
-
const [
|
|
111
|
+
const [liveEvents, setLiveEvents] = useState<any[]>([]);
|
|
112
|
+
const [lastFetchedBlock, setLastFetchedBlock] = useState<bigint | null>(null);
|
|
113
|
+
const [isPollingActive, setIsPollingActive] = useState(false);
|
|
98
114
|
|
|
99
115
|
const { data: blockNumber } = useBlockNumber({ watch: watch, chainId: selectedNetwork.id });
|
|
100
116
|
|
|
@@ -109,6 +125,15 @@ export const useScaffoldEventHistory = <
|
|
|
109
125
|
|
|
110
126
|
const isContractAddressAndClientReady = Boolean(deployedContractData?.address) && Boolean(publicClient);
|
|
111
127
|
|
|
128
|
+
const fromBlockValue =
|
|
129
|
+
fromBlock !== undefined
|
|
130
|
+
? fromBlock
|
|
131
|
+
: BigInt(
|
|
132
|
+
deployedContractData && "deployedOnBlock" in deployedContractData
|
|
133
|
+
? (deployedContractData.deployedOnBlock as any) || 0
|
|
134
|
+
: 0,
|
|
135
|
+
);
|
|
136
|
+
|
|
112
137
|
const query = useInfiniteQuery({
|
|
113
138
|
queryKey: [
|
|
114
139
|
"eventHistory",
|
|
@@ -116,7 +141,7 @@ export const useScaffoldEventHistory = <
|
|
|
116
141
|
contractName,
|
|
117
142
|
address: deployedContractData?.address,
|
|
118
143
|
eventName,
|
|
119
|
-
fromBlock:
|
|
144
|
+
fromBlock: fromBlockValue?.toString(),
|
|
120
145
|
toBlock: toBlock?.toString(),
|
|
121
146
|
chainId: selectedNetwork.id,
|
|
122
147
|
filters: JSON.stringify(filters, replacer),
|
|
@@ -146,18 +171,16 @@ export const useScaffoldEventHistory = <
|
|
|
146
171
|
{ blockData, transactionData, receiptData },
|
|
147
172
|
);
|
|
148
173
|
|
|
174
|
+
setLastFetchedBlock(batchToBlock || blockNumber || 0n);
|
|
175
|
+
|
|
149
176
|
return data;
|
|
150
177
|
},
|
|
151
|
-
enabled: enabled && isContractAddressAndClientReady,
|
|
152
|
-
initialPageParam:
|
|
178
|
+
enabled: enabled && isContractAddressAndClientReady && !isPollingActive, // Disable when polling starts
|
|
179
|
+
initialPageParam: fromBlockValue,
|
|
153
180
|
getNextPageParam: (lastPage, allPages, lastPageParam) => {
|
|
154
|
-
if (!blockNumber ||
|
|
181
|
+
if (!blockNumber || fromBlockValue >= blockNumber) return undefined;
|
|
155
182
|
|
|
156
|
-
const
|
|
157
|
-
Number(lastPageParam),
|
|
158
|
-
...(lastPage || []).map(event => Number(event.blockNumber || 0)),
|
|
159
|
-
);
|
|
160
|
-
const nextBlock = BigInt(Math.max(Number(lastPageParam), lastPageHighestBlock) + 1);
|
|
183
|
+
const nextBlock = lastPageParam + BigInt(blocksBatchSize);
|
|
161
184
|
|
|
162
185
|
// Don't go beyond the specified toBlock or current block
|
|
163
186
|
const maxBlock = toBlock && toBlock < blockNumber ? toBlock : blockNumber;
|
|
@@ -182,28 +205,84 @@ export const useScaffoldEventHistory = <
|
|
|
182
205
|
},
|
|
183
206
|
});
|
|
184
207
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if (
|
|
188
|
-
// skipping on first render, since on first render we should call queryFn with
|
|
189
|
-
// fromBlock value, not blockNumber
|
|
190
|
-
if (isFirstRender) setIsFirstRender(false);
|
|
191
|
-
return;
|
|
192
|
-
}
|
|
208
|
+
// Check if we're caught up and should start polling
|
|
209
|
+
const shouldStartPolling = () => {
|
|
210
|
+
if (!watch || !blockNumber || isPollingActive) return false;
|
|
193
211
|
|
|
194
|
-
query.
|
|
195
|
-
|
|
196
|
-
|
|
212
|
+
return !query.hasNextPage && query.status === "success";
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
// Poll for new events when watch mode is enabled
|
|
216
|
+
useQuery({
|
|
217
|
+
queryKey: ["liveEvents", contractName, eventName, blockNumber?.toString(), lastFetchedBlock?.toString()],
|
|
218
|
+
enabled: Boolean(
|
|
219
|
+
watch && enabled && isContractAddressAndClientReady && blockNumber && (shouldStartPolling() || isPollingActive),
|
|
220
|
+
),
|
|
221
|
+
queryFn: async () => {
|
|
222
|
+
if (!isContractAddressAndClientReady || !blockNumber) return null;
|
|
223
|
+
|
|
224
|
+
if (!isPollingActive && shouldStartPolling()) {
|
|
225
|
+
setIsPollingActive(true);
|
|
226
|
+
}
|
|
197
227
|
|
|
198
|
-
|
|
228
|
+
const maxBlock = toBlock && toBlock < blockNumber ? toBlock : blockNumber;
|
|
229
|
+
const startBlock = lastFetchedBlock || maxBlock;
|
|
230
|
+
|
|
231
|
+
// Only fetch if there are new blocks to check
|
|
232
|
+
if (startBlock >= maxBlock) return null;
|
|
233
|
+
|
|
234
|
+
const newEvents = await getEvents(
|
|
235
|
+
{
|
|
236
|
+
address: deployedContractData?.address,
|
|
237
|
+
event,
|
|
238
|
+
fromBlock: startBlock + 1n,
|
|
239
|
+
toBlock: maxBlock,
|
|
240
|
+
args: filters,
|
|
241
|
+
},
|
|
242
|
+
publicClient,
|
|
243
|
+
{ blockData, transactionData, receiptData },
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
if (newEvents && newEvents.length > 0) {
|
|
247
|
+
setLiveEvents(prev => [...newEvents, ...prev]);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
setLastFetchedBlock(maxBlock);
|
|
251
|
+
return newEvents;
|
|
252
|
+
},
|
|
253
|
+
refetchInterval: false,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Manual trigger to fetch next page when previous page completes (only when not polling)
|
|
199
257
|
useEffect(() => {
|
|
200
|
-
if (
|
|
258
|
+
if (
|
|
259
|
+
!isPollingActive &&
|
|
260
|
+
query.status === "success" &&
|
|
261
|
+
query.hasNextPage &&
|
|
262
|
+
!query.isFetchingNextPage &&
|
|
263
|
+
!query.error
|
|
264
|
+
) {
|
|
201
265
|
query.fetchNextPage();
|
|
202
266
|
}
|
|
203
|
-
}, [query]);
|
|
267
|
+
}, [query, isPollingActive]);
|
|
268
|
+
|
|
269
|
+
// Combine historical data from infinite query with live events from watch hook
|
|
270
|
+
const historicalEvents = query.data?.pages || [];
|
|
271
|
+
const allEvents = [...liveEvents, ...historicalEvents] as typeof historicalEvents;
|
|
272
|
+
|
|
273
|
+
// remove duplicates
|
|
274
|
+
const seenEvents = new Set<string>();
|
|
275
|
+
const combinedEvents = allEvents.filter(event => {
|
|
276
|
+
const eventKey = `${event?.transactionHash}-${event?.logIndex}-${event?.blockHash}`;
|
|
277
|
+
if (seenEvents.has(eventKey)) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
seenEvents.add(eventKey);
|
|
281
|
+
return true;
|
|
282
|
+
}) as typeof historicalEvents;
|
|
204
283
|
|
|
205
284
|
return {
|
|
206
|
-
data:
|
|
285
|
+
data: combinedEvents,
|
|
207
286
|
status: query.status,
|
|
208
287
|
error: query.error,
|
|
209
288
|
isLoading: query.isLoading,
|
|
@@ -117,7 +117,11 @@ export function useScaffoldWriteContract<TContractName extends ContractName>(
|
|
|
117
117
|
} as WriteContractVariables<Abi, string, any[], Config, number>;
|
|
118
118
|
|
|
119
119
|
if (!finalConfig?.disableSimulate) {
|
|
120
|
-
await simulateContractWriteAndNotifyError({
|
|
120
|
+
await simulateContractWriteAndNotifyError({
|
|
121
|
+
wagmiConfig,
|
|
122
|
+
writeContractParams: writeContractObject,
|
|
123
|
+
chainId: selectedNetwork.id as AllowedChainIds,
|
|
124
|
+
});
|
|
121
125
|
}
|
|
122
126
|
|
|
123
127
|
const makeWriteWithParams = () =>
|
|
@@ -2,9 +2,10 @@ import { Hash, SendTransactionParameters, TransactionReceipt, WalletClient } fro
|
|
|
2
2
|
import { Config, useWalletClient } from "wagmi";
|
|
3
3
|
import { getPublicClient } from "wagmi/actions";
|
|
4
4
|
import { SendTransactionMutate } from "wagmi/query";
|
|
5
|
+
import scaffoldConfig from "~~/scaffold.config";
|
|
5
6
|
import { wagmiConfig } from "~~/services/web3/wagmiConfig";
|
|
6
|
-
import {
|
|
7
|
-
import { getBlockExplorerTxLink } from "~~/utils/scaffold-stylus";
|
|
7
|
+
import { getParsedErrorWithAllAbis, notification } from "~~/utils/scaffold-eth";
|
|
8
|
+
import { AllowedChainIds, getBlockExplorerTxLink } from "~~/utils/scaffold-stylus";
|
|
8
9
|
import { TransactorFuncOptions } from "~~/utils/scaffold-eth/contract";
|
|
9
10
|
|
|
10
11
|
type TransactionFunc = (
|
|
@@ -51,8 +52,9 @@ export const useTransactor = (_walletClient?: WalletClient): TransactionFunc =>
|
|
|
51
52
|
let transactionHash: Hash | undefined = undefined;
|
|
52
53
|
let transactionReceipt: TransactionReceipt | undefined;
|
|
53
54
|
let blockExplorerTxURL = "";
|
|
55
|
+
let chainId: number = scaffoldConfig.targetNetworks[0].id;
|
|
54
56
|
try {
|
|
55
|
-
|
|
57
|
+
chainId = await walletClient.getChainId();
|
|
56
58
|
// Get full transaction from public client
|
|
57
59
|
const publicClient = getPublicClient(wagmiConfig);
|
|
58
60
|
|
|
@@ -68,7 +70,7 @@ export const useTransactor = (_walletClient?: WalletClient): TransactionFunc =>
|
|
|
68
70
|
}
|
|
69
71
|
notification.remove(notificationId);
|
|
70
72
|
|
|
71
|
-
blockExplorerTxURL =
|
|
73
|
+
blockExplorerTxURL = chainId ? getBlockExplorerTxLink(chainId, transactionHash) : "";
|
|
72
74
|
|
|
73
75
|
notificationId = notification.loading(
|
|
74
76
|
<TxnNotification message="Waiting for transaction to complete." blockExplorerLink={blockExplorerTxURL} />,
|
|
@@ -95,7 +97,7 @@ export const useTransactor = (_walletClient?: WalletClient): TransactionFunc =>
|
|
|
95
97
|
notification.remove(notificationId);
|
|
96
98
|
}
|
|
97
99
|
console.error("⚡️ ~ file: useTransactor.ts ~ error", error);
|
|
98
|
-
const message =
|
|
100
|
+
const message = getParsedErrorWithAllAbis(error, chainId as AllowedChainIds);
|
|
99
101
|
|
|
100
102
|
// if receipt was reverted, show notification with block explorer link and return error
|
|
101
103
|
if (transactionReceipt?.status === "reverted") {
|
|
@@ -17,9 +17,9 @@ const LightBugAntIcon = ({ width = 26, height = 30, className = "" }) => {
|
|
|
17
17
|
<path
|
|
18
18
|
d="M13.0007 16.0776C14.6792 16.0776 16.3313 16.1925 17.9469 16.4179C19.4631 16.6275 20.6752 17.8049 20.6752 19.3082C20.6752 24.6609 17.2393 29 12.9993 29C8.75924 29 5.32482 24.6609 5.32482 19.3082C5.32482 17.8063 6.53835 16.6275 8.05306 16.4179C9.69215 16.1909 11.3454 16.0772 13.0007 16.0776ZM13.0007 16.0776C17.2159 16.0776 21.2571 16.807 25 18.1452C24.8235 21.1048 24.2573 24.0295 23.3157 26.8463M13.0007 16.0776C8.78556 16.0776 4.74438 16.807 1 18.1452C1.18276 21.1661 1.76028 24.0837 2.68578 26.8463M13.0007 16.0776C13.4456 16.0777 13.8858 15.9891 14.2949 15.8174C14.7039 15.6456 15.0732 15.3941 15.3804 15.0782C15.6877 14.7622 15.9264 14.3884 16.0824 13.9792C16.2383 13.57 16.308 13.1341 16.2875 12.6977M13.0007 16.0776C12.5559 16.0777 12.1156 15.9891 11.7066 15.8174C11.2976 15.6456 10.9283 15.3941 10.621 15.0782C10.3138 14.7622 10.075 14.3884 9.91911 13.9792C9.7632 13.57 9.69342 13.1341 9.71398 12.6977M16.2875 12.6977C16.2484 11.8675 15.885 11.0841 15.2729 10.5102C14.6607 9.93635 13.847 9.61623 13.0007 9.61638M16.2875 12.6977C18.884 12.4615 21.447 11.9404 23.9254 11.1441C23.845 9.52592 23.652 7.93646 23.3522 6.38578M9.71398 12.6977C9.7531 11.8675 10.1165 11.0841 10.7286 10.5102C11.3407 9.93635 12.1545 9.61623 13.0007 9.61638M9.71398 12.6977C7.07201 12.4564 4.5163 11.9281 2.07755 11.1441C2.15617 9.54687 2.34767 7.95693 2.65069 6.38578M13.0007 9.61638C14.4555 9.61638 15.8825 9.50151 17.2729 9.27752C17.8621 9.18276 18.3549 8.7635 18.4353 8.18343C18.5851 7.07324 18.3813 5.94474 17.8519 4.95282M13.0007 9.61638C11.546 9.61638 10.1204 9.50151 8.72854 9.27752C8.14079 9.18276 7.6466 8.7635 7.56619 8.18343C7.4116 7.07159 7.61615 5.94014 8.15102 4.94852M8.15102 4.94852C7.52825 4.54124 6.9608 4.05923 6.46232 3.51126C6.56467 2.60669 6.85708 1.75668 7.30155 1.00287M8.15102 4.94852C8.61646 4.08119 9.31421 3.35657 10.169 2.85008C11.0238 2.3436 12.0031 2.07592 13.0015 2.07592C13.9998 2.07592 14.9792 2.3436 15.8339 2.85008C16.6887 3.35657 17.3865 4.08263 17.8519 4.94995C18.4762 4.54361 19.0435 4.05974 19.5406 3.51556C19.4414 2.62879 19.1551 1.77205 18.6999 1"
|
|
19
19
|
stroke="url(#paint1_linear_2148_348)"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
strokeWidth="1.5"
|
|
21
|
+
strokeLinecap="round"
|
|
22
|
+
strokeLinejoin="round"
|
|
23
23
|
/>
|
|
24
24
|
<defs>
|
|
25
25
|
<linearGradient
|
|
@@ -30,8 +30,8 @@ const LightBugAntIcon = ({ width = 26, height = 30, className = "" }) => {
|
|
|
30
30
|
y2="15"
|
|
31
31
|
gradientUnits="userSpaceOnUse"
|
|
32
32
|
>
|
|
33
|
-
<stop
|
|
34
|
-
<stop offset="1"
|
|
33
|
+
<stop stopColor="#E3066E" />
|
|
34
|
+
<stop offset="1" stopColor="#203147" />
|
|
35
35
|
</linearGradient>
|
|
36
36
|
<linearGradient
|
|
37
37
|
id="paint1_linear_2148_348"
|
|
@@ -41,8 +41,8 @@ const LightBugAntIcon = ({ width = 26, height = 30, className = "" }) => {
|
|
|
41
41
|
y2="15"
|
|
42
42
|
gradientUnits="userSpaceOnUse"
|
|
43
43
|
>
|
|
44
|
-
<stop
|
|
45
|
-
<stop offset="1"
|
|
44
|
+
<stop stopColor="#E3066E" />
|
|
45
|
+
<stop offset="1" stopColor="#203147" />
|
|
46
46
|
</linearGradient>
|
|
47
47
|
</defs>
|
|
48
48
|
</svg>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="next" />
|
|
2
2
|
/// <reference types="next/image-types/global" />
|
|
3
|
+
/// <reference path="./.next/types/routes.d.ts" />
|
|
3
4
|
|
|
4
5
|
// NOTE: This file should not be edited
|
|
5
6
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
|
@@ -23,14 +23,13 @@
|
|
|
23
23
|
"has-ansi": "5.0.1"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@ethersproject/providers": "^5.7.2",
|
|
27
26
|
"@heroicons/react": "^2.1.5",
|
|
28
|
-
"@rainbow-me/rainbowkit": "2.2.
|
|
27
|
+
"@rainbow-me/rainbowkit": "2.2.8",
|
|
29
28
|
"@tanstack/react-query": "^5.59.15",
|
|
30
29
|
"@uniswap/sdk-core": "^5.8.2",
|
|
31
30
|
"@uniswap/v2-sdk": "^4.6.1",
|
|
32
31
|
"blo": "^1.2.0",
|
|
33
|
-
"burner-connector": "0.0.
|
|
32
|
+
"burner-connector": "0.0.18",
|
|
34
33
|
"daisyui": "4.5.0",
|
|
35
34
|
"kubo-rpc-client": "^5.0.2",
|
|
36
35
|
"next": "^15.2.3",
|
|
@@ -41,8 +40,8 @@
|
|
|
41
40
|
"react-dom": "^19.0.0",
|
|
42
41
|
"react-hot-toast": "^2.4.0",
|
|
43
42
|
"usehooks-ts": "^3.1.0",
|
|
44
|
-
"viem": "2.
|
|
45
|
-
"wagmi": "2.
|
|
43
|
+
"viem": "2.34.0",
|
|
44
|
+
"wagmi": "2.16.4",
|
|
46
45
|
"zustand": "^5.0.0"
|
|
47
46
|
},
|
|
48
47
|
"devDependencies": {
|
|
@@ -38,6 +38,7 @@ const wallets = [
|
|
|
38
38
|
*/
|
|
39
39
|
export const wagmiConnectors = () => {
|
|
40
40
|
// Only create connectors on client-side to avoid SSR issues
|
|
41
|
+
// TODO: update when https://github.com/rainbow-me/rainbowkit/issues/2476 is resolved
|
|
41
42
|
if (typeof window === "undefined") {
|
|
42
43
|
return [];
|
|
43
44
|
}
|
|
@@ -24,7 +24,9 @@ p {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
.btn {
|
|
27
|
-
box-shadow:
|
|
27
|
+
box-shadow:
|
|
28
|
+
0 4px 6px -1px rgb(0 0 0 / 0.1),
|
|
29
|
+
0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
.btn.btn-ghost {
|
|
@@ -96,14 +98,14 @@ p {
|
|
|
96
98
|
--spacing-2xl: 16px;
|
|
97
99
|
--spacing-4xl: 24px;
|
|
98
100
|
--spacing-7xl: 40px;
|
|
99
|
-
--stroke-sub-20: rgba(255, 255, 255, 0.
|
|
100
|
-
--bg-surface-surface-40: rgba(2, 2, 2, 0.
|
|
101
|
+
--stroke-sub-20: rgba(255, 255, 255, 0.2);
|
|
102
|
+
--bg-surface-surface-40: rgba(2, 2, 2, 0.4);
|
|
101
103
|
--bg-surface-input-20: rgba(255, 255, 255, 0.04);
|
|
102
|
-
--text-sub-600: rgba(255, 255, 255, 0.
|
|
103
|
-
--text-soft-400: rgba(255, 255, 255, 0.
|
|
104
|
-
--text-strong-950: #
|
|
105
|
-
--figma-pink: #
|
|
106
|
-
--figma-sky-blue: #
|
|
104
|
+
--text-sub-600: rgba(255, 255, 255, 0.6);
|
|
105
|
+
--text-soft-400: rgba(255, 255, 255, 0.4);
|
|
106
|
+
--text-strong-950: #ffffff;
|
|
107
|
+
--figma-pink: #ff50a2;
|
|
108
|
+
--figma-sky-blue: #30b4ed;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
111
|
/* Contract Card Styles */
|
|
@@ -116,8 +118,8 @@ p {
|
|
|
116
118
|
gap: var(--spacing-4xl, 24px);
|
|
117
119
|
align-self: stretch;
|
|
118
120
|
border-radius: var(--spacing-2xl, 16px);
|
|
119
|
-
border: 1px solid var(--stroke-sub-20, rgba(255, 255, 255, 0.
|
|
120
|
-
background: var(--bg-surface-surface-40, rgba(2, 2, 2, 0.
|
|
121
|
+
border: 1px solid var(--stroke-sub-20, rgba(255, 255, 255, 0.2));
|
|
122
|
+
background: var(--bg-surface-surface-40, rgba(2, 2, 2, 0.4));
|
|
121
123
|
backdrop-filter: blur(25px);
|
|
122
124
|
}
|
|
123
125
|
|
|
@@ -153,7 +155,7 @@ p {
|
|
|
153
155
|
|
|
154
156
|
/* Reusable Typography */
|
|
155
157
|
.typography-uppercase {
|
|
156
|
-
color: var(--text-sub-600, rgba(255, 255, 255, 0.
|
|
158
|
+
color: var(--text-sub-600, rgba(255, 255, 255, 0.6));
|
|
157
159
|
text-align: center;
|
|
158
160
|
font-family: var(--font-orbitron), sans-serif;
|
|
159
161
|
font-size: 14px;
|
|
@@ -200,7 +202,7 @@ p {
|
|
|
200
202
|
}
|
|
201
203
|
|
|
202
204
|
.tab-button:not(.active) .tab-text {
|
|
203
|
-
color: var(--text-sub-600, rgba(255, 255, 255, 0.
|
|
205
|
+
color: var(--text-sub-600, rgba(255, 255, 255, 0.6));
|
|
204
206
|
}
|
|
205
207
|
|
|
206
208
|
/* Function Styling */
|
|
@@ -209,7 +211,7 @@ p {
|
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
.param-type {
|
|
212
|
-
color: var(--text-sub-600, rgba(255, 255, 255, 0.
|
|
214
|
+
color: var(--text-sub-600, rgba(255, 255, 255, 0.6));
|
|
213
215
|
}
|
|
214
216
|
|
|
215
217
|
[data-theme="light"] .param-name {
|
|
@@ -234,7 +236,7 @@ p {
|
|
|
234
236
|
}
|
|
235
237
|
|
|
236
238
|
.input-text {
|
|
237
|
-
color: var(--text-soft-400, rgba(255, 255, 255, 0.
|
|
239
|
+
color: var(--text-soft-400, rgba(255, 255, 255, 0.4));
|
|
238
240
|
text-align: center;
|
|
239
241
|
font-family: Inter, sans-serif;
|
|
240
242
|
font-size: 14px;
|
|
@@ -296,7 +298,7 @@ p {
|
|
|
296
298
|
border: none !important;
|
|
297
299
|
box-shadow: none !important;
|
|
298
300
|
outline: none !important;
|
|
299
|
-
color: var(--text-soft-400, rgba(255, 255, 255, 0.
|
|
301
|
+
color: var(--text-soft-400, rgba(255, 255, 255, 0.4)) !important;
|
|
300
302
|
font-family: Inter, sans-serif !important;
|
|
301
303
|
font-size: 14px !important;
|
|
302
304
|
font-weight: 500 !important;
|
|
@@ -329,8 +331,8 @@ p {
|
|
|
329
331
|
align-items: center;
|
|
330
332
|
gap: 10px;
|
|
331
333
|
border-radius: var(--spacing-md, 8px);
|
|
332
|
-
background: linear-gradient(180deg, #
|
|
333
|
-
color: var(--text-strong-950, #
|
|
334
|
+
background: linear-gradient(180deg, #fc3592 0%, #e3066e 100%);
|
|
335
|
+
color: var(--text-strong-950, #fff);
|
|
334
336
|
text-align: center;
|
|
335
337
|
font-family: var(--font-orbitron), sans-serif;
|
|
336
338
|
font-size: 14px;
|
|
@@ -343,7 +345,9 @@ p {
|
|
|
343
345
|
cursor: pointer;
|
|
344
346
|
transition: all 0.2s ease;
|
|
345
347
|
position: relative;
|
|
346
|
-
box-shadow:
|
|
348
|
+
box-shadow:
|
|
349
|
+
0 2px 0 #ff9ccb,
|
|
350
|
+
0 4px 8px rgba(255, 156, 203, 0.3);
|
|
347
351
|
}
|
|
348
352
|
|
|
349
353
|
.send-button:hover {
|
|
@@ -364,8 +368,8 @@ p {
|
|
|
364
368
|
align-items: center;
|
|
365
369
|
gap: 10px;
|
|
366
370
|
border-radius: var(--spacing-md, 8px);
|
|
367
|
-
background: linear-gradient(180deg, #
|
|
368
|
-
color: var(--text-strong-950, #
|
|
371
|
+
background: linear-gradient(180deg, #fc3592 0%, #e3066e 100%);
|
|
372
|
+
color: var(--text-strong-950, #fff);
|
|
369
373
|
text-align: center;
|
|
370
374
|
font-family: var(--font-orbitron), sans-serif;
|
|
371
375
|
font-size: 14px;
|
|
@@ -378,7 +382,9 @@ p {
|
|
|
378
382
|
cursor: pointer;
|
|
379
383
|
transition: all 0.2s ease;
|
|
380
384
|
position: relative;
|
|
381
|
-
box-shadow:
|
|
385
|
+
box-shadow:
|
|
386
|
+
0 2px 0 #ff9ccb,
|
|
387
|
+
0 4px 8px rgba(255, 156, 203, 0.3);
|
|
382
388
|
margin-left: auto;
|
|
383
389
|
}
|
|
384
390
|
|
|
@@ -417,4 +423,4 @@ p {
|
|
|
417
423
|
display: flex;
|
|
418
424
|
align-items: center;
|
|
419
425
|
gap: 8px;
|
|
420
|
-
}
|
|
426
|
+
}
|