diff --git a/.changeset/wise-bats-wish.md b/.changeset/wise-bats-wish.md new file mode 100644 index 00000000..a845151c --- /dev/null +++ b/.changeset/wise-bats-wish.md @@ -0,0 +1,2 @@ +--- +--- diff --git a/README.md b/README.md index 7afd8210..e357da65 100644 --- a/README.md +++ b/README.md @@ -351,7 +351,7 @@ console.log(hardhatConfig.etherscan()); ### hardhatConfig.getEnvVariableNames() -Returns an API key required for Etherscan V2 contract verification API and a single `MNEMONIC` variable that can be used to configure all networks. +Returns environment variable names that are expected to be set for Hardhat configuration. ```ts import { hardhatConfig } from '@api3/contracts'; @@ -359,6 +359,7 @@ console.log(hardhatConfig.getEnvVariableNames()); /* [ 'MNEMONIC', + 'KEYCARD_ACCOUNT', 'ETHERSCAN_API_KEY', 'HARDHAT_HTTP_RPC_URL_APECHAIN_ARBITRUM_SEPOLIA_TESTNET', ... diff --git a/deploy/1_deploy.ts b/deploy/1_deploy.ts index 78faf085..871b990c 100644 --- a/deploy/1_deploy.ts +++ b/deploy/1_deploy.ts @@ -105,7 +105,12 @@ module.exports = async () => { api3ReaderProxyV1Metadata ); if ((await ethers.provider.getCode(expectedApi3ReaderProxyV1Address)) === '0x') { - await api3ReaderProxyV1Factory.deployApi3ReaderProxyV1(dapiName, dappId, api3ReaderProxyV1Metadata); + const proxyTransactionResponse = await api3ReaderProxyV1Factory.deployApi3ReaderProxyV1( + dapiName, + dappId, + api3ReaderProxyV1Metadata + ); + await proxyTransactionResponse.wait(1); log(`Deployed example Api3ReaderProxyV1 at ${expectedApi3ReaderProxyV1Address}`); } diff --git a/example.env b/example.env index fa34089b..0ebd2c3a 100644 --- a/example.env +++ b/example.env @@ -1,2 +1,3 @@ MNEMONIC= +KEYCARD_ACCOUNT= ETHERSCAN_API_KEY= diff --git a/hardhat.config.ts b/hardhat.config.ts index fe81b87b..cf60f3e3 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -3,6 +3,7 @@ import * as fs from 'node:fs'; import { glob } from 'glob'; import type { HardhatUserConfig } from 'hardhat/config'; import '@nomicfoundation/hardhat-toolbox'; +import 'keycard-hardhat-provider'; import 'hardhat-deploy'; import 'dotenv/config'; import { task } from 'hardhat/config'; diff --git a/package.json b/package.json index d311eb40..80938fe5 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "hardhat": "^2.26.2", "hardhat-deploy": "1.0.2", "hardhat-gas-reporter": "^2.3.0", + "keycard-hardhat-provider": "^0.1.1", "jest": "^30.0.5", "prettier": "^3.5.3", "prettier-plugin-solidity": "^2.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8a9e04d..139f9f7d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -99,6 +99,9 @@ importers: jest: specifier: ^30.0.5 version: 30.0.5(@types/node@22.17.1)(ts-node@10.9.2(@types/node@22.17.1)(typescript@5.9.2)) + keycard-hardhat-provider: + specifier: ^0.1.1 + version: 0.1.1(@typechain/ethers-v6@0.5.1(ethers@6.15.0)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2))(hardhat@2.26.3(ts-node@10.9.2(@types/node@22.17.1)(typescript@5.9.2))(typescript@5.9.2))(typechain@8.3.2(typescript@5.9.2)) prettier: specifier: ^3.5.3 version: 3.5.3 @@ -2169,8 +2172,8 @@ packages: elliptic@6.5.4: resolution: {integrity: sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==} - elliptic@6.5.7: - resolution: {integrity: sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q==} + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} @@ -3516,6 +3519,16 @@ packages: resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} engines: {node: '>=10.0.0'} + keycard-hardhat-provider@0.1.1: + resolution: {integrity: sha512-k+aKlPNA7UTP7hx97Ul3QkbkF+ywTzyspki3qr/wAAynsr//iu6fNYj41yvrXhos1HzmaeEElazM6CHqd26p9g==} + peerDependencies: + hardhat: ^2.26.0 + + keycard-manager@0.9.5: + resolution: {integrity: sha512-tPL2EJPMepZ4jO8S+L0/VzlnRo+V2lgMWw7ILRvjj7o/knlc8KF6sFPCY/IUgf8zDP5SYd8AR+PXtmlLweMybQ==} + peerDependencies: + ethers: ^6.15.0 + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -7753,7 +7766,7 @@ snapshots: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - elliptic@6.5.7: + elliptic@6.6.1: dependencies: bn.js: 4.12.0 brorand: 1.1.0 @@ -9767,6 +9780,24 @@ snapshots: node-gyp-build: 4.8.0 readable-stream: 3.6.2 + keycard-hardhat-provider@0.1.1(@typechain/ethers-v6@0.5.1(ethers@6.15.0)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2))(hardhat@2.26.3(ts-node@10.9.2(@types/node@22.17.1)(typescript@5.9.2))(typescript@5.9.2))(typechain@8.3.2(typescript@5.9.2)): + dependencies: + '@typechain/hardhat': 9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.15.0)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2))(ethers@6.15.0)(hardhat@2.26.3(ts-node@10.9.2(@types/node@22.17.1)(typescript@5.9.2))(typescript@5.9.2))(typechain@8.3.2(typescript@5.9.2)) + '@types/node': 22.17.1 + ethers: 6.15.0 + hardhat: 2.26.3(ts-node@10.9.2(@types/node@22.17.1)(typescript@5.9.2))(typescript@5.9.2) + keycard-manager: 0.9.5(ethers@6.15.0) + transitivePeerDependencies: + - '@typechain/ethers-v6' + - bufferutil + - typechain + - utf-8-validate + + keycard-manager@0.9.5(ethers@6.15.0): + dependencies: + elliptic: 6.6.1 + ethers: 6.15.0 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -10583,7 +10614,7 @@ snapshots: secp256k1@4.0.4: dependencies: - elliptic: 6.5.7 + elliptic: 6.6.1 node-addon-api: 5.1.0 node-gyp-build: 4.8.0 diff --git a/scripts/check-example-env-file.ts b/scripts/check-example-env-file.ts index c1264c0b..63199cfd 100644 --- a/scripts/check-example-env-file.ts +++ b/scripts/check-example-env-file.ts @@ -1,6 +1,6 @@ import * as fs from 'node:fs'; -const expectedEnvVars = ['MNEMONIC', 'ETHERSCAN_API_KEY']; +const expectedEnvVars = ['MNEMONIC', 'KEYCARD_ACCOUNT', 'ETHERSCAN_API_KEY']; const expectedExampleEnvFileContents = expectedEnvVars.reduce((fileContents: string, envVariableName: string) => { return `${fileContents}${envVariableName}=\n`; }, ''); diff --git a/src/hardhat-config.test.ts b/src/hardhat-config.test.ts index caf6a7d2..1215756e 100644 --- a/src/hardhat-config.test.ts +++ b/src/hardhat-config.test.ts @@ -24,7 +24,7 @@ describe(getEnvVariableNames.name, () => { it('returns an array with expected env variables', () => { const apiKeyEnvName = etherscanApiKeyName(); const networkRpcUrlNames = CHAINS.map((chain) => networkHttpRpcUrlName(chain)); - const expected = ['MNEMONIC', apiKeyEnvName, ...networkRpcUrlNames]; + const expected = ['MNEMONIC', 'KEYCARD_ACCOUNT', apiKeyEnvName, ...networkRpcUrlNames]; expect(getEnvVariableNames()).toStrictEqual(expected); }); }); diff --git a/src/hardhat-config.ts b/src/hardhat-config.ts index d3446725..ca179495 100644 --- a/src/hardhat-config.ts +++ b/src/hardhat-config.ts @@ -12,7 +12,7 @@ export function getEnvVariableNames(): string[] { const networkRpcUrlNames = CHAINS.map((chain) => networkHttpRpcUrlName(chain)); - return ['MNEMONIC', apiKeyEnvName, ...networkRpcUrlNames]; + return ['MNEMONIC', 'KEYCARD_ACCOUNT', apiKeyEnvName, ...networkRpcUrlNames]; } export function etherscanApiKeyName(): string { @@ -77,12 +77,16 @@ export function networks(): HardhatNetworksConfig { throw new Error('Cannot be called outside of a Node.js environment'); } + const credentials = process.env.KEYCARD_ACCOUNT + ? { keycardAccount: process.env.KEYCARD_ACCOUNT } + : { accounts: { mnemonic: process.env.MNEMONIC ?? '' } }; + return CHAINS.reduce((networks, chain) => { const defaultProvider = chain.providers.find((p) => p.alias === 'default'); const overrides = chain.hardhatConfigOverrides?.networks ?? {}; networks[chain.alias] = { - accounts: { mnemonic: process.env.MNEMONIC ?? '' }, + ...credentials, chainId: Number(chain.id), url: process.env[networkHttpRpcUrlName(chain)] ?? defaultProvider!.rpcUrl!, ...overrides, diff --git a/src/types.ts b/src/types.ts index d3b03eaf..7314fe9a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -84,7 +84,8 @@ export type ChainProvider = z.infer; export interface HardhatNetworksConfig { [key: string]: { - accounts: { mnemonic: string }; + accounts?: { mnemonic: string }; + keycardAccount?: string; chainId: number; url: string; };