mirror of
https://github.com/datahaven-xyz/datahaven
synced 2026-05-24 01:38:32 +00:00
test: 🧙 Generate Type Bindings for Contracts (#58)
## Summary
This PR adds statically typed bindings for contracts. This allows you to
write E2E tests with full completions in TS.
## Additions
- `ts-build.yml` New CI, this will make sure that if there's changes
made to the contracts that the contract-bindings are up to date.
- `package.json` script changes
- `start:e2e:ci` - Designed to be run with all options specified since
CIs are famously bad with iteractive CLI prompts
- `test:e2e` - added timeout
- `generate:wagmi` - This generates the smart contract bindings for our
tests
- New Function Helpers:
- `generateRandomAccount()` Returns a viem account type object for a
random account. Useful for tests where you want idempotency on a long
lived network since the state is probabilistically fresh
- `getContractInstance()` Returns a viem contract instance that allows
you to read/write to the deployed contract. You should get full type
inference here for the methods available and parameters required.
### Example
```ts
it("avs() can be read from contract instance", async () => {
const value = await instance.read.avs();
expect(isAddress(value), "AVS getter should return an address").toBeTrue();
});
```
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Facundo Farall <37149322+ffarall@users.noreply.github.com>
This commit is contained in:
parent
ca9eb0f813
commit
fa4d3b8391
22 changed files with 17705 additions and 71 deletions
2
.github/workflows/e2e.yml
vendored
2
.github/workflows/e2e.yml
vendored
|
|
@ -58,5 +58,5 @@ jobs:
|
|||
${{ runner.os }}-foundry-
|
||||
|
||||
- run: bun install
|
||||
- run: bun start:e2e:minimal
|
||||
- run: bun start:e2e:ci
|
||||
- run: bun test:e2e
|
||||
|
|
|
|||
50
.github/workflows/ts-build.yml
vendored
Normal file
50
.github/workflows/ts-build.yml
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
name: TS Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
generate-wagmi:
|
||||
runs-on: ubuntu-latest
|
||||
name: Check Bindings are current
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Install Foundry
|
||||
uses: foundry-rs/foundry-toolchain@v1
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.bun/install/cache
|
||||
key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lockb') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-bun-
|
||||
- name: Run Forge build
|
||||
run: |
|
||||
forge build
|
||||
working-directory: contracts
|
||||
- name: Install dependencies
|
||||
working-directory: test
|
||||
run: bun install
|
||||
- name: Generate Wagmi Bindings
|
||||
working-directory: test
|
||||
run: bun generate:wagmi
|
||||
- run: bun fmt:fix
|
||||
working-directory: test
|
||||
- name: Check no local changes
|
||||
run: |
|
||||
changes=$(git status --porcelain .)
|
||||
if [ -n "$changes" ]; then
|
||||
echo "generate:wagmi produced changes:"
|
||||
echo "$changes"
|
||||
echo "Please run 'bun generate:wagmi' locally and commit the changes."
|
||||
exit 1
|
||||
else
|
||||
echo "No changes"
|
||||
exit 0
|
||||
fi
|
||||
|
|
@ -84,6 +84,16 @@ bun test:e2e
|
|||
> [!NOTE]
|
||||
> You can increase the logging level by setting `LOG_LEVEL=debug` before running the tests.
|
||||
|
||||
### Wagmi Bindings Generation
|
||||
|
||||
To ensure contract bindings are up-to-date, run the following command after modifying smart contracts or updating ABIs:
|
||||
|
||||
```bash
|
||||
bun generate:wagmi
|
||||
```
|
||||
|
||||
This command generates TypeScript bindings for interacting with the deployed smart contracts using Wagmi.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### E2E Network Launch doesn't work
|
||||
|
|
|
|||
715
test/bun.lock
715
test/bun.lock
File diff suppressed because it is too large
Load diff
BIN
test/bun.lockb
BIN
test/bun.lockb
Binary file not shown.
5
test/bunfig.toml
Normal file
5
test/bunfig.toml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# Keeping this file around to remind us
|
||||
# to check patch notes to see if they add things here we can use
|
||||
|
||||
[test]
|
||||
# Sadly there isnt any global timeout options here yet
|
||||
|
|
@ -4,7 +4,7 @@ import { logger } from "utils";
|
|||
|
||||
export class LaunchedNetwork {
|
||||
protected runId: string;
|
||||
protected processes: Bun.Subprocess[];
|
||||
protected processes: Bun.Subprocess<"inherit" | "pipe" | "ignore", number, number>[];
|
||||
protected fileDescriptors: number[];
|
||||
protected DHNodes: { id: string; port: number }[];
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ export class LaunchedNetwork {
|
|||
this.fileDescriptors.push(fd);
|
||||
}
|
||||
|
||||
addProcess(process: Bun.Subprocess) {
|
||||
addProcess(process: Bun.Subprocess<"inherit" | "pipe" | "ignore", number, number>) {
|
||||
this.processes.push(process);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import {
|
|||
SUBSTRATE_FUNDED_ACCOUNTS,
|
||||
getPortFromKurtosis,
|
||||
logger,
|
||||
parseDeploymentsFile,
|
||||
parseRelayConfig,
|
||||
printHeader
|
||||
} from "utils";
|
||||
|
|
@ -27,13 +28,8 @@ export const performRelayerOperations = async (
|
|||
) => {
|
||||
printHeader("Starting Snowbridge Relayers");
|
||||
logger.info("Preparing to generate configs");
|
||||
const anvilDeploymentsPath = "../contracts/deployments/anvil.json";
|
||||
const anvilDeploymentsFile = Bun.file(anvilDeploymentsPath);
|
||||
if (!(await anvilDeploymentsFile.exists())) {
|
||||
logger.error(`File ${anvilDeploymentsPath} does not exist`);
|
||||
throw new Error("Error reading anvil deployments file");
|
||||
}
|
||||
const anvilDeployments = await anvilDeploymentsFile.json();
|
||||
|
||||
const anvilDeployments = await parseDeploymentsFile();
|
||||
const beefyClientAddress = anvilDeployments.BeefyClient;
|
||||
const gatewayAddress = anvilDeployments.Gateway;
|
||||
invariant(beefyClientAddress, "❌ BeefyClient address not found in anvil.json");
|
||||
|
|
|
|||
16658
test/contract-bindings/generated.ts
Normal file
16658
test/contract-bindings/generated.ts
Normal file
File diff suppressed because it is too large
Load diff
1
test/contract-bindings/index.ts
Normal file
1
test/contract-bindings/index.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "./generated";
|
||||
|
|
@ -8,16 +8,18 @@
|
|||
"fmt": "biome check .",
|
||||
"fmt:fix": "biome check --write .",
|
||||
"build:docker:relayer": "bun -e \"import build from './scripts/snowbridge-relayer.ts'; build()\"",
|
||||
"generate:wagmi": "wagmi generate",
|
||||
"generate:snowbridge-cfgs": "bun -e \"import {generateSnowbridgeConfigs} from './scripts/gen-snowbridge-cfgs.ts'; await generateSnowbridgeConfigs()\"",
|
||||
"start:e2e:verified": "bun cli --verified --blockscout --deploy-contracts",
|
||||
"start:e2e:minimal": "bun cli",
|
||||
"start:e2e:ci": "bun cli -d --setup-validators --update-validator-set --fund-validators",
|
||||
"start:e2e:minrelayer": "bun cli --relayer -d --no-setup-validators --no-update-validator-set --no-fund-validators --datahaven",
|
||||
"stop:e2e": "pkill datahaven ; kurtosis enclave stop datahaven-ethereum && kurtosis clean && kurtosis engine stop && docker container prune -f",
|
||||
"stop:e2e:verified": "bun stop:e2e",
|
||||
"stop:e2e:minimal": "bun stop:e2e",
|
||||
"stop:e2e:quick": "kurtosis enclave stop datahaven-ethereum",
|
||||
"stop:kurtosis-engine": "kurtosis engine stop && docker container prune -f",
|
||||
"test:e2e": "bun test suites/e2e",
|
||||
"test:e2e": "bun test suites/e2e --timeout 30000",
|
||||
"typecheck": "tsc --noEmit"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -33,6 +35,8 @@
|
|||
"@inquirer/prompts": "^7.5.0",
|
||||
"@types/dockerode": "^3.3.38",
|
||||
"@types/node": "^22.14.1",
|
||||
"@wagmi/cli": "^2.3.0",
|
||||
"@wagmi/core": "^2.17.0",
|
||||
"chalk": "^5.4.1",
|
||||
"commander": "^13.1.0",
|
||||
"dockerode": "^4.0.6",
|
||||
|
|
@ -43,10 +47,17 @@
|
|||
"pino-pretty": "^13.0.0",
|
||||
"tiny-invariant": "^1.3.3",
|
||||
"viem": "^2.28.0",
|
||||
"wagmi": "^2.15.0",
|
||||
"zod": "^3.24.3"
|
||||
},
|
||||
"trustedDependencies": [
|
||||
"@biomejs/biome",
|
||||
"protobufjs"
|
||||
"bufferutil",
|
||||
"cpu-features",
|
||||
"esbuild",
|
||||
"keccak",
|
||||
"protobufjs",
|
||||
"ssh2",
|
||||
"utf-8-validate"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { logger } from "utils";
|
||||
import { generateRandomAccount, logger } from "utils";
|
||||
import { http, createWalletClient, defineChain, parseEther, publicActions } from "viem";
|
||||
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ export default async function main(privateKey: string, networkRpcUrl: string) {
|
|||
transport: http(networkRpcUrl)
|
||||
}).extend(publicActions);
|
||||
|
||||
const randAccount = privateKeyToAccount(generatePrivateKey());
|
||||
const randAccount = generateRandomAccount();
|
||||
const addresses = [
|
||||
// "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
|
||||
// "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc",
|
||||
|
|
|
|||
|
|
@ -3,13 +3,11 @@ import {
|
|||
ANVIL_FUNDED_ACCOUNTS,
|
||||
type ViemClientInterface,
|
||||
createDefaultClient,
|
||||
fetchContractAbiByAddress,
|
||||
fetchContractAddressByName,
|
||||
generateRandomAccount,
|
||||
logger
|
||||
} from "utils";
|
||||
import { isAddress, parseAbi, parseEther } from "viem";
|
||||
import { parseEther } from "viem";
|
||||
|
||||
// Tests are disabled because we lack ability to run blockscout reliably
|
||||
describe("E2E: Read-only", () => {
|
||||
let api: ViemClientInterface;
|
||||
|
||||
|
|
@ -34,44 +32,27 @@ describe("E2E: Read-only", () => {
|
|||
expect(balance).toBeGreaterThan(parseEther("1"));
|
||||
});
|
||||
|
||||
it.skip("Snowbridge contract is deployed and verified", async () => {
|
||||
const contractAddress = await fetchContractAddressByName("BeefyClient");
|
||||
logger.info(`Contract BeefyClient deployed to ${contractAddress}`);
|
||||
expect(isAddress(contractAddress)).toBeTrue();
|
||||
|
||||
const contractCode = await api.getCode({ address: contractAddress });
|
||||
expect(contractCode).toBeTruthy();
|
||||
|
||||
describe("BeefyClient contract", async () => {
|
||||
it("latestBeefyBlock()) can be read", async () => {
|
||||
const value = await api.readContract({
|
||||
abi: parseAbi(["function latestBeefyBlock() view returns (uint64)"]),
|
||||
address: contractAddress,
|
||||
functionName: "latestBeefyBlock"
|
||||
});
|
||||
expect(value, "Expected contract read to give positive blocknum").toBeGreaterThan(0n);
|
||||
});
|
||||
|
||||
it("blockscout can fetch abi", async () => {
|
||||
const address = await fetchContractAddressByName("BeefyClient");
|
||||
const abi = await fetchContractAbiByAddress(address);
|
||||
|
||||
const resp = await api.readContract({
|
||||
address,
|
||||
abi,
|
||||
functionName: "randaoCommitExpiration"
|
||||
});
|
||||
expect(resp, "Expected contract read").toBeGreaterThan(0n);
|
||||
});
|
||||
it("can send ETH txs", async () => {
|
||||
const amount = parseEther("1");
|
||||
const randomAddress = generateRandomAccount();
|
||||
const balanceBefore = await api.getBalance({
|
||||
address: randomAddress.address
|
||||
});
|
||||
});
|
||||
logger.debug(`Balance of ${randomAddress.address} before: ${balanceBefore}`);
|
||||
|
||||
it.skip("AVS contract is deployed and verified", async () => {
|
||||
const contractAddress = await fetchContractAddressByName("DataHavenServiceManager");
|
||||
logger.info(`Contract DataHavenServiceManager deployed to ${contractAddress}`);
|
||||
expect(isAddress(contractAddress)).toBeTrue();
|
||||
const hash = await api.sendTransaction({
|
||||
to: randomAddress.address,
|
||||
value: amount
|
||||
});
|
||||
|
||||
const contractCode = await api.getCode({ address: contractAddress });
|
||||
expect(contractCode).toBeTruthy();
|
||||
const receipt = await api.waitForTransactionReceipt({ hash });
|
||||
logger.debug(`Transaction receipt: ${receipt}`);
|
||||
|
||||
const balanceAfter = await api.getBalance({
|
||||
address: randomAddress.address
|
||||
});
|
||||
|
||||
logger.debug(`Balance of ${randomAddress.address} after: ${balanceAfter}`);
|
||||
expect(balanceAfter - balanceBefore).toBe(amount);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
46
test/suites/e2e/beefy-client.test.ts
Normal file
46
test/suites/e2e/beefy-client.test.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { beforeAll, describe, expect, it } from "bun:test";
|
||||
import { beefyClientAbi } from "contract-bindings";
|
||||
import {
|
||||
type AnvilDeployments,
|
||||
type ContractInstance,
|
||||
type ViemClientInterface,
|
||||
createDefaultClient,
|
||||
getContractInstance,
|
||||
logger,
|
||||
parseDeploymentsFile
|
||||
} from "utils";
|
||||
import { isAddress } from "viem";
|
||||
|
||||
describe("BeefyClient contract", async () => {
|
||||
let api: ViemClientInterface;
|
||||
let deployments: AnvilDeployments;
|
||||
let instance: ContractInstance<"BeefyClient">;
|
||||
|
||||
beforeAll(async () => {
|
||||
api = await createDefaultClient();
|
||||
deployments = await parseDeploymentsFile();
|
||||
instance = await getContractInstance("BeefyClient");
|
||||
});
|
||||
|
||||
it("BeefyClient contract is deployed", async () => {
|
||||
const contractAddress = deployments.BeefyClient;
|
||||
expect(isAddress(contractAddress)).toBeTrue();
|
||||
});
|
||||
|
||||
it("latestBeefyBlock() can be read", async () => {
|
||||
const value = await api.readContract({
|
||||
abi: beefyClientAbi,
|
||||
functionName: "latestBeefyBlock",
|
||||
address: deployments.BeefyClient
|
||||
});
|
||||
logger.debug(`latestBeefyBlock() value: ${value}`);
|
||||
expect(value, "Expected contract read to give positive blocknum").toBeGreaterThan(0n);
|
||||
});
|
||||
|
||||
it("latestBeefyBlock() can be read from contract instance", async () => {
|
||||
const value = await instance.read.latestBeefyBlock();
|
||||
|
||||
logger.debug(`latestBeefyBlock() value: ${value}`);
|
||||
expect(value, "Expected contract read to give positive blocknum").toBeGreaterThan(0n);
|
||||
});
|
||||
});
|
||||
27
test/suites/e2e/service-manager.test.ts
Normal file
27
test/suites/e2e/service-manager.test.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { beforeAll, describe, expect, it } from "bun:test";
|
||||
import { beefyClientAbi } from "contract-bindings";
|
||||
import {
|
||||
type AnvilDeployments,
|
||||
type ContractInstance,
|
||||
type ViemClientInterface,
|
||||
createDefaultClient,
|
||||
getContractInstance,
|
||||
logger,
|
||||
parseDeploymentsFile
|
||||
} from "utils";
|
||||
import { isAddress } from "viem";
|
||||
|
||||
describe("BeefyClient contract", async () => {
|
||||
let instance: ContractInstance<"ServiceManager">;
|
||||
|
||||
beforeAll(async () => {
|
||||
instance = await getContractInstance("ServiceManager");
|
||||
});
|
||||
|
||||
it("avs() can be read from contract instance", async () => {
|
||||
const value = await instance.read.avs();
|
||||
|
||||
logger.debug(`avs() value: ${value}`);
|
||||
expect(isAddress(value), "AVS getter should return an address").toBeTrue();
|
||||
});
|
||||
});
|
||||
|
|
@ -31,6 +31,6 @@
|
|||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
},
|
||||
"include": ["utils/*.ts", "scripts/*.ts", "suites/**/*.ts", "cli/**/*.ts"],
|
||||
"include": ["utils/*.ts", "scripts/*.ts", "suites/**/*.ts", "cli/**/*.ts", "wagmi.config.ts", "contract-bindings/*.ts"],
|
||||
"exclude": ["node_modules/"]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ export const ANVIL_FUNDED_ACCOUNTS = {
|
|||
derivationPath: "m/44'/60'/0'/0/"
|
||||
} as const;
|
||||
|
||||
export const CHAIN_ID = 31337;
|
||||
export const CHAIN_ID = 3151908;
|
||||
|
||||
export const CONTAINER_NAMES = {
|
||||
EL1: "el-1-reth-lighthouse",
|
||||
|
|
|
|||
115
test/utils/contracts.ts
Normal file
115
test/utils/contracts.ts
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
import * as generated from "contract-bindings";
|
||||
import { type Abi, erc20Abi, getContract, isAddress } from "viem";
|
||||
import { z } from "zod";
|
||||
import { logger } from "./logger";
|
||||
import { type ViemClientInterface, createDefaultClient } from "./viem";
|
||||
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
const ethAddressRegex = /^0x[a-fA-F0-9]{40}$/;
|
||||
const ethAddress = z.string().regex(ethAddressRegex, "Invalid Ethereum address");
|
||||
const ethAddressCustom = z.custom<`0x${string}`>(
|
||||
(val) => typeof val === "string" && ethAddressRegex.test(val),
|
||||
{ message: "Invalid Ethereum address" }
|
||||
);
|
||||
|
||||
const DeployedStrategySchema = z.object({
|
||||
address: ethAddress,
|
||||
underlyingToken: ethAddress,
|
||||
tokenCreator: ethAddress
|
||||
});
|
||||
|
||||
const AnvilDeploymentsSchema = z.object({
|
||||
network: z.string(),
|
||||
BeefyClient: ethAddressCustom,
|
||||
AgentExecutor: ethAddressCustom,
|
||||
Gateway: ethAddressCustom,
|
||||
ServiceManager: ethAddressCustom,
|
||||
VetoableSlasher: ethAddressCustom,
|
||||
RewardsRegistry: ethAddressCustom,
|
||||
Agent: ethAddressCustom,
|
||||
DelegationManager: ethAddressCustom,
|
||||
StrategyManager: ethAddressCustom,
|
||||
AVSDirectory: ethAddressCustom,
|
||||
EigenPodManager: ethAddressCustom,
|
||||
EigenPodBeacon: ethAddressCustom,
|
||||
RewardsCoordinator: ethAddressCustom,
|
||||
AllocationManager: ethAddressCustom,
|
||||
PermissionController: ethAddressCustom,
|
||||
ETHPOSDeposit: ethAddressCustom,
|
||||
BaseStrategyImplementation: ethAddressCustom,
|
||||
DeployedStrategies: z.array(DeployedStrategySchema)
|
||||
});
|
||||
|
||||
export type AnvilDeployments = z.infer<typeof AnvilDeploymentsSchema>;
|
||||
|
||||
export const parseDeploymentsFile = async (): Promise<AnvilDeployments> => {
|
||||
const anvilDeploymentsPath = "../contracts/deployments/anvil.json";
|
||||
const anvilDeploymentsFile = Bun.file(anvilDeploymentsPath);
|
||||
if (!(await anvilDeploymentsFile.exists())) {
|
||||
logger.error(`File ${anvilDeploymentsPath} does not exist`);
|
||||
throw new Error("Error reading anvil deployments file");
|
||||
}
|
||||
const anvilDeploymentsJson = await anvilDeploymentsFile.json();
|
||||
try {
|
||||
const parsedDeployments = AnvilDeploymentsSchema.parse(anvilDeploymentsJson);
|
||||
logger.debug("Successfully parsed anvil deployments file.");
|
||||
return parsedDeployments;
|
||||
} catch (error) {
|
||||
logger.error("Failed to parse anvil deployments file:", error);
|
||||
throw new Error("Invalid anvil deployments file format");
|
||||
}
|
||||
};
|
||||
|
||||
// Add to this if we add any new contracts
|
||||
const abiMap = {
|
||||
BeefyClient: generated.beefyClientAbi,
|
||||
AgentExecutor: generated.agentExecutorAbi,
|
||||
Gateway: generated.gatewayAbi,
|
||||
ServiceManager: generated.dataHavenServiceManagerAbi,
|
||||
VetoableSlasher: generated.vetoableSlasherAbi,
|
||||
RewardsRegistry: generated.rewardsRegistryAbi,
|
||||
Agent: generated.agentAbi,
|
||||
DelegationManager: generated.delegationManagerAbi,
|
||||
StrategyManager: generated.strategyManagerAbi,
|
||||
AVSDirectory: generated.avsDirectoryAbi,
|
||||
EigenPodManager: generated.eigenPodManagerAbi,
|
||||
EigenPodBeacon: generated.eigenPodAbi,
|
||||
RewardsCoordinator: generated.rewardsCoordinatorAbi,
|
||||
AllocationManager: generated.allocationManagerAbi,
|
||||
PermissionController: generated.permissionControllerAbi,
|
||||
ETHPOSDeposit: generated.iethposDepositAbi,
|
||||
BaseStrategyImplementation: generated.strategyBaseTvlLimitsAbi,
|
||||
DeployedStrategies: erc20Abi
|
||||
} as const satisfies Record<keyof Omit<AnvilDeployments, "network">, Abi>;
|
||||
|
||||
type ContractName = keyof typeof abiMap;
|
||||
type AbiFor<C extends ContractName> = (typeof abiMap)[C];
|
||||
export type ContractInstance<C extends ContractName> = Awaited<
|
||||
ReturnType<typeof getContractInstance<C>>
|
||||
>;
|
||||
|
||||
// TODO: make this work with DeployedStrategies
|
||||
export const getContractInstance = async <C extends ContractName>(
|
||||
contract: C,
|
||||
viemClient?: ViemClientInterface
|
||||
) => {
|
||||
const deployments = await parseDeploymentsFile();
|
||||
const contractAddress = deployments[contract];
|
||||
logger.debug(`Contract ${contract} deployed to ${contractAddress}`);
|
||||
|
||||
const client = viemClient ?? (await createDefaultClient());
|
||||
invariant(
|
||||
typeof contractAddress === "string" && isAddress(contractAddress),
|
||||
`Contract address for ${contract} is not a valid address`
|
||||
);
|
||||
|
||||
const abi: AbiFor<C> = abiMap[contract];
|
||||
invariant(abi, `ABI for contract ${contract} not found`);
|
||||
|
||||
return getContract({
|
||||
address: contractAddress,
|
||||
abi,
|
||||
client
|
||||
});
|
||||
};
|
||||
|
|
@ -7,3 +7,4 @@ export * from "./rpc";
|
|||
export * from "./viem";
|
||||
export * from "./kurtosis";
|
||||
export * from "./parser";
|
||||
export * from "./contracts";
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export const timeoutConfirm = createPrompt<boolean, TimeoutConfirmConfig>((cfg,
|
|||
clearInterval(id);
|
||||
done(cfg.default ?? true);
|
||||
}
|
||||
}, 10);
|
||||
}, 200);
|
||||
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
|
|
@ -71,7 +71,10 @@ ${defaultBadge} ${input}`;
|
|||
)
|
||||
);
|
||||
|
||||
return `${border}\n${hint}\n${main}\n${border}`;
|
||||
return `${border}
|
||||
${hint}
|
||||
${main}
|
||||
${border}`;
|
||||
});
|
||||
|
||||
export const confirmWithTimeout = (
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
defineChain,
|
||||
publicActions
|
||||
} from "viem";
|
||||
import { privateKeyToAccount } from "viem/accounts";
|
||||
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts";
|
||||
|
||||
export const createChainConfig = async () =>
|
||||
defineChain({
|
||||
|
|
@ -45,4 +45,8 @@ export const createDefaultClient = async () =>
|
|||
transport: http()
|
||||
}).extend(publicActions);
|
||||
|
||||
export interface ViemClientInterface extends WalletClient, PublicActions {}
|
||||
// export interface ViemClientInterface extends WalletClient, PublicActions {}
|
||||
|
||||
export type ViemClientInterface = Awaited<ReturnType<typeof createDefaultClient>>;
|
||||
|
||||
export const generateRandomAccount = () => privateKeyToAccount(generatePrivateKey());
|
||||
|
|
|
|||
33
test/wagmi.config.ts
Normal file
33
test/wagmi.config.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
import { defineConfig } from "@wagmi/cli";
|
||||
import { actions, foundry } from "@wagmi/cli/plugins";
|
||||
|
||||
export default defineConfig({
|
||||
out: "contract-bindings/generated.ts",
|
||||
plugins: [
|
||||
actions(), // TODO: Investigate why the actions() plugin is not functioning as expected. Refer to the @wagmi/cli documentation for potential solutions.
|
||||
foundry({
|
||||
project: "../contracts",
|
||||
include: [
|
||||
"BeefyClient.sol/**",
|
||||
"AgentExecutor.sol/**",
|
||||
"Gateway.sol/**",
|
||||
"TransparentUpgradeableProxy.sol/**",
|
||||
"VetoableSlasher.sol/**",
|
||||
"RewardsRegistry.sol/**",
|
||||
"Agent.sol/**",
|
||||
"StrategyManager.sol/**",
|
||||
"AVSDirectory.sol/**",
|
||||
"DataHavenServiceManager.sol/**",
|
||||
"EigenPodManager.sol/**",
|
||||
"EigenPod.sol/**",
|
||||
"UpgradeableBeacon.sol/**",
|
||||
"RewardsCoordinator.sol/**",
|
||||
"AllocationManager.sol/**",
|
||||
"DelegationManager.sol/**",
|
||||
"PermissionController.sol/**",
|
||||
"IETHPOSDeposit.sol/**",
|
||||
"StrategyBaseTVLLimits.sol/**"
|
||||
]
|
||||
})
|
||||
]
|
||||
});
|
||||
Loading…
Reference in a new issue