create-stylus 1.1.0
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/.github/issue_template.md +7 -0
- package/.github/pull_request_template.md +11 -0
- package/.github/workflows/release-alpha.yml +32 -0
- package/.yarnrc.yml +1 -0
- package/CONTRIBUTING.md +42 -0
- package/README.md +66 -0
- package/bin/create-dapp-ss.js +4 -0
- package/dist/cli.js +656 -0
- package/dist/cli.js.map +1 -0
- package/package.json +46 -0
- package/rollup.config.js +22 -0
- package/src/cli.ts +14 -0
- package/src/extensions.json +14 -0
- package/src/main.ts +70 -0
- package/src/tasks/copy-extension-file.ts +227 -0
- package/src/tasks/copy-template-files.ts +252 -0
- package/src/tasks/create-first-git-commit.ts +35 -0
- package/src/tasks/create-project-directory.ts +34 -0
- package/src/tasks/index.ts +5 -0
- package/src/tasks/install-packages.ts +15 -0
- package/src/tasks/prettier-format.ts +17 -0
- package/src/types.ts +31 -0
- package/src/utils/consts.ts +1 -0
- package/src/utils/find-files-recursively.ts +19 -0
- package/src/utils/link.ts +44 -0
- package/src/utils/load-extensions.ts +10 -0
- package/src/utils/merge-package-json.ts +33 -0
- package/src/utils/parse-arguments-into-options.ts +38 -0
- package/src/utils/prompt-for-missing-options.ts +53 -0
- package/src/utils/render-intro-message.ts +11 -0
- package/src/utils/render-outro-message.ts +34 -0
- package/templates/base/.github/ISSUE_TEMPLATE/bug_report.yml +58 -0
- package/templates/base/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/templates/base/.github/pull_request_template.md +16 -0
- package/templates/base/.github/workflows/lint.yaml +300 -0
- package/templates/base/.gitignore.template.mjs +19 -0
- package/templates/base/.gitmodules +0 -0
- package/templates/base/.husky/pre-commit +4 -0
- package/templates/base/.lintstagedrc.js +21 -0
- package/templates/base/.vscode/settings.json +7 -0
- package/templates/base/.yarn/plugins/@yarnpkg/plugin-typescript.cjs +9 -0
- package/templates/base/.yarn/releases/yarn-3.2.3.cjs +783 -0
- package/templates/base/.yarnrc.yml +11 -0
- package/templates/base/CONTRIBUTING.md +86 -0
- package/templates/base/LICENCE +21 -0
- package/templates/base/nitro-devnode/LICENSE +201 -0
- package/templates/base/nitro-devnode/README.md +70 -0
- package/templates/base/nitro-devnode/run-dev-node.sh +132 -0
- package/templates/base/nitro-devnode/start-chain-with-cors.sh +150 -0
- package/templates/base/nitro-devnode/stylus-deployer-bytecode.txt +1 -0
- package/templates/base/nitro-devnode/stylus-dev/Dockerfile +10 -0
- package/templates/base/package.json +43 -0
- package/templates/base/packages/nextjs/.env.example +13 -0
- package/templates/base/packages/nextjs/.eslintignore +11 -0
- package/templates/base/packages/nextjs/.eslintrc.json +15 -0
- package/templates/base/packages/nextjs/.gitignore.template.mjs +42 -0
- package/templates/base/packages/nextjs/.prettierrc.js +9 -0
- package/templates/base/packages/nextjs/.prettierrc.json +8 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/AddressCodeTab.tsx +27 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/AddressComponent.tsx +36 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/AddressLogsTab.tsx +21 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/AddressStorageTab.tsx +61 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/BackButton.tsx +12 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/ContractTabs.tsx +102 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/PaginationButton.tsx +39 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/SearchBar.tsx +49 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/TransactionHash.tsx +28 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/TransactionsTable.tsx +71 -0
- package/templates/base/packages/nextjs/app/blockexplorer/_components/index.tsx +7 -0
- package/templates/base/packages/nextjs/app/blockexplorer/address/[address]/page.tsx +101 -0
- package/templates/base/packages/nextjs/app/blockexplorer/layout.tsx +12 -0
- package/templates/base/packages/nextjs/app/blockexplorer/page.tsx +83 -0
- package/templates/base/packages/nextjs/app/blockexplorer/transaction/[txHash]/page.tsx +23 -0
- package/templates/base/packages/nextjs/app/blockexplorer/transaction/_components/TransactionComp.tsx +152 -0
- package/templates/base/packages/nextjs/app/debug/_components/DebugContracts.tsx +73 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/ContractInput.tsx +84 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/ContractReadMethods.tsx +43 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/ContractUI.tsx +164 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/ContractVariables.tsx +50 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/ContractWriteMethods.tsx +49 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/DisplayVariable.tsx +85 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/InheritanceTooltip.tsx +14 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/ReadOnlyFunctionForm.tsx +102 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/Tuple.tsx +44 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/TupleArray.tsx +142 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/TxReceipt.tsx +42 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/WriteOnlyFunctionForm.tsx +144 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/index.tsx +8 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/utilsContract.tsx +166 -0
- package/templates/base/packages/nextjs/app/debug/_components/contract/utilsDisplay.tsx +114 -0
- package/templates/base/packages/nextjs/app/debug/page.tsx +14 -0
- package/templates/base/packages/nextjs/app/layout.tsx +67 -0
- package/templates/base/packages/nextjs/app/not-found.tsx +16 -0
- package/templates/base/packages/nextjs/app/page.tsx +94 -0
- package/templates/base/packages/nextjs/components/Background.tsx +37 -0
- package/templates/base/packages/nextjs/components/Card.tsx +40 -0
- package/templates/base/packages/nextjs/components/Footer.tsx +93 -0
- package/templates/base/packages/nextjs/components/Header.tsx +114 -0
- package/templates/base/packages/nextjs/components/ScaffoldEthAppWithProviders.tsx +77 -0
- package/templates/base/packages/nextjs/components/SwitchTheme.tsx +41 -0
- package/templates/base/packages/nextjs/components/ThemeProvider.tsx +13 -0
- package/templates/base/packages/nextjs/components/assets/BuidlGuidlLogo.tsx +18 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Address/Address.tsx +187 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Address/AddressCopyIcon.tsx +23 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Address/AddressLinkWrapper.tsx +29 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Balance.tsx +75 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/BlockieAvatar.tsx +17 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Faucet.tsx +131 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/FaucetButton.tsx +75 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Input/AddressInput.tsx +120 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Input/Bytes32Input.tsx +31 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Input/BytesInput.tsx +28 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Input/EtherInput.tsx +128 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Input/InputBase.tsx +66 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Input/IntegerInput.tsx +63 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Input/index.ts +9 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/Input/utils.ts +109 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/AddressInfoDropdown.tsx +121 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/AddressQRCodeModal.tsx +33 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/BurnerWalletModal.tsx +63 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/NetworkOptions.tsx +48 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/WrongNetworkDropdown.tsx +32 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/RainbowKitCustomConnectButton/index.tsx +89 -0
- package/templates/base/packages/nextjs/components/scaffold-eth/index.tsx +7 -0
- package/templates/base/packages/nextjs/contracts/deployedContracts.ts +9 -0
- package/templates/base/packages/nextjs/contracts/externalContracts.ts +16 -0
- package/templates/base/packages/nextjs/eslint.config.mjs +32 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/index.ts +17 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useAnimationConfig.ts +20 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useContractLogs.ts +40 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useCopyToClipboard.ts +19 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useDeployedContractInfo.ts +86 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useDisplayUsdMode.ts +21 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useFetchBlocks.ts +133 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useInitializeNativeCurrencyPrice.ts +32 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useNativeCurrencyPrice.ts +34 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useNetworkColor.ts +22 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useOutsideClick.ts +23 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldContract.ts +65 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldEventHistory.ts +213 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldReadContract.ts +80 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldWatchContractEvent.ts +40 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useScaffoldWriteContract.ts +191 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useSelectedNetwork.ts +18 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useTargetNetwork.ts +23 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useTransactor.tsx +114 -0
- package/templates/base/packages/nextjs/hooks/scaffold-eth/useWatchBalance.ts +21 -0
- package/templates/base/packages/nextjs/icons/CompassIcon.tsx +39 -0
- package/templates/base/packages/nextjs/icons/DarkBugAntIcon.tsx +30 -0
- package/templates/base/packages/nextjs/icons/LightBugAntIcon.tsx +52 -0
- package/templates/base/packages/nextjs/next-env.d.ts +5 -0
- package/templates/base/packages/nextjs/next.config.js +19 -0
- package/templates/base/packages/nextjs/package.json +58 -0
- package/templates/base/packages/nextjs/postcss.config.js +6 -0
- package/templates/base/packages/nextjs/public/debug-image.png +0 -0
- package/templates/base/packages/nextjs/public/favicon.png +0 -0
- package/templates/base/packages/nextjs/public/logo.svg +8 -0
- package/templates/base/packages/nextjs/public/manifest.json +5 -0
- package/templates/base/packages/nextjs/public/thumbnail.jpg +0 -0
- package/templates/base/packages/nextjs/react-copy-to-clipboard.d.ts +44 -0
- package/templates/base/packages/nextjs/scaffold.config.ts +56 -0
- package/templates/base/packages/nextjs/services/store/store.ts +39 -0
- package/templates/base/packages/nextjs/services/web3/wagmiConfig.tsx +44 -0
- package/templates/base/packages/nextjs/services/web3/wagmiConnectors.tsx +51 -0
- package/templates/base/packages/nextjs/styles/globals.css +80 -0
- package/templates/base/packages/nextjs/tailwind.config.js +97 -0
- package/templates/base/packages/nextjs/tsconfig.json +28 -0
- package/templates/base/packages/nextjs/types/abitype/abi.d.ts +16 -0
- package/templates/base/packages/nextjs/types/utils.ts +3 -0
- package/templates/base/packages/nextjs/utils/scaffold-eth/block.ts +17 -0
- package/templates/base/packages/nextjs/utils/scaffold-eth/common.ts +8 -0
- package/templates/base/packages/nextjs/utils/scaffold-eth/contract.ts +352 -0
- package/templates/base/packages/nextjs/utils/scaffold-eth/contractsData.ts +11 -0
- package/templates/base/packages/nextjs/utils/scaffold-eth/decodeTxData.ts +65 -0
- package/templates/base/packages/nextjs/utils/scaffold-eth/fetchPriceFromUniswap.ts +72 -0
- package/templates/base/packages/nextjs/utils/scaffold-eth/getMetadata.ts +50 -0
- package/templates/base/packages/nextjs/utils/scaffold-eth/getParsedError.ts +35 -0
- package/templates/base/packages/nextjs/utils/scaffold-eth/index.ts +6 -0
- package/templates/base/packages/nextjs/utils/scaffold-eth/notification.tsx +90 -0
- package/templates/base/packages/nextjs/utils/scaffold-stylus/burner.ts +59 -0
- package/templates/base/packages/nextjs/utils/scaffold-stylus/chain.ts +42 -0
- package/templates/base/packages/nextjs/utils/scaffold-stylus/index.ts +3 -0
- package/templates/base/packages/nextjs/utils/scaffold-stylus/networks.ts +94 -0
- package/templates/base/packages/nextjs/vercel.json +3 -0
- package/templates/base/packages/stylus/.env.example +13 -0
- package/templates/base/packages/stylus/.eslintrc.js +23 -0
- package/templates/base/packages/stylus/.gitignore.template.mjs +7 -0
- package/templates/base/packages/stylus/README.md +263 -0
- package/templates/base/packages/stylus/header.png +0 -0
- package/templates/base/packages/stylus/jest.config.js +15 -0
- package/templates/base/packages/stylus/package.json +49 -0
- package/templates/base/packages/stylus/scripts/deploy.ts +29 -0
- package/templates/base/packages/stylus/scripts/deploy_all_contracts.ts +59 -0
- package/templates/base/packages/stylus/scripts/deploy_contract.ts +93 -0
- package/templates/base/packages/stylus/scripts/deploy_wrapper.ts +79 -0
- package/templates/base/packages/stylus/scripts/export_abi.ts +87 -0
- package/templates/base/packages/stylus/scripts/index.ts +0 -0
- package/templates/base/packages/stylus/scripts/new_module.sh +35 -0
- package/templates/base/packages/stylus/scripts/test_network.ts +31 -0
- package/templates/base/packages/stylus/scripts/utils/command.ts +165 -0
- package/templates/base/packages/stylus/scripts/utils/contract.ts +219 -0
- package/templates/base/packages/stylus/scripts/utils/deployment.ts +136 -0
- package/templates/base/packages/stylus/scripts/utils/index.ts +6 -0
- package/templates/base/packages/stylus/scripts/utils/network.ts +112 -0
- package/templates/base/packages/stylus/scripts/utils/type.ts +48 -0
- package/templates/base/packages/stylus/scripts/utils.ts +3 -0
- package/templates/base/packages/stylus/tsconfig.json +41 -0
- package/templates/base/packages/stylus/your-contract/.cargo/config.toml +18 -0
- package/templates/base/packages/stylus/your-contract/Cargo.lock +5744 -0
- package/templates/base/packages/stylus/your-contract/Cargo.toml +46 -0
- package/templates/base/packages/stylus/your-contract/examples/counter.rs +78 -0
- package/templates/base/packages/stylus/your-contract/header.png +0 -0
- package/templates/base/packages/stylus/your-contract/licenses/Apache-2.0 +201 -0
- package/templates/base/packages/stylus/your-contract/licenses/COPYRIGHT.md +5 -0
- package/templates/base/packages/stylus/your-contract/licenses/DCO.txt +34 -0
- package/templates/base/packages/stylus/your-contract/licenses/MIT +21 -0
- package/templates/base/packages/stylus/your-contract/rust-toolchain.toml +2 -0
- package/templates/base/packages/stylus/your-contract/src/lib.rs +211 -0
- package/templates/base/packages/stylus/your-contract/src/main.rs +10 -0
- package/templates/base/readme.md +187 -0
- package/templates/base/yarn.lock +17860 -0
- package/tsconfig.json +13 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
3
|
+
import { Abi, AbiEvent, ExtractAbiEventNames } from "abitype";
|
|
4
|
+
import { BlockNumber, GetLogsParameters } from "viem";
|
|
5
|
+
import { Config, UsePublicClientReturnType, useBlockNumber, usePublicClient } from "wagmi";
|
|
6
|
+
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
|
|
7
|
+
import { useDeployedContractInfo } from "~~/hooks/scaffold-eth";
|
|
8
|
+
import { AllowedChainIds } from "~~/utils/scaffold-stylus";
|
|
9
|
+
import { replacer } from "~~/utils/scaffold-eth/common";
|
|
10
|
+
import {
|
|
11
|
+
ContractAbi,
|
|
12
|
+
ContractName,
|
|
13
|
+
UseScaffoldEventHistoryConfig,
|
|
14
|
+
UseScaffoldEventHistoryData,
|
|
15
|
+
} from "~~/utils/scaffold-eth/contract";
|
|
16
|
+
|
|
17
|
+
const getEvents = async (
|
|
18
|
+
getLogsParams: GetLogsParameters<AbiEvent | undefined, AbiEvent[] | undefined, boolean, BlockNumber, BlockNumber>,
|
|
19
|
+
publicClient?: UsePublicClientReturnType<Config, number>,
|
|
20
|
+
Options?: {
|
|
21
|
+
blockData?: boolean;
|
|
22
|
+
transactionData?: boolean;
|
|
23
|
+
receiptData?: boolean;
|
|
24
|
+
},
|
|
25
|
+
) => {
|
|
26
|
+
const logs = await publicClient?.getLogs({
|
|
27
|
+
address: getLogsParams.address,
|
|
28
|
+
fromBlock: getLogsParams.fromBlock,
|
|
29
|
+
toBlock: getLogsParams.toBlock,
|
|
30
|
+
args: getLogsParams.args,
|
|
31
|
+
event: getLogsParams.event,
|
|
32
|
+
});
|
|
33
|
+
if (!logs) return undefined;
|
|
34
|
+
|
|
35
|
+
const finalEvents = await Promise.all(
|
|
36
|
+
logs.map(async log => {
|
|
37
|
+
return {
|
|
38
|
+
...log,
|
|
39
|
+
blockData:
|
|
40
|
+
Options?.blockData && log.blockHash ? await publicClient?.getBlock({ blockHash: log.blockHash }) : null,
|
|
41
|
+
transactionData:
|
|
42
|
+
Options?.transactionData && log.transactionHash
|
|
43
|
+
? await publicClient?.getTransaction({ hash: log.transactionHash })
|
|
44
|
+
: null,
|
|
45
|
+
receiptData:
|
|
46
|
+
Options?.receiptData && log.transactionHash
|
|
47
|
+
? await publicClient?.getTransactionReceipt({ hash: log.transactionHash })
|
|
48
|
+
: null,
|
|
49
|
+
};
|
|
50
|
+
}),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
return finalEvents;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Reads events from a deployed contract
|
|
58
|
+
* @param config - The config settings
|
|
59
|
+
* @param config.contractName - deployed contract name
|
|
60
|
+
* @param config.eventName - name of the event to listen for
|
|
61
|
+
* @param config.fromBlock - the block number to start reading events from
|
|
62
|
+
* @param config.toBlock - optional block number to stop reading events at (if not provided, reads until current block)
|
|
63
|
+
* @param config.chainId - optional chainId that is configured with the scaffold project to make use for multi-chain interactions.
|
|
64
|
+
* @param config.filters - filters to be applied to the event (parameterName: value)
|
|
65
|
+
* @param config.blockData - if set to true it will return the block data for each event (default: false)
|
|
66
|
+
* @param config.transactionData - if set to true it will return the transaction data for each event (default: false)
|
|
67
|
+
* @param config.receiptData - if set to true it will return the receipt data for each event (default: false)
|
|
68
|
+
* @param config.watch - if set to true, the events will be updated every pollingInterval milliseconds set at scaffoldConfig (default: false)
|
|
69
|
+
* @param config.enabled - set this to false to disable the hook from running (default: true)
|
|
70
|
+
* @param config.blocksBatchSize - optional batch size for fetching events. If specified, each batch will contain at most this many blocks (default: 500)
|
|
71
|
+
*/
|
|
72
|
+
export const useScaffoldEventHistory = <
|
|
73
|
+
TContractName extends ContractName,
|
|
74
|
+
TEventName extends ExtractAbiEventNames<ContractAbi<TContractName>>,
|
|
75
|
+
TBlockData extends boolean = false,
|
|
76
|
+
TTransactionData extends boolean = false,
|
|
77
|
+
TReceiptData extends boolean = false,
|
|
78
|
+
>({
|
|
79
|
+
contractName,
|
|
80
|
+
eventName,
|
|
81
|
+
fromBlock,
|
|
82
|
+
toBlock,
|
|
83
|
+
chainId,
|
|
84
|
+
filters,
|
|
85
|
+
blockData,
|
|
86
|
+
transactionData,
|
|
87
|
+
receiptData,
|
|
88
|
+
watch,
|
|
89
|
+
enabled = true,
|
|
90
|
+
blocksBatchSize = 500,
|
|
91
|
+
}: UseScaffoldEventHistoryConfig<TContractName, TEventName, TBlockData, TTransactionData, TReceiptData>) => {
|
|
92
|
+
const selectedNetwork = useSelectedNetwork(chainId);
|
|
93
|
+
|
|
94
|
+
const publicClient = usePublicClient({
|
|
95
|
+
chainId: selectedNetwork.id,
|
|
96
|
+
});
|
|
97
|
+
const [isFirstRender, setIsFirstRender] = useState(true);
|
|
98
|
+
|
|
99
|
+
const { data: blockNumber } = useBlockNumber({ watch: watch, chainId: selectedNetwork.id });
|
|
100
|
+
|
|
101
|
+
const { data: deployedContractData } = useDeployedContractInfo({
|
|
102
|
+
contractName,
|
|
103
|
+
chainId: selectedNetwork.id as AllowedChainIds,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const event =
|
|
107
|
+
deployedContractData &&
|
|
108
|
+
((deployedContractData.abi as Abi).find(part => part.type === "event" && part.name === eventName) as AbiEvent);
|
|
109
|
+
|
|
110
|
+
const isContractAddressAndClientReady = Boolean(deployedContractData?.address) && Boolean(publicClient);
|
|
111
|
+
|
|
112
|
+
const query = useInfiniteQuery({
|
|
113
|
+
queryKey: [
|
|
114
|
+
"eventHistory",
|
|
115
|
+
{
|
|
116
|
+
contractName,
|
|
117
|
+
address: deployedContractData?.address,
|
|
118
|
+
eventName,
|
|
119
|
+
fromBlock: fromBlock.toString(),
|
|
120
|
+
toBlock: toBlock?.toString(),
|
|
121
|
+
chainId: selectedNetwork.id,
|
|
122
|
+
filters: JSON.stringify(filters, replacer),
|
|
123
|
+
blocksBatchSize: blocksBatchSize.toString(),
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
queryFn: async ({ pageParam }) => {
|
|
127
|
+
if (!isContractAddressAndClientReady) return undefined;
|
|
128
|
+
|
|
129
|
+
// Calculate the toBlock for this batch
|
|
130
|
+
let batchToBlock = toBlock;
|
|
131
|
+
const batchEndBlock = pageParam + BigInt(blocksBatchSize) - 1n;
|
|
132
|
+
const maxBlock = toBlock || (blockNumber ? BigInt(blockNumber) : undefined);
|
|
133
|
+
if (maxBlock) {
|
|
134
|
+
batchToBlock = batchEndBlock < maxBlock ? batchEndBlock : maxBlock;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const data = await getEvents(
|
|
138
|
+
{
|
|
139
|
+
address: deployedContractData?.address,
|
|
140
|
+
event,
|
|
141
|
+
fromBlock: pageParam,
|
|
142
|
+
toBlock: batchToBlock,
|
|
143
|
+
args: filters,
|
|
144
|
+
},
|
|
145
|
+
publicClient,
|
|
146
|
+
{ blockData, transactionData, receiptData },
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
return data;
|
|
150
|
+
},
|
|
151
|
+
enabled: enabled && isContractAddressAndClientReady,
|
|
152
|
+
initialPageParam: fromBlock,
|
|
153
|
+
getNextPageParam: (lastPage, allPages, lastPageParam) => {
|
|
154
|
+
if (!blockNumber || fromBlock >= blockNumber) return undefined;
|
|
155
|
+
|
|
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);
|
|
161
|
+
|
|
162
|
+
// Don't go beyond the specified toBlock or current block
|
|
163
|
+
const maxBlock = toBlock && toBlock < blockNumber ? toBlock : blockNumber;
|
|
164
|
+
|
|
165
|
+
if (nextBlock > maxBlock) return undefined;
|
|
166
|
+
|
|
167
|
+
return nextBlock;
|
|
168
|
+
},
|
|
169
|
+
select: data => {
|
|
170
|
+
const events = data.pages.flat() as unknown as UseScaffoldEventHistoryData<
|
|
171
|
+
TContractName,
|
|
172
|
+
TEventName,
|
|
173
|
+
TBlockData,
|
|
174
|
+
TTransactionData,
|
|
175
|
+
TReceiptData
|
|
176
|
+
>;
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
pages: events?.reverse(),
|
|
180
|
+
pageParams: data.pageParams,
|
|
181
|
+
};
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
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
|
+
}
|
|
193
|
+
|
|
194
|
+
query.fetchNextPage();
|
|
195
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
196
|
+
}, [blockNumber, watch]);
|
|
197
|
+
|
|
198
|
+
// Manual trigger to fetch next page when previous page completes
|
|
199
|
+
useEffect(() => {
|
|
200
|
+
if (query.status === "success" && query.hasNextPage && !query.isFetchingNextPage && !query.error) {
|
|
201
|
+
query.fetchNextPage();
|
|
202
|
+
}
|
|
203
|
+
}, [query]);
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
data: query.data?.pages,
|
|
207
|
+
status: query.status,
|
|
208
|
+
error: query.error,
|
|
209
|
+
isLoading: query.isLoading,
|
|
210
|
+
isFetchingNewEvent: query.isFetchingNextPage,
|
|
211
|
+
refetch: query.refetch,
|
|
212
|
+
};
|
|
213
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { QueryObserverResult, RefetchOptions, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import type { ExtractAbiFunctionNames } from "abitype";
|
|
4
|
+
import { ReadContractErrorType } from "viem";
|
|
5
|
+
import { useBlockNumber, useReadContract } from "wagmi";
|
|
6
|
+
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
|
|
7
|
+
import { useDeployedContractInfo } from "~~/hooks/scaffold-eth";
|
|
8
|
+
import { AllowedChainIds } from "~~/utils/scaffold-stylus";
|
|
9
|
+
import {
|
|
10
|
+
AbiFunctionReturnType,
|
|
11
|
+
ContractAbi,
|
|
12
|
+
ContractName,
|
|
13
|
+
UseScaffoldReadConfig,
|
|
14
|
+
} from "~~/utils/scaffold-eth/contract";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Wrapper around wagmi's useContractRead hook which automatically loads (by name) the contract ABI and address from
|
|
18
|
+
* the contracts present in deployedContracts.ts & externalContracts.ts corresponding to targetNetworks configured in scaffold.config.ts
|
|
19
|
+
* @param config - The config settings, including extra wagmi configuration
|
|
20
|
+
* @param config.contractName - deployed contract name
|
|
21
|
+
* @param config.functionName - name of the function to be called
|
|
22
|
+
* @param config.args - args to be passed to the function call
|
|
23
|
+
* @param config.chainId - optional chainId that is configured with the scaffold project to make use for multi-chain interactions.
|
|
24
|
+
*/
|
|
25
|
+
export const useScaffoldReadContract = <
|
|
26
|
+
TContractName extends ContractName,
|
|
27
|
+
TFunctionName extends ExtractAbiFunctionNames<ContractAbi<TContractName>, "pure" | "view">,
|
|
28
|
+
>({
|
|
29
|
+
contractName,
|
|
30
|
+
functionName,
|
|
31
|
+
args,
|
|
32
|
+
chainId,
|
|
33
|
+
...readConfig
|
|
34
|
+
}: UseScaffoldReadConfig<TContractName, TFunctionName>) => {
|
|
35
|
+
const selectedNetwork = useSelectedNetwork(chainId);
|
|
36
|
+
const { data: deployedContract } = useDeployedContractInfo({
|
|
37
|
+
contractName,
|
|
38
|
+
chainId: selectedNetwork.id as AllowedChainIds,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const { query: queryOptions, watch, ...readContractConfig } = readConfig;
|
|
42
|
+
// set watch to true by default
|
|
43
|
+
const defaultWatch = watch ?? true;
|
|
44
|
+
|
|
45
|
+
const readContractHookRes = useReadContract({
|
|
46
|
+
chainId: selectedNetwork.id,
|
|
47
|
+
functionName,
|
|
48
|
+
address: deployedContract?.address,
|
|
49
|
+
abi: deployedContract?.abi,
|
|
50
|
+
args,
|
|
51
|
+
...(readContractConfig as any),
|
|
52
|
+
query: {
|
|
53
|
+
enabled: !Array.isArray(args) || !args.some(arg => arg === undefined),
|
|
54
|
+
...queryOptions,
|
|
55
|
+
},
|
|
56
|
+
}) as Omit<ReturnType<typeof useReadContract>, "data" | "refetch"> & {
|
|
57
|
+
data: AbiFunctionReturnType<ContractAbi, TFunctionName> | undefined;
|
|
58
|
+
refetch: (
|
|
59
|
+
options?: RefetchOptions | undefined,
|
|
60
|
+
) => Promise<QueryObserverResult<AbiFunctionReturnType<ContractAbi, TFunctionName>, ReadContractErrorType>>;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const queryClient = useQueryClient();
|
|
64
|
+
const { data: blockNumber } = useBlockNumber({
|
|
65
|
+
watch: defaultWatch,
|
|
66
|
+
chainId: selectedNetwork.id,
|
|
67
|
+
query: {
|
|
68
|
+
enabled: defaultWatch,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
if (defaultWatch) {
|
|
74
|
+
queryClient.invalidateQueries({ queryKey: readContractHookRes.queryKey });
|
|
75
|
+
}
|
|
76
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
77
|
+
}, [blockNumber]);
|
|
78
|
+
|
|
79
|
+
return readContractHookRes;
|
|
80
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Abi, ExtractAbiEventNames } from "abitype";
|
|
2
|
+
import { Log } from "viem";
|
|
3
|
+
import { useWatchContractEvent } from "wagmi";
|
|
4
|
+
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
|
|
5
|
+
import { useDeployedContractInfo } from "~~/hooks/scaffold-eth";
|
|
6
|
+
import { AllowedChainIds } from "~~/utils/scaffold-stylus";
|
|
7
|
+
import { ContractAbi, ContractName, UseScaffoldEventConfig } from "~~/utils/scaffold-eth/contract";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Wrapper around wagmi's useEventSubscriber hook which automatically loads (by name) the contract ABI and
|
|
11
|
+
* address from the contracts present in deployedContracts.ts & externalContracts.ts
|
|
12
|
+
* @param config - The config settings
|
|
13
|
+
* @param config.contractName - deployed contract name
|
|
14
|
+
* @param config.eventName - name of the event to listen for
|
|
15
|
+
* @param config.chainId - optional chainId that is configured with the scaffold project to make use for multi-chain interactions.
|
|
16
|
+
* @param config.onLogs - the callback that receives events.
|
|
17
|
+
*/
|
|
18
|
+
export const useScaffoldWatchContractEvent = <
|
|
19
|
+
TContractName extends ContractName,
|
|
20
|
+
TEventName extends ExtractAbiEventNames<ContractAbi<TContractName>>,
|
|
21
|
+
>({
|
|
22
|
+
contractName,
|
|
23
|
+
eventName,
|
|
24
|
+
chainId,
|
|
25
|
+
onLogs,
|
|
26
|
+
}: UseScaffoldEventConfig<TContractName, TEventName>) => {
|
|
27
|
+
const selectedNetwork = useSelectedNetwork(chainId);
|
|
28
|
+
const { data: deployedContractData } = useDeployedContractInfo({
|
|
29
|
+
contractName,
|
|
30
|
+
chainId: selectedNetwork.id as AllowedChainIds,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
return useWatchContractEvent({
|
|
34
|
+
address: deployedContractData?.address,
|
|
35
|
+
abi: deployedContractData?.abi as Abi,
|
|
36
|
+
chainId: selectedNetwork.id,
|
|
37
|
+
onLogs: (logs: Log[]) => onLogs(logs as Parameters<typeof onLogs>[0]),
|
|
38
|
+
eventName,
|
|
39
|
+
});
|
|
40
|
+
};
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { MutateOptions } from "@tanstack/react-query";
|
|
3
|
+
import { Abi, ExtractAbiFunctionNames } from "abitype";
|
|
4
|
+
import { Config, UseWriteContractParameters, useAccount, useConfig, useWriteContract } from "wagmi";
|
|
5
|
+
import { WriteContractErrorType, WriteContractReturnType } from "wagmi/actions";
|
|
6
|
+
import { WriteContractVariables } from "wagmi/query";
|
|
7
|
+
import { useSelectedNetwork } from "~~/hooks/scaffold-eth";
|
|
8
|
+
import { useDeployedContractInfo, useTransactor } from "~~/hooks/scaffold-eth";
|
|
9
|
+
import { notification } from "~~/utils/scaffold-eth";
|
|
10
|
+
import { AllowedChainIds } from "~~/utils/scaffold-stylus";
|
|
11
|
+
import {
|
|
12
|
+
ContractAbi,
|
|
13
|
+
ContractName,
|
|
14
|
+
ScaffoldWriteContractOptions,
|
|
15
|
+
ScaffoldWriteContractVariables,
|
|
16
|
+
UseScaffoldWriteConfig,
|
|
17
|
+
simulateContractWriteAndNotifyError,
|
|
18
|
+
} from "~~/utils/scaffold-eth/contract";
|
|
19
|
+
|
|
20
|
+
type ScaffoldWriteContractReturnType<TContractName extends ContractName> = Omit<
|
|
21
|
+
ReturnType<typeof useWriteContract>,
|
|
22
|
+
"writeContract" | "writeContractAsync"
|
|
23
|
+
> & {
|
|
24
|
+
isMining: boolean;
|
|
25
|
+
writeContractAsync: <
|
|
26
|
+
TFunctionName extends ExtractAbiFunctionNames<ContractAbi<TContractName>, "nonpayable" | "payable">,
|
|
27
|
+
>(
|
|
28
|
+
variables: ScaffoldWriteContractVariables<TContractName, TFunctionName>,
|
|
29
|
+
options?: ScaffoldWriteContractOptions,
|
|
30
|
+
) => Promise<WriteContractReturnType | undefined>;
|
|
31
|
+
writeContract: <TFunctionName extends ExtractAbiFunctionNames<ContractAbi<TContractName>, "nonpayable" | "payable">>(
|
|
32
|
+
variables: ScaffoldWriteContractVariables<TContractName, TFunctionName>,
|
|
33
|
+
options?: Omit<ScaffoldWriteContractOptions, "onBlockConfirmation" | "blockConfirmations">,
|
|
34
|
+
) => void;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export function useScaffoldWriteContract<TContractName extends ContractName>(
|
|
38
|
+
config: UseScaffoldWriteConfig<TContractName>,
|
|
39
|
+
): ScaffoldWriteContractReturnType<TContractName>;
|
|
40
|
+
/**
|
|
41
|
+
* @deprecated Use object parameter version instead: useScaffoldWriteContract({ contractName: "YourContract" })
|
|
42
|
+
*/
|
|
43
|
+
export function useScaffoldWriteContract<TContractName extends ContractName>(
|
|
44
|
+
contractName: TContractName,
|
|
45
|
+
writeContractParams?: UseWriteContractParameters,
|
|
46
|
+
): ScaffoldWriteContractReturnType<TContractName>;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Wrapper around wagmi's useWriteContract hook which automatically loads (by name) the contract ABI and address from
|
|
50
|
+
* the contracts present in deployedContracts.ts & externalContracts.ts corresponding to targetNetworks configured in scaffold.config.ts
|
|
51
|
+
* @param contractName - name of the contract to be written to
|
|
52
|
+
* @param config.chainId - optional chainId that is configured with the scaffold project to make use for multi-chain interactions.
|
|
53
|
+
* @param writeContractParams - wagmi's useWriteContract parameters
|
|
54
|
+
*/
|
|
55
|
+
export function useScaffoldWriteContract<TContractName extends ContractName>(
|
|
56
|
+
configOrName: UseScaffoldWriteConfig<TContractName> | TContractName,
|
|
57
|
+
writeContractParams?: UseWriteContractParameters,
|
|
58
|
+
): ScaffoldWriteContractReturnType<TContractName> {
|
|
59
|
+
const finalConfig =
|
|
60
|
+
typeof configOrName === "string"
|
|
61
|
+
? { contractName: configOrName, writeContractParams, chainId: undefined }
|
|
62
|
+
: (configOrName as UseScaffoldWriteConfig<TContractName>);
|
|
63
|
+
const { contractName, chainId, writeContractParams: finalWriteContractParams } = finalConfig;
|
|
64
|
+
|
|
65
|
+
const wagmiConfig = useConfig();
|
|
66
|
+
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
if (typeof configOrName === "string") {
|
|
69
|
+
console.warn(
|
|
70
|
+
"Using `useScaffoldWriteContract` with a string parameter is deprecated. Please use the object parameter version instead.",
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}, [configOrName]);
|
|
74
|
+
|
|
75
|
+
const { chain: accountChain } = useAccount();
|
|
76
|
+
const writeTx = useTransactor();
|
|
77
|
+
const [isMining, setIsMining] = useState(false);
|
|
78
|
+
|
|
79
|
+
const wagmiContractWrite = useWriteContract(finalWriteContractParams);
|
|
80
|
+
|
|
81
|
+
const selectedNetwork = useSelectedNetwork(chainId);
|
|
82
|
+
|
|
83
|
+
const { data: deployedContractData } = useDeployedContractInfo({
|
|
84
|
+
contractName,
|
|
85
|
+
chainId: selectedNetwork.id as AllowedChainIds,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const sendContractWriteAsyncTx = async <
|
|
89
|
+
TFunctionName extends ExtractAbiFunctionNames<ContractAbi<TContractName>, "nonpayable" | "payable">,
|
|
90
|
+
>(
|
|
91
|
+
variables: ScaffoldWriteContractVariables<TContractName, TFunctionName>,
|
|
92
|
+
options?: ScaffoldWriteContractOptions,
|
|
93
|
+
) => {
|
|
94
|
+
if (!deployedContractData) {
|
|
95
|
+
notification.error("Target Contract is not deployed, did you forget to run `yarn deploy`?");
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!accountChain?.id) {
|
|
100
|
+
notification.error("Please connect your wallet");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (accountChain?.id !== selectedNetwork.id) {
|
|
105
|
+
notification.error(`Wallet is connected to the wrong network. Please switch to ${selectedNetwork.name}`);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
setIsMining(true);
|
|
111
|
+
const { blockConfirmations, onBlockConfirmation, ...mutateOptions } = options || {};
|
|
112
|
+
|
|
113
|
+
const writeContractObject = {
|
|
114
|
+
abi: deployedContractData.abi as Abi,
|
|
115
|
+
address: deployedContractData.address,
|
|
116
|
+
...variables,
|
|
117
|
+
} as WriteContractVariables<Abi, string, any[], Config, number>;
|
|
118
|
+
|
|
119
|
+
if (!finalConfig?.disableSimulate) {
|
|
120
|
+
await simulateContractWriteAndNotifyError({ wagmiConfig, writeContractParams: writeContractObject });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const makeWriteWithParams = () =>
|
|
124
|
+
wagmiContractWrite.writeContractAsync(
|
|
125
|
+
writeContractObject,
|
|
126
|
+
mutateOptions as
|
|
127
|
+
| MutateOptions<
|
|
128
|
+
WriteContractReturnType,
|
|
129
|
+
WriteContractErrorType,
|
|
130
|
+
WriteContractVariables<Abi, string, any[], Config, number>,
|
|
131
|
+
unknown
|
|
132
|
+
>
|
|
133
|
+
| undefined,
|
|
134
|
+
);
|
|
135
|
+
const writeTxResult = await writeTx(makeWriteWithParams, { blockConfirmations, onBlockConfirmation });
|
|
136
|
+
|
|
137
|
+
return writeTxResult;
|
|
138
|
+
} catch (e: any) {
|
|
139
|
+
throw e;
|
|
140
|
+
} finally {
|
|
141
|
+
setIsMining(false);
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const sendContractWriteTx = <
|
|
146
|
+
TContractName extends ContractName,
|
|
147
|
+
TFunctionName extends ExtractAbiFunctionNames<ContractAbi<TContractName>, "nonpayable" | "payable">,
|
|
148
|
+
>(
|
|
149
|
+
variables: ScaffoldWriteContractVariables<TContractName, TFunctionName>,
|
|
150
|
+
options?: Omit<ScaffoldWriteContractOptions, "onBlockConfirmation" | "blockConfirmations">,
|
|
151
|
+
) => {
|
|
152
|
+
if (!deployedContractData) {
|
|
153
|
+
notification.error("Target Contract is not deployed, did you forget to run `yarn deploy`?");
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (!accountChain?.id) {
|
|
157
|
+
notification.error("Please connect your wallet");
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (accountChain?.id !== selectedNetwork.id) {
|
|
162
|
+
notification.error(`Wallet is connected to the wrong network. Please switch to ${selectedNetwork.name}`);
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
wagmiContractWrite.writeContract(
|
|
167
|
+
{
|
|
168
|
+
abi: deployedContractData.abi as Abi,
|
|
169
|
+
address: deployedContractData.address,
|
|
170
|
+
...variables,
|
|
171
|
+
} as WriteContractVariables<Abi, string, any[], Config, number>,
|
|
172
|
+
options as
|
|
173
|
+
| MutateOptions<
|
|
174
|
+
WriteContractReturnType,
|
|
175
|
+
WriteContractErrorType,
|
|
176
|
+
WriteContractVariables<Abi, string, any[], Config, number>,
|
|
177
|
+
unknown
|
|
178
|
+
>
|
|
179
|
+
| undefined,
|
|
180
|
+
);
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
...wagmiContractWrite,
|
|
185
|
+
isMining,
|
|
186
|
+
// Overwrite wagmi's writeContactAsync
|
|
187
|
+
writeContractAsync: sendContractWriteAsyncTx,
|
|
188
|
+
// Overwrite wagmi's writeContract
|
|
189
|
+
writeContract: sendContractWriteTx,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import scaffoldConfig from "~~/scaffold.config";
|
|
2
|
+
import { useGlobalState } from "~~/services/store/store";
|
|
3
|
+
import { AllowedChainIds, ChainWithAttributes, NETWORKS_EXTRA_DATA } from "~~/utils/scaffold-stylus";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Given a chainId, retrives the network object from `scaffold.config`,
|
|
7
|
+
* if not found default to network set by `useTargetNetwork` hook
|
|
8
|
+
*/
|
|
9
|
+
export function useSelectedNetwork(chainId?: AllowedChainIds): ChainWithAttributes {
|
|
10
|
+
const globalTargetNetwork = useGlobalState(({ targetNetwork }) => targetNetwork);
|
|
11
|
+
const targetNetwork = scaffoldConfig.targetNetworks.find(targetNetwork => targetNetwork.id === chainId);
|
|
12
|
+
|
|
13
|
+
if (targetNetwork) {
|
|
14
|
+
return { ...targetNetwork, ...NETWORKS_EXTRA_DATA[targetNetwork.id] };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return globalTargetNetwork;
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useEffect, useMemo } from "react";
|
|
2
|
+
import { useAccount } from "wagmi";
|
|
3
|
+
import scaffoldConfig from "~~/scaffold.config";
|
|
4
|
+
import { useGlobalState } from "~~/services/store/store";
|
|
5
|
+
import { ChainWithAttributes, NETWORKS_EXTRA_DATA } from "~~/utils/scaffold-stylus";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Retrieves the connected wallet's network from scaffold.config or defaults to the 0th network in the list if the wallet is not connected.
|
|
9
|
+
*/
|
|
10
|
+
export function useTargetNetwork(): { targetNetwork: ChainWithAttributes } {
|
|
11
|
+
const { chain } = useAccount();
|
|
12
|
+
const targetNetwork = useGlobalState(({ targetNetwork }) => targetNetwork);
|
|
13
|
+
const setTargetNetwork = useGlobalState(({ setTargetNetwork }) => setTargetNetwork);
|
|
14
|
+
|
|
15
|
+
useEffect(() => {
|
|
16
|
+
const newSelectedNetwork = scaffoldConfig.targetNetworks.find(targetNetwork => targetNetwork.id === chain?.id);
|
|
17
|
+
if (newSelectedNetwork && newSelectedNetwork.id !== targetNetwork.id) {
|
|
18
|
+
setTargetNetwork({ ...newSelectedNetwork, ...NETWORKS_EXTRA_DATA[newSelectedNetwork.id] });
|
|
19
|
+
}
|
|
20
|
+
}, [chain?.id, setTargetNetwork, targetNetwork.id]);
|
|
21
|
+
|
|
22
|
+
return useMemo(() => ({ targetNetwork }), [targetNetwork]);
|
|
23
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Hash, SendTransactionParameters, TransactionReceipt, WalletClient } from "viem";
|
|
2
|
+
import { Config, useWalletClient } from "wagmi";
|
|
3
|
+
import { getPublicClient } from "wagmi/actions";
|
|
4
|
+
import { SendTransactionMutate } from "wagmi/query";
|
|
5
|
+
import { wagmiConfig } from "~~/services/web3/wagmiConfig";
|
|
6
|
+
import { getParsedError, notification } from "~~/utils/scaffold-eth";
|
|
7
|
+
import { getBlockExplorerTxLink } from "~~/utils/scaffold-stylus";
|
|
8
|
+
import { TransactorFuncOptions } from "~~/utils/scaffold-eth/contract";
|
|
9
|
+
|
|
10
|
+
type TransactionFunc = (
|
|
11
|
+
tx: (() => Promise<Hash>) | Parameters<SendTransactionMutate<Config, undefined>>[0],
|
|
12
|
+
options?: TransactorFuncOptions,
|
|
13
|
+
) => Promise<Hash | undefined>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Custom notification content for TXs.
|
|
17
|
+
*/
|
|
18
|
+
const TxnNotification = ({ message, blockExplorerLink }: { message: string; blockExplorerLink?: string }) => {
|
|
19
|
+
return (
|
|
20
|
+
<div className={`flex flex-col ml-1 cursor-default`}>
|
|
21
|
+
<p className="my-0">{message}</p>
|
|
22
|
+
{blockExplorerLink && blockExplorerLink.length > 0 ? (
|
|
23
|
+
<a href={blockExplorerLink} target="_blank" rel="noreferrer" className="block link">
|
|
24
|
+
check out transaction
|
|
25
|
+
</a>
|
|
26
|
+
) : null}
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Runs Transaction passed in to returned function showing UI feedback.
|
|
33
|
+
* @param _walletClient - Optional wallet client to use. If not provided, will use the one from useWalletClient.
|
|
34
|
+
* @returns function that takes in transaction function as callback, shows UI feedback for transaction and returns a promise of the transaction hash
|
|
35
|
+
*/
|
|
36
|
+
export const useTransactor = (_walletClient?: WalletClient): TransactionFunc => {
|
|
37
|
+
let walletClient = _walletClient;
|
|
38
|
+
const { data } = useWalletClient();
|
|
39
|
+
if (walletClient === undefined && data) {
|
|
40
|
+
walletClient = data;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const result: TransactionFunc = async (tx, options) => {
|
|
44
|
+
if (!walletClient) {
|
|
45
|
+
notification.error("Cannot access account");
|
|
46
|
+
console.error("⚡️ ~ file: useTransactor.tsx ~ error");
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let notificationId = null;
|
|
51
|
+
let transactionHash: Hash | undefined = undefined;
|
|
52
|
+
let transactionReceipt: TransactionReceipt | undefined;
|
|
53
|
+
let blockExplorerTxURL = "";
|
|
54
|
+
try {
|
|
55
|
+
const network = await walletClient.getChainId();
|
|
56
|
+
// Get full transaction from public client
|
|
57
|
+
const publicClient = getPublicClient(wagmiConfig);
|
|
58
|
+
|
|
59
|
+
notificationId = notification.loading(<TxnNotification message="Awaiting for user confirmation" />);
|
|
60
|
+
if (typeof tx === "function") {
|
|
61
|
+
// Tx is already prepared by the caller
|
|
62
|
+
const result = await tx();
|
|
63
|
+
transactionHash = result;
|
|
64
|
+
} else if (tx != null) {
|
|
65
|
+
transactionHash = await walletClient.sendTransaction(tx as SendTransactionParameters);
|
|
66
|
+
} else {
|
|
67
|
+
throw new Error("Incorrect transaction passed to transactor");
|
|
68
|
+
}
|
|
69
|
+
notification.remove(notificationId);
|
|
70
|
+
|
|
71
|
+
blockExplorerTxURL = network ? getBlockExplorerTxLink(network, transactionHash) : "";
|
|
72
|
+
|
|
73
|
+
notificationId = notification.loading(
|
|
74
|
+
<TxnNotification message="Waiting for transaction to complete." blockExplorerLink={blockExplorerTxURL} />,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
transactionReceipt = await publicClient.waitForTransactionReceipt({
|
|
78
|
+
hash: transactionHash,
|
|
79
|
+
confirmations: options?.blockConfirmations,
|
|
80
|
+
});
|
|
81
|
+
notification.remove(notificationId);
|
|
82
|
+
|
|
83
|
+
if (transactionReceipt.status === "reverted") throw new Error("Transaction reverted");
|
|
84
|
+
|
|
85
|
+
notification.success(
|
|
86
|
+
<TxnNotification message="Transaction completed successfully!" blockExplorerLink={blockExplorerTxURL} />,
|
|
87
|
+
{
|
|
88
|
+
icon: "🎉",
|
|
89
|
+
},
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (options?.onBlockConfirmation) options.onBlockConfirmation(transactionReceipt);
|
|
93
|
+
} catch (error: any) {
|
|
94
|
+
if (notificationId) {
|
|
95
|
+
notification.remove(notificationId);
|
|
96
|
+
}
|
|
97
|
+
console.error("⚡️ ~ file: useTransactor.ts ~ error", error);
|
|
98
|
+
const message = getParsedError(error);
|
|
99
|
+
|
|
100
|
+
// if receipt was reverted, show notification with block explorer link and return error
|
|
101
|
+
if (transactionReceipt?.status === "reverted") {
|
|
102
|
+
notification.error(<TxnNotification message={message} blockExplorerLink={blockExplorerTxURL} />);
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
notification.error(message);
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return transactionHash;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return result;
|
|
114
|
+
};
|