Skip to content

Commit

Permalink
deployedContracts & externalContracts (#592)
Browse files Browse the repository at this point in the history
  • Loading branch information
technophile-04 authored Nov 2, 2023
1 parent 9dd6ce2 commit 61b1c64
Show file tree
Hide file tree
Showing 12 changed files with 81 additions and 44 deletions.
27 changes: 16 additions & 11 deletions packages/hardhat/deploy/99_generateTsAbis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ import * as fs from "fs";
import prettier from "prettier";
import { DeployFunction } from "hardhat-deploy/types";

const generatedContractComment = `
/**
* This file is autogenerated by Scaffold-ETH.
* You should not edit it manually or your changes might be overwritten.
*/
`;

function getDirectories(path: string) {
return fs
.readdirSync(path, { withFileTypes: true })
Expand Down Expand Up @@ -40,13 +47,7 @@ function getContractDataFromDeployments() {
);
contracts[contractName] = { address, abi };
}
output[chainId] = [
{
chainId,
name: chainName,
contracts,
},
];
output[chainId] = contracts;
}
return output;
}
Expand All @@ -56,7 +57,7 @@ function getContractDataFromDeployments() {
* This script should be run last.
*/
const generateTsAbis: DeployFunction = async function () {
const TARGET_DIR = "../nextjs/generated/";
const TARGET_DIR = "../nextjs/contracts/";
const allContractsData = getContractDataFromDeployments();

const fileContent = Object.entries(allContractsData).reduce((content, [chainId, chainConfig]) => {
Expand All @@ -68,9 +69,13 @@ const generateTsAbis: DeployFunction = async function () {
}
fs.writeFileSync(
`${TARGET_DIR}deployedContracts.ts`,
prettier.format(`const contracts = {${fileContent}} as const; \n\n export default contracts`, {
parser: "typescript",
}),
prettier.format(
`${generatedContractComment} import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract"; \n\n
const deployedContracts = {${fileContent}} as const; \n\n export default deployedContracts satisfies GenericContractsDeclaration`,
{
parser: "typescript",
},
),
);

console.log(`📝 Updated TypeScript contract definition file on ${TARGET_DIR}deployedContracts.ts`);
Expand Down
9 changes: 9 additions & 0 deletions packages/nextjs/contracts/deployedContracts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* This file is autogenerated by Scaffold-ETH.
* You should not edit it manually or your changes might be overwritten.
*/
import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract";

const deployedContracts = {} as const;

export default deployedContracts satisfies GenericContractsDeclaration;
15 changes: 15 additions & 0 deletions packages/nextjs/contracts/externalContracts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract";

/**
* @example
* const externalContracts = {
* 1: {
* DAI: {
* address: "0x...",
* abi: [...],
* }
* } as const;
*/
const externalContracts = {} as const;

export default externalContracts satisfies GenericContractsDeclaration;
3 changes: 0 additions & 3 deletions packages/nextjs/generated/deployedContracts.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { Contract, ContractCodeStatus, ContractName, contracts } from "~~/utils/
*/
export const useDeployedContractInfo = <TContractName extends ContractName>(contractName: TContractName) => {
const isMounted = useIsMounted();
const deployedContract = contracts?.[scaffoldConfig.targetNetwork.id]?.[0]?.contracts?.[
const deployedContract = contracts?.[scaffoldConfig.targetNetwork.id]?.[
contractName as ContractName
] as Contract<TContractName>;
const [status, setStatus] = useState<ContractCodeStatus>(ContractCodeStatus.LOADING);
Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"postcss": "^8.4.16",
"prettier": "^2.8.4",
"tailwindcss": "^3.3.3",
"type-fest": "^4.6.0",
"typescript": "^5.1.6",
"vercel": "^28.15.1"
}
Expand Down
4 changes: 2 additions & 2 deletions packages/nextjs/pages/blockexplorer/address/[address].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
TransactionsTable,
} from "~~/components/blockexplorer/";
import { Address, Balance } from "~~/components/scaffold-eth";
import deployedContracts from "~~/generated/deployedContracts";
import deployedContracts from "~~/contracts/deployedContracts";
import { useFetchBlocks } from "~~/hooks/scaffold-eth";
import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract";

Expand Down Expand Up @@ -176,7 +176,7 @@ export const getServerSideProps: GetServerSideProps = async context => {
throw new Error(`Directory ${buildInfoDirectory} not found.`);
}

const deployedContractsOnChain = contracts ? contracts[chainId][0].contracts : {};
const deployedContractsOnChain = contracts ? contracts[chainId] : {};
for (const [contractName, contractInfo] of Object.entries(deployedContractsOnChain)) {
if (contractInfo.address.toLowerCase() === address) {
contractPath = `contracts/${contractName}.sol`;
Expand Down
2 changes: 1 addition & 1 deletion packages/nextjs/utils/scaffold-eth/common.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
// To be used in JSON.stringify when a field might be bigint
// https://wagmi.sh/react/faq#bigint-serialization
export const replacer = (key: string, value: unknown) => (typeof value === "bigint" ? value.toString() : value);
export const replacer = (_key: string, value: unknown) => (typeof value === "bigint" ? value.toString() : value);
46 changes: 24 additions & 22 deletions packages/nextjs/utils/scaffold-eth/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
ExtractAbiFunction,
} from "abitype";
import type { ExtractAbiFunctionNames } from "abitype";
import type { Simplify } from "type-fest";
import type { MergeDeepRecord } from "type-fest/source/merge-deep";
import {
Address,
Block,
Expand All @@ -17,30 +19,30 @@ import {
TransactionReceipt,
} from "viem";
import { UseContractEventConfig, UseContractReadConfig, UseContractWriteConfig } from "wagmi";
import contractsData from "~~/generated/deployedContracts";
import deployedContractsData from "~~/contracts/deployedContracts";
import externalContractsData from "~~/contracts/externalContracts";
import scaffoldConfig from "~~/scaffold.config";

/**
* @description Combines members of an intersection into a readable type.
* @example
* Prettify<{ a: string } & { b: string } & { c: number, d: bigint }>
* => { a: string, b: string, c: number, d: bigint }
*/
type Prettify<T> = {
[K in keyof T]: T[K];
} & unknown;
const deepMergeContracts = <D extends Record<PropertyKey, any>, S extends Record<PropertyKey, any>>(
destination: D,
source: S,
) => {
const result: Record<PropertyKey, any> = {};
const allKeys = Array.from(new Set([...Object.keys(source), ...Object.keys(destination)]));
for (const key of allKeys) {
result[key] = { ...destination[key], ...source[key] };
}
return result as MergeDeepRecord<D, S, { arrayMergeMode: "replace" }>;
};
const contractsData = deepMergeContracts(deployedContractsData, externalContractsData);

export type GenericContractsDeclaration = {
[key: number]: readonly {
name: string;
chainId: string;
contracts: {
[key: string]: {
address: Address;
abi: Abi;
};
[chainId: number]: {
[contractName: string]: {
address: Address;
abi: Abi;
};
}[];
};
};

export const contracts = contractsData as GenericContractsDeclaration | null;
Expand All @@ -53,7 +55,7 @@ type IsContractDeclarationMissing<TYes, TNo> = typeof contractsData extends { [k

type ContractsDeclaration = IsContractDeclarationMissing<GenericContractsDeclaration, typeof contractsData>;

type Contracts = ContractsDeclaration[ConfiguredChainId][0]["contracts"];
type Contracts = ContractsDeclaration[ConfiguredChainId];

export type ContractName = keyof Contracts;

Expand Down Expand Up @@ -170,7 +172,7 @@ export type UseScaffoldEventConfig<
} & IsContractDeclarationMissing<
Omit<UseContractEventConfig, "listener"> & {
listener: (
logs: Prettify<
logs: Simplify<
Omit<Log<bigint, number, any>, "args" | "eventName"> & {
args: Record<string, unknown>;
eventName: string;
Expand All @@ -180,7 +182,7 @@ export type UseScaffoldEventConfig<
},
Omit<UseContractEventConfig<ContractAbi<TContractName>, TEventName>, "listener"> & {
listener: (
logs: Prettify<
logs: Simplify<
Omit<Log<bigint, number, false, TEvent, false, [TEvent], TEventName>, "args"> & {
args: AbiParametersToPrimitiveTypes<TEvent["inputs"]> &
GetEventArgs<
Expand Down
2 changes: 1 addition & 1 deletion packages/nextjs/utils/scaffold-eth/contractNames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import scaffoldConfig from "~~/scaffold.config";
import { ContractName, contracts } from "~~/utils/scaffold-eth/contract";

export function getContractNames() {
const contractsData = contracts?.[scaffoldConfig.targetNetwork.id]?.[0]?.contracts;
const contractsData = contracts?.[scaffoldConfig.targetNetwork.id];
return contractsData ? (Object.keys(contractsData) as ContractName[]) : [];
}
6 changes: 3 additions & 3 deletions packages/nextjs/utils/scaffold-eth/decodeTxData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { TransactionWithFunction } from "./block";
import { GenericContractsDeclaration } from "./contract";
import { Abi, decodeFunctionData, getAbiItem } from "viem";
import { hardhat } from "viem/chains";
import contractData from "~~/generated/deployedContracts";
import contractData from "~~/contracts/deployedContracts";

type ContractsInterfaces = Record<string, Abi>;
type TransactionType = TransactionWithFunction | null;

const deployedContracts = contractData as GenericContractsDeclaration | null;
const chainMetaData = deployedContracts?.[hardhat.id]?.[0];
const chainMetaData = deployedContracts?.[hardhat.id];
const interfaces = chainMetaData
? Object.entries(chainMetaData.contracts).reduce((finalInterfacesObj, [contractName, contract]) => {
? Object.entries(chainMetaData).reduce((finalInterfacesObj, [contractName, contract]) => {
finalInterfacesObj[contractName] = contract.abi;
return finalInterfacesObj;
}, {} as ContractsInterfaces)
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,7 @@ __metadata:
react-dom: ^18.2.0
react-hot-toast: ^2.4.0
tailwindcss: ^3.3.3
type-fest: ^4.6.0
typescript: ^5.1.6
use-debounce: ^8.0.4
usehooks-ts: ^2.7.2
Expand Down Expand Up @@ -13367,6 +13368,13 @@ __metadata:
languageName: node
linkType: hard

"type-fest@npm:^4.6.0":
version: 4.6.0
resolution: "type-fest@npm:4.6.0"
checksum: e38f2b4b35e912bf60dbe7d4350653fb76b241a456e849fab85002ba08e938a26a7c44a330dd5620dd48ce57566be7c97e997064dc0d5066d5b6949b8c444430
languageName: node
linkType: hard

"typechain@npm:^8.1.0":
version: 8.1.0
resolution: "typechain@npm:8.1.0"
Expand Down

0 comments on commit 61b1c64

Please sign in to comment.