@scaffold-hbar-ui/debug-contracts 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/esm/Contract.js +22 -0
- package/dist/esm/components/Collapsible.js +9 -0
- package/dist/esm/components/ContractInput.js +56 -0
- package/dist/esm/components/ContractReadMethods.js +23 -0
- package/dist/esm/components/ContractVariables.js +23 -0
- package/dist/esm/components/ContractWriteMethods.js +23 -0
- package/dist/esm/components/DisplayVariable.js +34 -0
- package/dist/esm/components/InheritanceTooltip.js +4 -0
- package/dist/esm/components/ReadOnlyFunctionForm.js +48 -0
- package/dist/esm/components/Tooltip.js +37 -0
- package/dist/esm/components/Tuple.js +21 -0
- package/dist/esm/components/TupleArray.js +73 -0
- package/dist/esm/components/TxReceipt.js +13 -0
- package/dist/esm/components/WriteOnlyFunctionForm.js +59 -0
- package/dist/esm/components/inputs/Bytes32Input.js +13 -0
- package/dist/esm/components/inputs/BytesInput.js +10 -0
- package/dist/esm/components/inputs/DecimalMultiplierButtons.js +58 -0
- package/dist/esm/components/inputs/IntegerInput.js +17 -0
- package/dist/esm/components/inputs/index.js +4 -0
- package/dist/esm/contexts/ContractConfigContext.js +13 -0
- package/dist/esm/hooks/useAnimationConfig.js +16 -0
- package/dist/esm/hooks/useCopyToClipboard.js +17 -0
- package/dist/esm/hooks/useTransactor.js +86 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils/common.js +42 -0
- package/dist/esm/utils/contracts.js +186 -0
- package/dist/esm/utils/getParsedError.js +25 -0
- package/dist/esm/utils/inputs.js +100 -0
- package/dist/esm/utils/networks.js +46 -0
- package/dist/esm/utils/notification.js +45 -0
- package/dist/esm/utils/utilsDisplay.js +68 -0
- package/dist/types/Contract.d.ts +12 -0
- package/dist/types/Contract.d.ts.map +1 -0
- package/dist/types/components/Collapsible.d.ts +9 -0
- package/dist/types/components/Collapsible.d.ts.map +1 -0
- package/dist/types/components/ContractInput.d.ts +14 -0
- package/dist/types/components/ContractInput.d.ts.map +1 -0
- package/dist/types/components/ContractReadMethods.d.ts +8 -0
- package/dist/types/components/ContractReadMethods.d.ts.map +1 -0
- package/dist/types/components/ContractVariables.d.ts +10 -0
- package/dist/types/components/ContractVariables.d.ts.map +1 -0
- package/dist/types/components/ContractWriteMethods.d.ts +9 -0
- package/dist/types/components/ContractWriteMethods.d.ts.map +1 -0
- package/dist/types/components/DisplayVariable.d.ts +11 -0
- package/dist/types/components/DisplayVariable.d.ts.map +1 -0
- package/dist/types/components/InheritanceTooltip.d.ts +4 -0
- package/dist/types/components/InheritanceTooltip.d.ts.map +1 -0
- package/dist/types/components/ReadOnlyFunctionForm.d.ts +11 -0
- package/dist/types/components/ReadOnlyFunctionForm.d.ts.map +1 -0
- package/dist/types/components/Tooltip.d.ts +12 -0
- package/dist/types/components/Tooltip.d.ts.map +1 -0
- package/dist/types/components/Tuple.d.ts +11 -0
- package/dist/types/components/Tuple.d.ts.map +1 -0
- package/dist/types/components/TupleArray.d.ts +13 -0
- package/dist/types/components/TupleArray.d.ts.map +1 -0
- package/dist/types/components/TxReceipt.d.ts +5 -0
- package/dist/types/components/TxReceipt.d.ts.map +1 -0
- package/dist/types/components/WriteOnlyFunctionForm.d.ts +12 -0
- package/dist/types/components/WriteOnlyFunctionForm.d.ts.map +1 -0
- package/dist/types/components/inputs/Bytes32Input.d.ts +3 -0
- package/dist/types/components/inputs/Bytes32Input.d.ts.map +1 -0
- package/dist/types/components/inputs/BytesInput.d.ts +3 -0
- package/dist/types/components/inputs/BytesInput.d.ts.map +1 -0
- package/dist/types/components/inputs/DecimalMultiplierButtons.d.ts +7 -0
- package/dist/types/components/inputs/DecimalMultiplierButtons.d.ts.map +1 -0
- package/dist/types/components/inputs/IntegerInput.d.ts +7 -0
- package/dist/types/components/inputs/IntegerInput.d.ts.map +1 -0
- package/dist/types/components/inputs/index.d.ts +5 -0
- package/dist/types/components/inputs/index.d.ts.map +1 -0
- package/dist/types/contexts/ContractConfigContext.d.ts +13 -0
- package/dist/types/contexts/ContractConfigContext.d.ts.map +1 -0
- package/dist/types/hooks/useAnimationConfig.d.ts +4 -0
- package/dist/types/hooks/useAnimationConfig.d.ts.map +1 -0
- package/dist/types/hooks/useCopyToClipboard.d.ts +5 -0
- package/dist/types/hooks/useCopyToClipboard.d.ts.map +1 -0
- package/dist/types/hooks/useTransactor.d.ts +16 -0
- package/dist/types/hooks/useTransactor.d.ts.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/types.d.ts +16 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/utils/common.d.ts +5 -0
- package/dist/types/utils/common.d.ts.map +1 -0
- package/dist/types/utils/contracts.d.ts +29 -0
- package/dist/types/utils/contracts.d.ts.map +1 -0
- package/dist/types/utils/getParsedError.d.ts +7 -0
- package/dist/types/utils/getParsedError.d.ts.map +1 -0
- package/dist/types/utils/inputs.d.ts +78 -0
- package/dist/types/utils/inputs.d.ts.map +1 -0
- package/dist/types/utils/networks.d.ts +12 -0
- package/dist/types/utils/networks.d.ts.map +1 -0
- package/dist/types/utils/notification.d.ts +17 -0
- package/dist/types/utils/notification.d.ts.map +1 -0
- package/dist/types/utils/utilsDisplay.d.ts +14 -0
- package/dist/types/utils/utilsDisplay.d.ts.map +1 -0
- package/package.json +20 -20
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
const ANIMATION_TIME = 2000;
|
|
3
|
+
export function useAnimationConfig(data) {
|
|
4
|
+
const [showAnimation, setShowAnimation] = useState(false);
|
|
5
|
+
const [prevData, setPrevData] = useState();
|
|
6
|
+
useEffect(() => {
|
|
7
|
+
if (prevData !== undefined && prevData !== data) {
|
|
8
|
+
setShowAnimation(true);
|
|
9
|
+
setTimeout(() => setShowAnimation(false), ANIMATION_TIME);
|
|
10
|
+
}
|
|
11
|
+
setPrevData(data);
|
|
12
|
+
}, [data, prevData]);
|
|
13
|
+
return {
|
|
14
|
+
showAnimation,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
export const useCopyToClipboard = () => {
|
|
3
|
+
const [isCopiedToClipboard, setIsCopiedToClipboard] = useState(false);
|
|
4
|
+
const copyToClipboard = async (text) => {
|
|
5
|
+
try {
|
|
6
|
+
await navigator.clipboard.writeText(text);
|
|
7
|
+
setIsCopiedToClipboard(true);
|
|
8
|
+
setTimeout(() => {
|
|
9
|
+
setIsCopiedToClipboard(false);
|
|
10
|
+
}, 800);
|
|
11
|
+
}
|
|
12
|
+
catch (err) {
|
|
13
|
+
console.error("Failed to copy text:", err);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
return { copyToClipboard, isCopiedToClipboard };
|
|
17
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useConfig, useWalletClient } from "wagmi";
|
|
3
|
+
import { getPublicClient } from "wagmi/actions";
|
|
4
|
+
import { getParsedError } from "../utils/getParsedError";
|
|
5
|
+
import { notification } from "../utils/notification";
|
|
6
|
+
import { getBlockExplorerTxLink } from "../utils/networks";
|
|
7
|
+
/**
|
|
8
|
+
* Custom notification content for TXs.
|
|
9
|
+
*/
|
|
10
|
+
const TxnNotification = ({ message, blockExplorerLink }) => {
|
|
11
|
+
return (_jsxs("div", { className: `flex flex-col ml-1 cursor-default`, children: [_jsx("p", { className: "my-0", children: message }), blockExplorerLink && blockExplorerLink.length > 0 ? (_jsx("a", { href: blockExplorerLink, target: "_blank", rel: "noreferrer", className: "block link-dc", children: "check out transaction" })) : null] }));
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Runs Transaction passed in to returned function showing UI feedback.
|
|
15
|
+
* @param _walletClient - Optional wallet client to use. If not provided, will use the one from useWalletClient.
|
|
16
|
+
* @returns function that takes in transaction function as callback, shows UI feedback for transaction and returns a promise of the transaction hash
|
|
17
|
+
*/
|
|
18
|
+
export const useTransactor = (_walletClient) => {
|
|
19
|
+
let walletClient = _walletClient;
|
|
20
|
+
const { data } = useWalletClient();
|
|
21
|
+
const wagmiConfig = useConfig();
|
|
22
|
+
if (walletClient === undefined && data) {
|
|
23
|
+
walletClient = data;
|
|
24
|
+
}
|
|
25
|
+
const result = async (tx, options) => {
|
|
26
|
+
if (!walletClient) {
|
|
27
|
+
notification.error("Cannot access account");
|
|
28
|
+
console.error("⚡️ ~ file: useTransactor.tsx ~ error");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
let notificationId = null;
|
|
32
|
+
let transactionHash = undefined;
|
|
33
|
+
let transactionReceipt;
|
|
34
|
+
let blockExplorerTxURL = "";
|
|
35
|
+
try {
|
|
36
|
+
const network = await walletClient.getChainId();
|
|
37
|
+
// Get full transaction from public client
|
|
38
|
+
const publicClient = getPublicClient(wagmiConfig);
|
|
39
|
+
if (!publicClient)
|
|
40
|
+
throw new Error("Unable to access public client");
|
|
41
|
+
notificationId = notification.loading(_jsx(TxnNotification, { message: "Awaiting for user confirmation" }));
|
|
42
|
+
if (typeof tx === "function") {
|
|
43
|
+
// Tx is already prepared by the caller
|
|
44
|
+
const result = await tx();
|
|
45
|
+
transactionHash = result;
|
|
46
|
+
}
|
|
47
|
+
else if (tx != null) {
|
|
48
|
+
transactionHash = await walletClient.sendTransaction(tx);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
throw new Error("Incorrect transaction passed to transactor");
|
|
52
|
+
}
|
|
53
|
+
notification.remove(notificationId);
|
|
54
|
+
blockExplorerTxURL = network ? getBlockExplorerTxLink(network, transactionHash) : "";
|
|
55
|
+
notificationId = notification.loading(_jsx(TxnNotification, { message: "Waiting for transaction to complete.", blockExplorerLink: blockExplorerTxURL }));
|
|
56
|
+
transactionReceipt = await publicClient.waitForTransactionReceipt({
|
|
57
|
+
hash: transactionHash,
|
|
58
|
+
confirmations: options?.blockConfirmations,
|
|
59
|
+
});
|
|
60
|
+
notification.remove(notificationId);
|
|
61
|
+
if (transactionReceipt.status === "reverted")
|
|
62
|
+
throw new Error("Transaction reverted");
|
|
63
|
+
notification.success(_jsx(TxnNotification, { message: "Transaction completed successfully!", blockExplorerLink: blockExplorerTxURL }), {
|
|
64
|
+
icon: "🎉",
|
|
65
|
+
});
|
|
66
|
+
if (options?.onBlockConfirmation)
|
|
67
|
+
options.onBlockConfirmation(transactionReceipt);
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (notificationId) {
|
|
71
|
+
notification.remove(notificationId);
|
|
72
|
+
}
|
|
73
|
+
console.error("⚡️ ~ file: useTransactor.ts ~ error", error);
|
|
74
|
+
const message = getParsedError(error);
|
|
75
|
+
// if receipt was reverted, show notification with block explorer link and return error
|
|
76
|
+
if (transactionReceipt?.status === "reverted") {
|
|
77
|
+
notification.error(_jsx(TxnNotification, { message: message, blockExplorerLink: blockExplorerTxURL }));
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
notification.error(message);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
return transactionHash;
|
|
84
|
+
};
|
|
85
|
+
return result;
|
|
86
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { Contract } from "./Contract";
|
|
2
|
+
export { useContractConfig, ContractConfigProvider } from "./contexts/ContractConfigContext";
|
|
3
|
+
export { Bytes32Input, BytesInput, DecimalMultiplierButtons, IntegerInput, } from "./components/inputs/index";
|
|
4
|
+
export { IntegerVariant } from "./utils/inputs";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { hardhat, polygon, polygonMumbai, optimismSepolia, optimism, arbitrum, fantom, arbitrumSepolia, fantomTestnet, scrollSepolia, celo, celoAlfajores, sepolia, } from "viem/chains";
|
|
2
|
+
export const NETWORKS_EXTRA_DATA = {
|
|
3
|
+
[hardhat.id]: {
|
|
4
|
+
color: "#b8af0c",
|
|
5
|
+
},
|
|
6
|
+
[sepolia.id]: {
|
|
7
|
+
color: "#87ff65",
|
|
8
|
+
},
|
|
9
|
+
[polygon.id]: {
|
|
10
|
+
color: "#2bbdf7",
|
|
11
|
+
},
|
|
12
|
+
[polygonMumbai.id]: {
|
|
13
|
+
color: "#92D9FA",
|
|
14
|
+
},
|
|
15
|
+
[optimismSepolia.id]: {
|
|
16
|
+
color: "#f01a37",
|
|
17
|
+
},
|
|
18
|
+
[optimism.id]: {
|
|
19
|
+
color: "#f01a37",
|
|
20
|
+
},
|
|
21
|
+
[arbitrumSepolia.id]: {
|
|
22
|
+
color: "#28a0f0",
|
|
23
|
+
},
|
|
24
|
+
[arbitrum.id]: {
|
|
25
|
+
color: "#28a0f0",
|
|
26
|
+
},
|
|
27
|
+
[fantom.id]: {
|
|
28
|
+
color: "#1969ff",
|
|
29
|
+
},
|
|
30
|
+
[fantomTestnet.id]: {
|
|
31
|
+
color: "#1969ff",
|
|
32
|
+
},
|
|
33
|
+
[scrollSepolia.id]: {
|
|
34
|
+
color: "#fbebd4",
|
|
35
|
+
},
|
|
36
|
+
[celo.id]: {
|
|
37
|
+
color: "#FCFF52",
|
|
38
|
+
},
|
|
39
|
+
[celoAlfajores.id]: {
|
|
40
|
+
color: "#476520",
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { getAddress } from "viem";
|
|
2
|
+
import { simulateContract } from "wagmi/actions";
|
|
3
|
+
import { chainIdToHederaNetwork, getEvmAddressFromHederaAccountId, HEDERA_CHAIN_IDS } from "@scaffold-hbar-ui/hooks";
|
|
4
|
+
import { getParsedError } from "./getParsedError";
|
|
5
|
+
import { notification } from "./notification";
|
|
6
|
+
/**
|
|
7
|
+
* Generates a key based on function metadata
|
|
8
|
+
*/
|
|
9
|
+
const getFunctionInputKey = (functionName, input, inputIndex) => {
|
|
10
|
+
const name = input?.name || `input_${inputIndex}_`;
|
|
11
|
+
return functionName + "_" + name + "_" + input.internalType + "_" + input.type;
|
|
12
|
+
};
|
|
13
|
+
const isJsonString = (str) => {
|
|
14
|
+
try {
|
|
15
|
+
JSON.parse(str);
|
|
16
|
+
return true;
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
18
|
+
}
|
|
19
|
+
catch (e) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const isBigInt = (str) => {
|
|
24
|
+
if (str.trim().length === 0 || str.startsWith("0"))
|
|
25
|
+
return false;
|
|
26
|
+
try {
|
|
27
|
+
BigInt(str);
|
|
28
|
+
return true;
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
// Recursive function to deeply parse JSON strings, correctly handling nested arrays and encoded JSON strings
|
|
36
|
+
const deepParseValues = (value) => {
|
|
37
|
+
if (typeof value === "string") {
|
|
38
|
+
// first try with bigInt because we losse precision with JSON.parse
|
|
39
|
+
if (isBigInt(value)) {
|
|
40
|
+
return BigInt(value);
|
|
41
|
+
}
|
|
42
|
+
if (isJsonString(value)) {
|
|
43
|
+
const parsed = JSON.parse(value);
|
|
44
|
+
return deepParseValues(parsed);
|
|
45
|
+
}
|
|
46
|
+
// It's a string but not a JSON string, return as is
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
else if (Array.isArray(value)) {
|
|
50
|
+
// If it's an array, recursively parse each element
|
|
51
|
+
return value.map((element) => deepParseValues(element));
|
|
52
|
+
}
|
|
53
|
+
else if (typeof value === "object" && value !== null) {
|
|
54
|
+
// If it's an object, recursively parse each value
|
|
55
|
+
return Object.entries(value).reduce((acc, [key, val]) => {
|
|
56
|
+
acc[key] = deepParseValues(val);
|
|
57
|
+
return acc;
|
|
58
|
+
}, {});
|
|
59
|
+
}
|
|
60
|
+
// Handle boolean values represented as strings
|
|
61
|
+
if (value === "true" || value === "1" || value === "0x1" || value === "0x01" || value === "0x0001") {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
else if (value === "false" || value === "0" || value === "0x0" || value === "0x00" || value === "0x0000") {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* parses form input with array support
|
|
71
|
+
*/
|
|
72
|
+
const getParsedContractFunctionArgs = (form) => {
|
|
73
|
+
return Object.keys(form).map((key) => {
|
|
74
|
+
const valueOfArg = form[key];
|
|
75
|
+
// Attempt to deeply parse JSON strings
|
|
76
|
+
return deepParseValues(valueOfArg);
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
const getInitialFormState = (abiFunction) => {
|
|
80
|
+
const initialForm = {};
|
|
81
|
+
if (!abiFunction.inputs)
|
|
82
|
+
return initialForm;
|
|
83
|
+
abiFunction.inputs.forEach((input, inputIndex) => {
|
|
84
|
+
const key = getFunctionInputKey(abiFunction.name, input, inputIndex);
|
|
85
|
+
initialForm[key] = "";
|
|
86
|
+
});
|
|
87
|
+
return initialForm;
|
|
88
|
+
};
|
|
89
|
+
const getInitialTupleFormState = (abiTupleParameter) => {
|
|
90
|
+
const initialForm = {};
|
|
91
|
+
if (abiTupleParameter.components.length === 0)
|
|
92
|
+
return initialForm;
|
|
93
|
+
abiTupleParameter.components.forEach((component, componentIndex) => {
|
|
94
|
+
const key = getFunctionInputKey(abiTupleParameter.name || "tuple", component, componentIndex);
|
|
95
|
+
initialForm[key] = "";
|
|
96
|
+
});
|
|
97
|
+
return initialForm;
|
|
98
|
+
};
|
|
99
|
+
const getInitialTupleArrayFormState = (abiTupleParameter) => {
|
|
100
|
+
const initialForm = {};
|
|
101
|
+
if (abiTupleParameter.components.length === 0)
|
|
102
|
+
return initialForm;
|
|
103
|
+
abiTupleParameter.components.forEach((component, componentIndex) => {
|
|
104
|
+
const key = getFunctionInputKey("0_" + abiTupleParameter.name || "tuple", component, componentIndex);
|
|
105
|
+
initialForm[key] = "";
|
|
106
|
+
});
|
|
107
|
+
return initialForm;
|
|
108
|
+
};
|
|
109
|
+
const adjustInput = (input) => {
|
|
110
|
+
if (input.type.startsWith("tuple[")) {
|
|
111
|
+
const depth = (input.type.match(/\[\]/g) || []).length;
|
|
112
|
+
return {
|
|
113
|
+
...input,
|
|
114
|
+
components: transformComponents(input.components, depth, {
|
|
115
|
+
internalType: input.internalType || "struct",
|
|
116
|
+
name: input.name,
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
else if (input.components) {
|
|
121
|
+
return {
|
|
122
|
+
...input,
|
|
123
|
+
components: input.components.map((value) => adjustInput(value)),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return input;
|
|
127
|
+
};
|
|
128
|
+
const transformComponents = (components, depth, parentComponentData) => {
|
|
129
|
+
// Base case: if depth is 1 or no components, return the original components
|
|
130
|
+
if (depth === 1 || !components) {
|
|
131
|
+
return [...components];
|
|
132
|
+
}
|
|
133
|
+
// Recursive case: wrap components in an additional tuple layer
|
|
134
|
+
const wrappedComponents = {
|
|
135
|
+
internalType: `${parentComponentData.internalType || "struct"}`.replace(/\[\]/g, "") + "[]".repeat(depth - 1),
|
|
136
|
+
name: `${parentComponentData.name || "tuple"}`,
|
|
137
|
+
type: `tuple${"[]".repeat(depth - 1)}`,
|
|
138
|
+
components: transformComponents(components, depth - 1, parentComponentData),
|
|
139
|
+
};
|
|
140
|
+
return [wrappedComponents];
|
|
141
|
+
};
|
|
142
|
+
const transformAbiFunction = (abiFunction) => {
|
|
143
|
+
return {
|
|
144
|
+
...abiFunction,
|
|
145
|
+
inputs: abiFunction.inputs.map((value) => adjustInput(value)),
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
const NATIVE_ACCOUNT_ID_REGEX = /^\d+\.\d+\.\d+$/;
|
|
149
|
+
/**
|
|
150
|
+
* For Hedera chains: replaces top-level `address` form fields that look like `0.0.n`
|
|
151
|
+
* with the checksummed EVM alias so ABI encoding / simulate / read succeed.
|
|
152
|
+
*/
|
|
153
|
+
export async function resolveHederaNativeAccountIdsInForm(form, abiFunction, chainId) {
|
|
154
|
+
if (!HEDERA_CHAIN_IDS.has(chainId)) {
|
|
155
|
+
return form;
|
|
156
|
+
}
|
|
157
|
+
const network = chainIdToHederaNetwork(chainId);
|
|
158
|
+
const transformedFunction = transformAbiFunction(abiFunction);
|
|
159
|
+
const resolved = { ...form };
|
|
160
|
+
for (let inputIndex = 0; inputIndex < transformedFunction.inputs.length; inputIndex++) {
|
|
161
|
+
const input = transformedFunction.inputs[inputIndex];
|
|
162
|
+
if (input.type !== "address")
|
|
163
|
+
continue;
|
|
164
|
+
const key = getFunctionInputKey(abiFunction.name, input, inputIndex);
|
|
165
|
+
const raw = String(resolved[key] ?? "").trim();
|
|
166
|
+
if (!NATIVE_ACCOUNT_ID_REGEX.test(raw))
|
|
167
|
+
continue;
|
|
168
|
+
const evm = await getEvmAddressFromHederaAccountId(raw, network);
|
|
169
|
+
if (evm === null) {
|
|
170
|
+
throw new Error(`Account ${raw} has no EVM alias on this network.`);
|
|
171
|
+
}
|
|
172
|
+
resolved[key] = getAddress(evm);
|
|
173
|
+
}
|
|
174
|
+
return resolved;
|
|
175
|
+
}
|
|
176
|
+
export { getFunctionInputKey, getInitialFormState, getParsedContractFunctionArgs, getInitialTupleFormState, getInitialTupleArrayFormState, transformAbiFunction, };
|
|
177
|
+
export const simulateContractWriteAndNotifyError = async ({ wagmiConfig, writeContractParams: params, }) => {
|
|
178
|
+
try {
|
|
179
|
+
await simulateContract(wagmiConfig, params);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
const parsedError = getParsedError(error);
|
|
183
|
+
notification.error(parsedError);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseError as BaseViemError, ContractFunctionRevertedError } from "viem";
|
|
2
|
+
/**
|
|
3
|
+
* Parses an viem/wagmi error to get a displayable string
|
|
4
|
+
* @param e - error object
|
|
5
|
+
* @returns parsed error string
|
|
6
|
+
*/
|
|
7
|
+
export const getParsedError = (error) => {
|
|
8
|
+
const parsedError = error?.walk ? error.walk() : error;
|
|
9
|
+
if (parsedError instanceof BaseViemError) {
|
|
10
|
+
if (parsedError.details) {
|
|
11
|
+
return parsedError.details;
|
|
12
|
+
}
|
|
13
|
+
if (parsedError.shortMessage) {
|
|
14
|
+
if (parsedError instanceof ContractFunctionRevertedError &&
|
|
15
|
+
parsedError.data &&
|
|
16
|
+
parsedError.data.errorName !== "Error") {
|
|
17
|
+
const customErrorArgs = parsedError.data.args?.toString() ?? "";
|
|
18
|
+
return `${parsedError.shortMessage.replace(/reverted\.$/, "reverted with the following reason:")}\n${parsedError.data.errorName}(${customErrorArgs})`;
|
|
19
|
+
}
|
|
20
|
+
return parsedError.shortMessage;
|
|
21
|
+
}
|
|
22
|
+
return parsedError.message ?? parsedError.name ?? "An unknown error occurred";
|
|
23
|
+
}
|
|
24
|
+
return parsedError?.message ?? "An unknown error occurred";
|
|
25
|
+
};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
export var IntegerVariant;
|
|
2
|
+
(function (IntegerVariant) {
|
|
3
|
+
IntegerVariant["UINT8"] = "uint8";
|
|
4
|
+
IntegerVariant["UINT16"] = "uint16";
|
|
5
|
+
IntegerVariant["UINT24"] = "uint24";
|
|
6
|
+
IntegerVariant["UINT32"] = "uint32";
|
|
7
|
+
IntegerVariant["UINT40"] = "uint40";
|
|
8
|
+
IntegerVariant["UINT48"] = "uint48";
|
|
9
|
+
IntegerVariant["UINT56"] = "uint56";
|
|
10
|
+
IntegerVariant["UINT64"] = "uint64";
|
|
11
|
+
IntegerVariant["UINT72"] = "uint72";
|
|
12
|
+
IntegerVariant["UINT80"] = "uint80";
|
|
13
|
+
IntegerVariant["UINT88"] = "uint88";
|
|
14
|
+
IntegerVariant["UINT96"] = "uint96";
|
|
15
|
+
IntegerVariant["UINT104"] = "uint104";
|
|
16
|
+
IntegerVariant["UINT112"] = "uint112";
|
|
17
|
+
IntegerVariant["UINT120"] = "uint120";
|
|
18
|
+
IntegerVariant["UINT128"] = "uint128";
|
|
19
|
+
IntegerVariant["UINT136"] = "uint136";
|
|
20
|
+
IntegerVariant["UINT144"] = "uint144";
|
|
21
|
+
IntegerVariant["UINT152"] = "uint152";
|
|
22
|
+
IntegerVariant["UINT160"] = "uint160";
|
|
23
|
+
IntegerVariant["UINT168"] = "uint168";
|
|
24
|
+
IntegerVariant["UINT176"] = "uint176";
|
|
25
|
+
IntegerVariant["UINT184"] = "uint184";
|
|
26
|
+
IntegerVariant["UINT192"] = "uint192";
|
|
27
|
+
IntegerVariant["UINT200"] = "uint200";
|
|
28
|
+
IntegerVariant["UINT208"] = "uint208";
|
|
29
|
+
IntegerVariant["UINT216"] = "uint216";
|
|
30
|
+
IntegerVariant["UINT224"] = "uint224";
|
|
31
|
+
IntegerVariant["UINT232"] = "uint232";
|
|
32
|
+
IntegerVariant["UINT240"] = "uint240";
|
|
33
|
+
IntegerVariant["UINT248"] = "uint248";
|
|
34
|
+
IntegerVariant["UINT256"] = "uint256";
|
|
35
|
+
IntegerVariant["INT8"] = "int8";
|
|
36
|
+
IntegerVariant["INT16"] = "int16";
|
|
37
|
+
IntegerVariant["INT24"] = "int24";
|
|
38
|
+
IntegerVariant["INT32"] = "int32";
|
|
39
|
+
IntegerVariant["INT40"] = "int40";
|
|
40
|
+
IntegerVariant["INT48"] = "int48";
|
|
41
|
+
IntegerVariant["INT56"] = "int56";
|
|
42
|
+
IntegerVariant["INT64"] = "int64";
|
|
43
|
+
IntegerVariant["INT72"] = "int72";
|
|
44
|
+
IntegerVariant["INT80"] = "int80";
|
|
45
|
+
IntegerVariant["INT88"] = "int88";
|
|
46
|
+
IntegerVariant["INT96"] = "int96";
|
|
47
|
+
IntegerVariant["INT104"] = "int104";
|
|
48
|
+
IntegerVariant["INT112"] = "int112";
|
|
49
|
+
IntegerVariant["INT120"] = "int120";
|
|
50
|
+
IntegerVariant["INT128"] = "int128";
|
|
51
|
+
IntegerVariant["INT136"] = "int136";
|
|
52
|
+
IntegerVariant["INT144"] = "int144";
|
|
53
|
+
IntegerVariant["INT152"] = "int152";
|
|
54
|
+
IntegerVariant["INT160"] = "int160";
|
|
55
|
+
IntegerVariant["INT168"] = "int168";
|
|
56
|
+
IntegerVariant["INT176"] = "int176";
|
|
57
|
+
IntegerVariant["INT184"] = "int184";
|
|
58
|
+
IntegerVariant["INT192"] = "int192";
|
|
59
|
+
IntegerVariant["INT200"] = "int200";
|
|
60
|
+
IntegerVariant["INT208"] = "int208";
|
|
61
|
+
IntegerVariant["INT216"] = "int216";
|
|
62
|
+
IntegerVariant["INT224"] = "int224";
|
|
63
|
+
IntegerVariant["INT232"] = "int232";
|
|
64
|
+
IntegerVariant["INT240"] = "int240";
|
|
65
|
+
IntegerVariant["INT248"] = "int248";
|
|
66
|
+
IntegerVariant["INT256"] = "int256";
|
|
67
|
+
})(IntegerVariant || (IntegerVariant = {}));
|
|
68
|
+
export const SIGNED_NUMBER_REGEX = /^-?\d+\.?\d*$/;
|
|
69
|
+
export const UNSIGNED_NUMBER_REGEX = /^\.?\d+\.?\d*$/;
|
|
70
|
+
export const isValidInteger = (dataType, value) => {
|
|
71
|
+
const isSigned = dataType.startsWith("i");
|
|
72
|
+
const bitcount = Number(dataType.substring(isSigned ? 3 : 4));
|
|
73
|
+
let valueAsBigInt;
|
|
74
|
+
try {
|
|
75
|
+
valueAsBigInt = BigInt(value);
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
// console.error(e);
|
|
80
|
+
}
|
|
81
|
+
if (typeof valueAsBigInt !== "bigint") {
|
|
82
|
+
if (!value || typeof value !== "string") {
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return isSigned ? SIGNED_NUMBER_REGEX.test(value) || value === "-" : UNSIGNED_NUMBER_REGEX.test(value);
|
|
86
|
+
}
|
|
87
|
+
else if (!isSigned && valueAsBigInt < 0) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
const hexString = valueAsBigInt.toString(16);
|
|
91
|
+
const significantHexDigits = hexString.match(/.*x0*(.*)$/)?.[1] ?? "";
|
|
92
|
+
if (significantHexDigits.length * 4 > bitcount ||
|
|
93
|
+
(isSigned && significantHexDigits.length * 4 === bitcount && parseInt(significantHexDigits.slice(-1)?.[0], 16) < 8)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
};
|
|
98
|
+
// Treat any dot-separated string as a potential ENS name
|
|
99
|
+
const ensRegex = /.+\..+/;
|
|
100
|
+
export const isENS = (address = "") => ensRegex.test(address);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as chains from "viem/chains";
|
|
2
|
+
/**
|
|
3
|
+
* Gives the block explorer transaction URL, returns empty string if the network is a local chain
|
|
4
|
+
*/
|
|
5
|
+
export function getBlockExplorerTxLink(chainId, txnHash) {
|
|
6
|
+
const chainNames = Object.keys(chains);
|
|
7
|
+
const targetChainArr = chainNames.filter((chainName) => {
|
|
8
|
+
const wagmiChain = chains[chainName];
|
|
9
|
+
return wagmiChain.id === chainId;
|
|
10
|
+
});
|
|
11
|
+
if (targetChainArr.length === 0) {
|
|
12
|
+
return "";
|
|
13
|
+
}
|
|
14
|
+
const targetChain = targetChainArr[0];
|
|
15
|
+
const blockExplorerTxURL = chains[targetChain]?.blockExplorers?.default?.url;
|
|
16
|
+
if (!blockExplorerTxURL) {
|
|
17
|
+
return "";
|
|
18
|
+
}
|
|
19
|
+
return `${blockExplorerTxURL}/tx/${txnHash}`;
|
|
20
|
+
}
|
|
21
|
+
function hashscanBaseUrlForChainId(chainId) {
|
|
22
|
+
if (chainId === chains.hedera.id)
|
|
23
|
+
return "https://hashscan.io/mainnet";
|
|
24
|
+
if (chainId === chains.hederaTestnet.id)
|
|
25
|
+
return "https://hashscan.io/testnet";
|
|
26
|
+
return "https://hashscan.io/testnet";
|
|
27
|
+
}
|
|
28
|
+
function isHederaChainId(chainId) {
|
|
29
|
+
return chainId === chains.hedera.id || chainId === chains.hederaTestnet.id;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Gives the block explorer URL for a given address.
|
|
33
|
+
* Hedera chains use HashScan with `/account/`; EVM explorers use `/address/`.
|
|
34
|
+
* If no explorer is configured on the chain, falls back to HashScan (mainnet / testnet by id, else testnet).
|
|
35
|
+
*/
|
|
36
|
+
export function getBlockExplorerAddressLink(network, address) {
|
|
37
|
+
const blockExplorerBaseURL = network.blockExplorers?.default?.url;
|
|
38
|
+
if (network.id === chains.hardhat.id) {
|
|
39
|
+
return `/blockexplorer/address/${address}`;
|
|
40
|
+
}
|
|
41
|
+
if (!blockExplorerBaseURL) {
|
|
42
|
+
return `${hashscanBaseUrlForChainId(network.id)}/account/${address}`;
|
|
43
|
+
}
|
|
44
|
+
const pathSegment = isHederaChainId(network.id) ? "account" : "address";
|
|
45
|
+
return `${blockExplorerBaseURL}/${pathSegment}/${address}`;
|
|
46
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { toast } from "react-hot-toast";
|
|
3
|
+
import { XMarkIcon } from "@heroicons/react/20/solid";
|
|
4
|
+
import { CheckCircleIcon, ExclamationCircleIcon, ExclamationTriangleIcon, InformationCircleIcon, } from "@heroicons/react/24/solid";
|
|
5
|
+
const ENUM_STATUSES = {
|
|
6
|
+
success: _jsx(CheckCircleIcon, { className: "w-7 text-success" }),
|
|
7
|
+
loading: _jsx("span", { className: "w-4 loading-dc loading-dc-spinner" }),
|
|
8
|
+
error: _jsx(ExclamationCircleIcon, { className: "w-7 text-error" }),
|
|
9
|
+
info: _jsx(InformationCircleIcon, { className: "w-7 text-sui-primary" }),
|
|
10
|
+
warning: _jsx(ExclamationTriangleIcon, { className: "w-7 text-warning" }),
|
|
11
|
+
};
|
|
12
|
+
const DEFAULT_DURATION = 3000;
|
|
13
|
+
const DEFAULT_POSITION = "top-center";
|
|
14
|
+
/**
|
|
15
|
+
* Custom Notification
|
|
16
|
+
*/
|
|
17
|
+
const Notification = ({ content, status, duration = DEFAULT_DURATION, icon, position = DEFAULT_POSITION, }) => {
|
|
18
|
+
return toast.custom((t) => (_jsxs("div", { className: `flex flex-row items-start justify-between max-w-sm rounded-xl shadow-center shadow-sui-primary bg-sui-primary-neutral p-4 transform-gpu relative transition-all duration-500 ease-in-out space-x-2
|
|
19
|
+
${position.substring(0, 3) == "top"
|
|
20
|
+
? `hover:translate-y-1 ${t.visible ? "top-0" : "-top-96"}`
|
|
21
|
+
: `hover:-translate-y-1 ${t.visible ? "bottom-0" : "-bottom-96"}`}`, children: [_jsx("div", { className: "self-center", children: icon ? icon : ENUM_STATUSES[status] }), _jsx("div", { className: `overflow-x-hidden break-words whitespace-pre-line ${icon ? "mt-1" : ""}`, children: content }), _jsx("div", { className: `cursor-pointer text-lg ${icon ? "mt-1" : ""}`, onClick: () => toast.dismiss(t.id), children: _jsx(XMarkIcon, { className: "w-6 cursor-pointer", onClick: () => toast.remove(t.id) }) })] })), {
|
|
22
|
+
duration: status === "loading" ? Infinity : duration,
|
|
23
|
+
position,
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
export const notification = {
|
|
27
|
+
success: (content, options) => {
|
|
28
|
+
return Notification({ content, status: "success", ...options });
|
|
29
|
+
},
|
|
30
|
+
info: (content, options) => {
|
|
31
|
+
return Notification({ content, status: "info", ...options });
|
|
32
|
+
},
|
|
33
|
+
warning: (content, options) => {
|
|
34
|
+
return Notification({ content, status: "warning", ...options });
|
|
35
|
+
},
|
|
36
|
+
error: (content, options) => {
|
|
37
|
+
return Notification({ content, status: "error", ...options });
|
|
38
|
+
},
|
|
39
|
+
loading: (content, options) => {
|
|
40
|
+
return Notification({ content, status: "loading", ...options });
|
|
41
|
+
},
|
|
42
|
+
remove: (toastId) => {
|
|
43
|
+
toast.remove(toastId);
|
|
44
|
+
},
|
|
45
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { formatEther, formatUnits, isAddress, isHex } from "viem";
|
|
4
|
+
import { Address } from "@scaffold-hbar-ui/components";
|
|
5
|
+
import { Tooltip } from "../components/Tooltip";
|
|
6
|
+
import { useContractConfig } from "../contexts/ContractConfigContext";
|
|
7
|
+
// To be used in JSON.stringify when a field might be bigint
|
|
8
|
+
// https://wagmi.sh/react/faq#bigint-serialization
|
|
9
|
+
export const replacer = (_key, value) => (typeof value === "bigint" ? value.toString() : value);
|
|
10
|
+
const AddressWithConfig = ({ address, size }) => {
|
|
11
|
+
const { chain, blockExplorerAddressLink } = useContractConfig();
|
|
12
|
+
return (_jsx(Address, { address: address, size: size, chain: chain, blockExplorerAddressLink: blockExplorerAddressLink }));
|
|
13
|
+
};
|
|
14
|
+
export const displayTxResult = (displayContent, fontSize = "base") => {
|
|
15
|
+
if (displayContent == null) {
|
|
16
|
+
return "";
|
|
17
|
+
}
|
|
18
|
+
if (typeof displayContent === "bigint") {
|
|
19
|
+
return _jsx(NumberDisplay, { value: displayContent });
|
|
20
|
+
}
|
|
21
|
+
if (typeof displayContent === "string") {
|
|
22
|
+
if (isAddress(displayContent)) {
|
|
23
|
+
return (_jsx(AddressWithConfig, { address: displayContent, size: fontSize }));
|
|
24
|
+
}
|
|
25
|
+
if (isHex(displayContent)) {
|
|
26
|
+
return displayContent; // don't add quotes
|
|
27
|
+
}
|
|
28
|
+
return displayContent; // plain string (e.g. ERC20 name/symbol)
|
|
29
|
+
}
|
|
30
|
+
if (Array.isArray(displayContent)) {
|
|
31
|
+
return (_jsx(ArrayDisplay, { values: displayContent, size: fontSize }));
|
|
32
|
+
}
|
|
33
|
+
if (typeof displayContent === "object") {
|
|
34
|
+
return (_jsx(StructDisplay, { struct: displayContent, size: fontSize }));
|
|
35
|
+
}
|
|
36
|
+
return JSON.stringify(displayContent, replacer, 2);
|
|
37
|
+
};
|
|
38
|
+
const NumberDisplay = ({ value }) => {
|
|
39
|
+
const [mode, setMode] = useState("raw");
|
|
40
|
+
const asNumber = Number(value);
|
|
41
|
+
if (asNumber <= Number.MAX_SAFE_INTEGER && asNumber >= Number.MIN_SAFE_INTEGER) {
|
|
42
|
+
return String(value);
|
|
43
|
+
}
|
|
44
|
+
const displayText = mode === "raw" ? value.toString() : mode === "e8" ? formatUnits(value, 8) : formatEther(value);
|
|
45
|
+
const segments = [
|
|
46
|
+
{ mode: "raw", label: "Raw", tooltip: "Raw Format" },
|
|
47
|
+
{ mode: "e8", label: "8", tooltip: "8 Decimals" },
|
|
48
|
+
{ mode: "e18", label: "18", tooltip: "18 Decimals" },
|
|
49
|
+
];
|
|
50
|
+
return (_jsxs("div", { className: "flex min-w-0 flex-col gap-1.5 font-sans", children: [_jsx("div", { className: "min-w-0 w-full overflow-x-auto overscroll-x-contain py-0.5 [scrollbar-width:thin]", children: _jsx("span", { className: "inline-block whitespace-nowrap tabular-nums text-sui-primary-content", children: displayText }) }), _jsxs("div", { className: "flex min-w-0 flex-wrap items-center justify-between gap-x-2 gap-y-1", children: [_jsx("span", { className: "shrink-0 text-[10px] font-medium uppercase tracking-wide text-sui-primary-content/40", children: "Format" }), _jsx("div", { className: "inline-flex shrink-0 gap-1", role: "group", "aria-label": "Number format", children: segments.map(({ mode: m, label, tooltip }) => {
|
|
51
|
+
const active = mode === m;
|
|
52
|
+
return (_jsx(Tooltip, { content: tooltip, position: "bottom", children: _jsx("button", { type: "button", className: [
|
|
53
|
+
"min-w-[2.75rem] rounded-md px-2 py-1 text-[11px] font-medium transition-colors",
|
|
54
|
+
active
|
|
55
|
+
? "bg-sui-primary/40 text-sui-primary-content"
|
|
56
|
+
: "cursor-pointer bg-sui-primary-content/[0.06] text-sui-primary-content/60 hover:bg-sui-primary-content/[0.12] hover:text-sui-primary-content",
|
|
57
|
+
].join(" "), "aria-pressed": active, onClick: () => setMode(m), children: label }) }, m));
|
|
58
|
+
}) })] })] }));
|
|
59
|
+
};
|
|
60
|
+
export const ObjectFieldDisplay = ({ name, value, size, leftPad = true, }) => {
|
|
61
|
+
return (_jsxs("div", { className: `flex min-w-0 flex-row items-baseline ${leftPad ? "ml-4" : ""}`, children: [_jsxs("span", { className: "shrink-0 text-sui-primary-content/60 mr-2", children: [name, ":"] }), _jsx("span", { className: "min-w-0 flex-1 text-sui-primary-content", children: displayTxResult(value, size) })] }));
|
|
62
|
+
};
|
|
63
|
+
const ArrayDisplay = ({ values, size }) => {
|
|
64
|
+
return (_jsxs("div", { className: "flex flex-col gap-y-1", children: [values.length ? "array" : "[]", values.map((v, i) => (_jsx(ObjectFieldDisplay, { name: `[${i}]`, value: v, size: size }, i)))] }));
|
|
65
|
+
};
|
|
66
|
+
const StructDisplay = ({ struct, size }) => {
|
|
67
|
+
return (_jsxs("div", { className: "flex flex-col gap-y-1", children: ["struct", Object.entries(struct).map(([k, v]) => (_jsx(ObjectFieldDisplay, { name: k, value: v, size: size }, k)))] }));
|
|
68
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Abi, type Address as AddressType } from "viem";
|
|
2
|
+
export type ContractProps = {
|
|
3
|
+
contractName: string;
|
|
4
|
+
contract: {
|
|
5
|
+
address: AddressType;
|
|
6
|
+
abi: Abi;
|
|
7
|
+
};
|
|
8
|
+
chainId: number;
|
|
9
|
+
blockExplorerAddressLink?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const Contract: React.FC<ContractProps>;
|
|
12
|
+
//# sourceMappingURL=Contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Contract.d.ts","sourceRoot":"","sources":["../../src/Contract.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAgB,KAAK,OAAO,IAAI,WAAW,EAAE,MAAM,MAAM,CAAC;AAStE,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE;QACR,OAAO,EAAE,WAAW,CAAC;QACrB,GAAG,EAAE,GAAG,CAAC;KACV,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAwF5C,CAAC"}
|