Skip to content

Commit 402ccdc

Browse files
authored
Merge pull request #4 from api3dao/proxy-deploy-scripts
Adds hardhat-deploy scripts for proxy contracts
2 parents ddbc5a1 + 1f0d70f commit 402ccdc

16 files changed

+745
-208
lines changed

.eslintignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ dist
1717
gas_report
1818

1919
contracts/vendor
20+
21+
# Hardhat deploy artifacts
22+
/deployments

.eslintrc.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
module.exports = {
22
extends: ['plugin:@api3/eslint-plugin-commons/universal', 'plugin:@api3/eslint-plugin-commons/jest'],
33
parserOptions: {
4-
project: ['./tsconfig.json'],
4+
project: './tsconfig.json',
5+
tsconfigRootDir: __dirname,
56
},
67
rules: {
78
camelcase: 'off',
@@ -26,4 +27,5 @@ module.exports = {
2627
'@typescript-eslint/no-unsafe-call': 'off',
2728
'@typescript-eslint/require-await': 'off',
2829
},
30+
ignorePatterns: ['typechain-types/*'],
2931
};

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@ dist
1515
/coverage.json
1616

1717
gas_report
18+
19+
# Hardhat deploy artifacts
20+
/deployments

.prettierignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,6 @@ dist
1717
gas_report
1818

1919
contracts/vendor
20+
21+
# Hardhat deploy artifacts
22+
/deployments
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import type { HardhatRuntimeEnvironment } from 'hardhat/types';
2+
3+
import { getDeploymentName } from '../src';
4+
5+
export const CONTRACT_NAME = 'InverseApi3ReaderProxyV1';
6+
7+
module.exports = async (hre: HardhatRuntimeEnvironment) => {
8+
const { getUnnamedAccounts, deployments, ethers, network, run } = hre;
9+
const { deploy, log } = deployments;
10+
11+
const [deployerAddress] = await getUnnamedAccounts();
12+
if (!deployerAddress) {
13+
throw new Error('No deployer address found.');
14+
}
15+
log(`Deployer address: ${deployerAddress}`);
16+
17+
const proxyAddress = process.env.PROXY;
18+
if (!proxyAddress) {
19+
throw new Error('PROXY environment variable not set. Please provide the address of the proxy contract.');
20+
}
21+
if (!ethers.isAddress(proxyAddress)) {
22+
throw new Error(`Invalid address provided for PROXY: ${proxyAddress}`);
23+
}
24+
log(`Proxy address: ${proxyAddress}`);
25+
26+
const isLocalNetwork = network.name === 'hardhat' || network.name === 'localhost';
27+
28+
const confirmations = isLocalNetwork ? 1 : 5;
29+
log(`Deployment confirmations: ${confirmations}`);
30+
31+
const constructorArgs = [proxyAddress];
32+
const constructorArgTypes = ['address'];
33+
34+
const deploymentName = getDeploymentName(CONTRACT_NAME, constructorArgTypes, constructorArgs);
35+
log(`Generated deterministic deployment name for this instance: ${deploymentName}`);
36+
37+
const deployment = await deploy(deploymentName, {
38+
contract: CONTRACT_NAME,
39+
from: deployerAddress,
40+
args: constructorArgs,
41+
log: true,
42+
waitConfirmations: confirmations,
43+
});
44+
45+
if (isLocalNetwork) {
46+
log('Skipping verification on local network.');
47+
return;
48+
}
49+
50+
log(
51+
`Attempting verification of ${deploymentName} (contract type ${CONTRACT_NAME}) at ${deployment.address} (already waited for confirmations)...`
52+
);
53+
await run('verify:verify', {
54+
address: deployment.address,
55+
constructorArguments: deployment.args,
56+
});
57+
};
58+
module.exports.tags = [CONTRACT_NAME];
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type { HardhatRuntimeEnvironment } from 'hardhat/types';
2+
import type { DeploymentsExtension } from 'hardhat-deploy/types';
3+
4+
import { getDeploymentName } from '../src';
5+
6+
export const CONTRACT_NAME = 'NormalizedApi3ReaderProxyV1';
7+
8+
const deployTestFeed = async (deployments: DeploymentsExtension, deployerAddress: string) => {
9+
const { address: scaledApi3FeedProxyV1Address } = await deployments.get('ScaledApi3FeedProxyV1').catch(async () => {
10+
return deployments.deploy('ScaledApi3FeedProxyV1', {
11+
from: deployerAddress,
12+
args: ['0x5b0cf2b36a65a6BB085D501B971e4c102B9Cd473', 8],
13+
log: true,
14+
});
15+
});
16+
return scaledApi3FeedProxyV1Address;
17+
};
18+
19+
module.exports = async (hre: HardhatRuntimeEnvironment) => {
20+
const { getUnnamedAccounts, deployments, network, ethers, run } = hre;
21+
const { deploy, log } = deployments;
22+
23+
const [deployerAddress] = await getUnnamedAccounts();
24+
if (!deployerAddress) {
25+
throw new Error('No deployer address found.');
26+
}
27+
log(`Deployer address: ${deployerAddress}`);
28+
29+
const feedAddress =
30+
network.name === 'hardhat' ? await deployTestFeed(deployments, deployerAddress) : process.env.FEED;
31+
if (!feedAddress) {
32+
throw new Error(
33+
'FEED environment variable not set. Please provide the address of the AggregatorV2V3Interface contract.'
34+
);
35+
}
36+
if (!ethers.isAddress(feedAddress)) {
37+
throw new Error(`Invalid address provided for FEED: ${feedAddress}`);
38+
}
39+
log(`Feed address: ${feedAddress}`);
40+
41+
const isLocalNetwork = network.name === 'hardhat' || network.name === 'localhost';
42+
43+
const confirmations = isLocalNetwork ? 1 : 5;
44+
log(`Deployment confirmations: ${confirmations}`);
45+
46+
const constructorArgs = [feedAddress];
47+
const constructorArgTypes = ['address'];
48+
49+
const deploymentName = getDeploymentName(CONTRACT_NAME, constructorArgTypes, constructorArgs);
50+
log(`Generated deterministic deployment name for this instance: ${deploymentName}`);
51+
52+
const deployment = await deploy(deploymentName, {
53+
contract: CONTRACT_NAME,
54+
from: deployerAddress,
55+
args: constructorArgs,
56+
log: true,
57+
waitConfirmations: confirmations,
58+
});
59+
60+
if (isLocalNetwork) {
61+
log('Skipping verification on local network.');
62+
return;
63+
}
64+
65+
log(
66+
`Attempting verification of ${deploymentName} (contract type ${CONTRACT_NAME}) at ${deployment.address} (already waited for confirmations)...`
67+
);
68+
await run('verify:verify', {
69+
address: deployment.address,
70+
constructorArguments: deployment.args,
71+
});
72+
};
73+
module.exports.tags = [CONTRACT_NAME];
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import type { HardhatRuntimeEnvironment } from 'hardhat/types';
2+
3+
import { getDeploymentName } from '../src';
4+
5+
export const CONTRACT_NAME = 'ProductApi3ReaderProxyV1';
6+
7+
module.exports = async (hre: HardhatRuntimeEnvironment) => {
8+
const { getUnnamedAccounts, deployments, ethers, network, run } = hre;
9+
const { deploy, log } = deployments;
10+
11+
const [deployerAddress] = await getUnnamedAccounts();
12+
if (!deployerAddress) {
13+
throw new Error('No deployer address found.');
14+
}
15+
log(`Deployer address: ${deployerAddress}`);
16+
17+
const proxy1Address = process.env.PROXY1;
18+
if (!proxy1Address) {
19+
throw new Error('PROXY1 environment variable not set. Please provide the address of the first proxy contract.');
20+
}
21+
if (!ethers.isAddress(proxy1Address)) {
22+
throw new Error(`Invalid address provided for PROXY1: ${proxy1Address}`);
23+
}
24+
log(`Proxy 1 address: ${proxy1Address}`);
25+
26+
const proxy2Address = process.env.PROXY2;
27+
if (!proxy2Address) {
28+
throw new Error('PROXY2 environment variable not set. Please provide the address of the second proxy contract.');
29+
}
30+
if (!ethers.isAddress(proxy2Address)) {
31+
throw new Error(`Invalid address provided for PROXY2: ${proxy2Address}`);
32+
}
33+
log(`Proxy 2 address: ${proxy2Address}`);
34+
35+
const isLocalNetwork = network.name === 'hardhat' || network.name === 'localhost';
36+
37+
const confirmations = isLocalNetwork ? 1 : 5;
38+
log(`Deployment confirmations: ${confirmations}`);
39+
40+
const constructorArgs = [proxy1Address, proxy2Address];
41+
const constructorArgTypes = ['address', 'address'];
42+
43+
const deploymentName = getDeploymentName(CONTRACT_NAME, constructorArgTypes, constructorArgs);
44+
log(`Generated deterministic deployment name for this instance: ${deploymentName}`);
45+
46+
const deployment = await deploy(deploymentName, {
47+
contract: CONTRACT_NAME,
48+
from: deployerAddress,
49+
args: constructorArgs,
50+
log: true,
51+
waitConfirmations: confirmations,
52+
});
53+
54+
if (isLocalNetwork) {
55+
log('Skipping verification on local network.');
56+
return;
57+
}
58+
59+
log(
60+
`Attempting verification of ${deploymentName} (contract type ${CONTRACT_NAME}) at ${deployment.address} (already waited for confirmations)...`
61+
);
62+
await run('verify:verify', {
63+
address: deployment.address,
64+
constructorArguments: deployment.args,
65+
});
66+
};
67+
module.exports.tags = [CONTRACT_NAME];
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import type { HardhatRuntimeEnvironment } from 'hardhat/types';
2+
import type { DeploymentsExtension } from 'hardhat-deploy/types';
3+
4+
import { getDeploymentName } from '../src';
5+
6+
export const CONTRACT_NAME = 'ScaledApi3FeedProxyV1';
7+
8+
const deployTestProxy = async (deployments: DeploymentsExtension, deployerAddress: string) => {
9+
const { address: inverseApi3ReaderProxyV1Address } = await deployments
10+
.get('InverseApi3ReaderProxyV1')
11+
.catch(async () => {
12+
return deployments.deploy('InverseApi3ReaderProxyV1', {
13+
from: deployerAddress,
14+
args: ['0x5b0cf2b36a65a6BB085D501B971e4c102B9Cd473'],
15+
log: true,
16+
});
17+
});
18+
return inverseApi3ReaderProxyV1Address;
19+
};
20+
21+
module.exports = async (hre: HardhatRuntimeEnvironment) => {
22+
const { getUnnamedAccounts, deployments, network, ethers, run } = hre;
23+
const { deploy, log } = deployments;
24+
25+
const [deployerAddress] = await getUnnamedAccounts();
26+
if (!deployerAddress) {
27+
throw new Error('No deployer address found.');
28+
}
29+
log(`Deployer address: ${deployerAddress}`);
30+
31+
if (!process.env.DECIMALS) {
32+
throw new Error('DECIMALS environment variable not set. Please provide the number of decimals to use.');
33+
}
34+
const decimals = Number.parseInt(process.env.DECIMALS, 10);
35+
log(`Decimals: ${decimals}`);
36+
37+
const proxyAddress =
38+
network.name === 'hardhat' ? await deployTestProxy(deployments, deployerAddress) : process.env.PROXY;
39+
if (!proxyAddress) {
40+
throw new Error('PROXY environment variable not set. Please provide the address of the Api3ReaderProxy contract.');
41+
}
42+
if (!ethers.isAddress(proxyAddress)) {
43+
throw new Error(`Invalid address provided for PROXY: ${proxyAddress}`);
44+
}
45+
log(`Proxy address: ${proxyAddress}`);
46+
47+
const isLocalNetwork = network.name === 'hardhat' || network.name === 'localhost';
48+
49+
const confirmations = isLocalNetwork ? 1 : 5;
50+
log(`Deployment confirmations: ${confirmations}`);
51+
52+
const constructorArgs = [proxyAddress, decimals];
53+
const constructorArgTypes = ['address', 'uint8'];
54+
55+
const deploymentName = getDeploymentName(CONTRACT_NAME, constructorArgTypes, constructorArgs);
56+
log(`Generated deterministic deployment name for this instance: ${deploymentName}`);
57+
58+
const deployment = await deploy(deploymentName, {
59+
contract: CONTRACT_NAME,
60+
from: deployerAddress,
61+
args: constructorArgs,
62+
log: true,
63+
waitConfirmations: confirmations,
64+
});
65+
66+
if (isLocalNetwork) {
67+
log('Skipping verification on local network.');
68+
return;
69+
}
70+
71+
log(
72+
`Attempting verification of ${deploymentName} (contract type ${CONTRACT_NAME}) at ${deployment.address} (already waited for confirmations)...`
73+
);
74+
await run('verify:verify', {
75+
address: deployment.address,
76+
constructorArguments: deployment.args,
77+
});
78+
};
79+
module.exports.tags = [CONTRACT_NAME];

example.env

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
MNEMONIC=
2+
ETHERSCAN_API_KEY_APECHAIN=
3+
ETHERSCAN_API_KEY_ARBITRUM_SEPOLIA_TESTNET=
4+
ETHERSCAN_API_KEY_ARBITRUM=
5+
ETHERSCAN_API_KEY_AVALANCHE_TESTNET=
6+
ETHERSCAN_API_KEY_AVALANCHE=
7+
ETHERSCAN_API_KEY_BASE_SEPOLIA_TESTNET=
8+
ETHERSCAN_API_KEY_BASE=
9+
ETHERSCAN_API_KEY_BERACHAIN=
10+
ETHERSCAN_API_KEY_BLAST_SEPOLIA_TESTNET=
11+
ETHERSCAN_API_KEY_BLAST=
12+
ETHERSCAN_API_KEY_BSC_TESTNET=
13+
ETHERSCAN_API_KEY_BSC=
14+
ETHERSCAN_API_KEY_CORE_TESTNET=
15+
ETHERSCAN_API_KEY_CORE=
16+
ETHERSCAN_API_KEY_ETHEREUM_HOLESKY_TESTNET=
17+
ETHERSCAN_API_KEY_ETHEREUM_SEPOLIA_TESTNET=
18+
ETHERSCAN_API_KEY_ETHEREUM=
19+
ETHERSCAN_API_KEY_FRAXTAL_HOLESKY_TESTNET=
20+
ETHERSCAN_API_KEY_FRAXTAL=
21+
ETHERSCAN_API_KEY_GNOSIS=
22+
ETHERSCAN_API_KEY_KROMA_SEPOLIA_TESTNET=
23+
ETHERSCAN_API_KEY_LINEA_SEPOLIA_TESTNET=
24+
ETHERSCAN_API_KEY_LINEA=
25+
ETHERSCAN_API_KEY_MANTLE_SEPOLIA_TESTNET=
26+
ETHERSCAN_API_KEY_MANTLE=
27+
ETHERSCAN_API_KEY_MOONBEAM_TESTNET=
28+
ETHERSCAN_API_KEY_MOONBEAM=
29+
ETHERSCAN_API_KEY_MOONRIVER=
30+
ETHERSCAN_API_KEY_OPBNB_TESTNET=
31+
ETHERSCAN_API_KEY_OPBNB=
32+
ETHERSCAN_API_KEY_OPTIMISM_SEPOLIA_TESTNET=
33+
ETHERSCAN_API_KEY_OPTIMISM=
34+
ETHERSCAN_API_KEY_POLYGON_SEPOLIA_TESTNET=
35+
ETHERSCAN_API_KEY_POLYGON_ZKEVM_SEPOLIA_TESTNET=
36+
ETHERSCAN_API_KEY_POLYGON_ZKEVM=
37+
ETHERSCAN_API_KEY_POLYGON=
38+
ETHERSCAN_API_KEY_SCROLL_SEPOLIA_TESTNET=
39+
ETHERSCAN_API_KEY_SCROLL=
40+
ETHERSCAN_API_KEY_SONIC_TESTNET=
41+
ETHERSCAN_API_KEY_SONIC=
42+
ETHERSCAN_API_KEY_TAIKO_HOLESKY_TESTNET=
43+
ETHERSCAN_API_KEY_TAIKO=
44+
ETHERSCAN_API_KEY_UNICHAIN_SEPOLIA_TESTNET=
45+
ETHERSCAN_API_KEY_UNICHAIN=
46+
ETHERSCAN_API_KEY_WORLD=
47+
ETHERSCAN_API_KEY_ZIRCUIT_SEPOLIA_TESTNET=
48+
ETHERSCAN_API_KEY_ZIRCUIT=

hardhat.config.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import { hardhatConfig } from '@api3/contracts';
22
import '@nomicfoundation/hardhat-toolbox';
3+
import '@nomicfoundation/hardhat-verify';
4+
import 'hardhat-deploy';
5+
import 'dotenv/config';
36
import type { HardhatUserConfig } from 'hardhat/config';
47

58
const config: HardhatUserConfig = {

0 commit comments

Comments
 (0)