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.
Files changed (38) hide show
  1. package/dist/cli.js +7 -8
  2. package/dist/cli.js.map +1 -1
  3. package/package.json +1 -1
  4. package/src/main.ts +2 -4
  5. package/src/tasks/copy-template-files.ts +7 -4
  6. package/src/utils/prompt-for-missing-options.ts +1 -1
  7. package/templates/base/package.json +1 -1
  8. package/templates/base/packages/nextjs/app/blockexplorer/_components/TransactionsTable.tsx +11 -9
  9. package/templates/base/packages/nextjs/app/debug/_components/contract/ContractUI.tsx +2 -2
  10. package/templates/base/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx +8 -4
  11. package/templates/base/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx +1 -9
  12. package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/AddressInfoDropdown.tsx +138 -24
  13. package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/RevealBurnerPKModal.tsx +59 -0
  14. package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/index.tsx +3 -2
  15. package/templates/base/packages/nextjs/eslint.config.mjs +6 -0
  16. package/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldEventHistory.ts +107 -28
  17. package/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldWriteContract.ts +5 -1
  18. package/templates/base/packages/nextjs/hooks/scaffold-eth/useTransactor.tsx +7 -5
  19. package/templates/base/packages/nextjs/icons/LightBugAntIcon.tsx +7 -7
  20. package/templates/base/packages/nextjs/next-env.d.ts +1 -0
  21. package/templates/base/packages/nextjs/package.json +4 -5
  22. package/templates/base/packages/nextjs/services/web3/wagmiConnectors.tsx +1 -0
  23. package/templates/base/packages/nextjs/styles/globals.css +28 -22
  24. package/templates/base/packages/nextjs/tailwind.config.js +1 -1
  25. package/templates/base/packages/nextjs/utils/scaffold-eth/contract.ts +74 -2
  26. package/templates/base/packages/stylus/scripts/deploy.ts +0 -8
  27. package/templates/base/packages/stylus/your-contract/Cargo.lock +4 -4
  28. package/templates/base/packages/stylus/your-contract/Cargo.toml +1 -1
  29. package/templates/base/packages/stylus/your-contract/src/lib.rs +3 -7
  30. package/templates/base/readme.md +56 -174
  31. package/templates/base/yarn.lock +239 -297
  32. package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/AngularWalletAddress.tsx +0 -223
  33. package/templates/base/packages/stylus/counter/.cargo/config.toml +0 -18
  34. package/templates/base/packages/stylus/counter/Cargo.lock +0 -5788
  35. package/templates/base/packages/stylus/counter/Cargo.toml +0 -46
  36. package/templates/base/packages/stylus/counter/rust-toolchain.toml +0 -2
  37. package/templates/base/packages/stylus/counter/src/lib.rs +0 -121
  38. 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
- <AngularWalletAddress
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
  })()}
@@ -29,4 +29,10 @@ export default defineConfig([
29
29
  ],
30
30
  },
31
31
  },
32
+ {
33
+ files: ["next-env.d.ts"],
34
+ rules: {
35
+ "@typescript-eslint/triple-slash-reference": "off",
36
+ },
37
+ },
32
38
  ]);
@@ -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
- * Reads events from a deployed contract
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 - the block number to start reading events from
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 [isFirstRender, setIsFirstRender] = useState(true);
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: fromBlock.toString(),
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: fromBlock,
178
+ enabled: enabled && isContractAddressAndClientReady && !isPollingActive, // Disable when polling starts
179
+ initialPageParam: fromBlockValue,
153
180
  getNextPageParam: (lastPage, allPages, lastPageParam) => {
154
- if (!blockNumber || fromBlock >= blockNumber) return undefined;
181
+ if (!blockNumber || fromBlockValue >= blockNumber) return undefined;
155
182
 
156
- const lastPageHighestBlock = Math.max(
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
- useEffect(() => {
186
- const shouldSkipEffect = !blockNumber || !watch || isFirstRender;
187
- if (shouldSkipEffect) {
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.fetchNextPage();
195
- // eslint-disable-next-line react-hooks/exhaustive-deps
196
- }, [blockNumber, watch]);
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
- // Manual trigger to fetch next page when previous page completes
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 (query.status === "success" && query.hasNextPage && !query.isFetchingNextPage && !query.error) {
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: query.data?.pages,
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({ wagmiConfig, writeContractParams: writeContractObject });
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 { getParsedError, notification } from "~~/utils/scaffold-eth";
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
- const network = await walletClient.getChainId();
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 = network ? getBlockExplorerTxLink(network, transactionHash) : "";
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 = getParsedError(error);
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
- stroke-width="1.5"
21
- stroke-linecap="round"
22
- stroke-linejoin="round"
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 stop-color="#E3066E" />
34
- <stop offset="1" stop-color="#203147" />
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 stop-color="#E3066E" />
45
- <stop offset="1" stop-color="#203147" />
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.7",
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.16",
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.31.1",
45
- "wagmi": "2.15.6",
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: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
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.20);
100
- --bg-surface-surface-40: rgba(2, 2, 2, 0.40);
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.60);
103
- --text-soft-400: rgba(255, 255, 255, 0.40);
104
- --text-strong-950: #FFFFFF;
105
- --figma-pink: #FF50A2;
106
- --figma-sky-blue: #30B4ED;
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.20));
120
- background: var(--bg-surface-surface-40, rgba(2, 2, 2, 0.40));
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.60));
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.60));
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.60));
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.40));
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.40)) !important;
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, #FC3592 0%, #E3066E 100%);
333
- color: var(--text-strong-950, #FFF);
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: 0 2px 0 #FF9CCB, 0 4px 8px rgba(255, 156, 203, 0.3);
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, #FC3592 0%, #E3066E 100%);
368
- color: var(--text-strong-950, #FFF);
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: 0 2px 0 #FF9CCB, 0 4px 8px rgba(255, 156, 203, 0.3);
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
+ }
@@ -99,4 +99,4 @@ module.exports = {
99
99
  },
100
100
  },
101
101
  },
102
- };
102
+ };