Skip to content

Commit 451d217

Browse files
Support TypeChain in deploy and upgrade proxy functions - continuation of work done on #535 (#1099)
Co-authored-by: Eric Lau <ericglau@outlook.com>
1 parent 7bdb777 commit 451d217

File tree

8 files changed

+66
-34
lines changed

8 files changed

+66
-34
lines changed

packages/plugin-hardhat/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## 3.8.0 (2024-12-19)
4+
5+
- Support TypeChain in `deployProxy`, `upgradeProxy`, `deployBeaconProxy`, and `defender.deployContract`. ([#1099](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1099))
6+
37
## 3.7.0 (2024-12-04)
48

59
- Add `proxyFactory` and `deployFunction` options which can be used to deploy a custom proxy contract. ([#1104](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1104))

packages/plugin-hardhat/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@openzeppelin/hardhat-upgrades",
3-
"version": "3.7.0",
3+
"version": "3.8.0",
44
"description": "",
55
"repository": "https://github.com/OpenZeppelin/openzeppelin-upgrades/tree/master/packages/plugin-hardhat",
66
"license": "MIT",

packages/plugin-hardhat/src/deploy-beacon-proxy.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { HardhatRuntimeEnvironment } from 'hardhat/types';
2-
import { Contract, ContractFactory } from 'ethers';
2+
import { ContractFactory } from 'ethers';
33

44
import {
55
Manifest,
@@ -24,27 +24,32 @@ import {
2424
} from './utils';
2525
import { enableDefender } from './defender/utils';
2626
import { getContractInstance } from './utils/contract-instance';
27+
import { ContractTypeOfFactory } from './type-extensions';
2728

2829
export interface DeployBeaconProxyFunction {
29-
(
30+
<F extends ContractFactory>(
3031
beacon: ContractAddressOrInstance,
31-
attachTo: ContractFactory,
32+
attachTo: F,
3233
args?: unknown[],
3334
opts?: DeployBeaconProxyOptions,
34-
): Promise<Contract>;
35-
(beacon: ContractAddressOrInstance, attachTo: ContractFactory, opts?: DeployBeaconProxyOptions): Promise<Contract>;
35+
): Promise<ContractTypeOfFactory<F>>;
36+
<F extends ContractFactory>(
37+
beacon: ContractAddressOrInstance,
38+
attachTo: F,
39+
opts?: DeployBeaconProxyOptions,
40+
): Promise<ContractTypeOfFactory<F>>;
3641
}
3742

3843
export function makeDeployBeaconProxy(
3944
hre: HardhatRuntimeEnvironment,
4045
defenderModule: boolean,
4146
): DeployBeaconProxyFunction {
42-
return async function deployBeaconProxy(
47+
return async function deployBeaconProxy<F extends ContractFactory>(
4348
beacon: ContractAddressOrInstance,
44-
attachTo: ContractFactory,
49+
attachTo: F,
4550
args: unknown[] | DeployBeaconProxyOptions = [],
4651
opts: DeployBeaconProxyOptions = {},
47-
) {
52+
): Promise<ContractTypeOfFactory<F>> {
4853
if (!(attachTo instanceof ContractFactory)) {
4954
throw new UpgradesError(
5055
`attachTo must specify a contract factory`,

packages/plugin-hardhat/src/deploy-contract.ts

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,37 @@
11
import { HardhatRuntimeEnvironment } from 'hardhat/types';
2-
import type { ContractFactory, Contract } from 'ethers';
2+
import type { ContractFactory } from 'ethers';
33

4-
import { deploy, DeployContractOptions, EthersOrDefenderDeployment } from './utils';
4+
import { deploy, DeployContractOptions, DeployTransaction, EthersOrDefenderDeployment } from './utils';
55
import { DeployData, getDeployData } from './utils/deploy-impl';
66
import { enableDefender } from './defender/utils';
77
import {
88
getContractNameAndRunValidation,
99
inferProxyKind,
1010
UpgradesError,
1111
inferInitializable,
12+
Deployment,
13+
RemoteDeploymentId,
1214
} from '@openzeppelin/upgrades-core';
1315
import { getContractInstance } from './utils/contract-instance';
16+
import { ContractTypeOfFactory } from './type-extensions';
1417

1518
export interface DeployContractFunction {
16-
(Contract: ContractFactory, args?: unknown[], opts?: DeployContractOptions): Promise<Contract>;
17-
(Contract: ContractFactory, opts?: DeployContractOptions): Promise<Contract>;
19+
<F extends ContractFactory>(
20+
Contract: F,
21+
args?: unknown[],
22+
opts?: DeployContractOptions,
23+
): Promise<ContractTypeOfFactory<F>>;
24+
<F extends ContractFactory>(
25+
Contract: ContractFactory,
26+
opts?: DeployContractOptions,
27+
): Promise<ContractTypeOfFactory<F>>;
1828
}
1929

2030
async function deployNonUpgradeableContract(
2131
hre: HardhatRuntimeEnvironment,
2232
Contract: ContractFactory,
2333
opts: DeployContractOptions,
24-
) {
34+
): Promise<Required<Deployment> & DeployTransaction & RemoteDeploymentId> {
2535
const deployData = await getDeployData(hre, Contract, opts);
2636

2737
if (!opts.unsafeAllowDeployContract) {
@@ -34,7 +44,6 @@ async function deployNonUpgradeableContract(
3444
Contract,
3545
...deployData.fullOpts.constructorArgs,
3646
);
37-
3847
return deployment;
3948
}
4049

@@ -52,11 +61,11 @@ function assertNonUpgradeable(deployData: DeployData) {
5261
}
5362

5463
export function makeDeployContract(hre: HardhatRuntimeEnvironment, defenderModule: boolean): DeployContractFunction {
55-
return async function deployContract(
56-
Contract,
64+
return async function deployContract<F extends ContractFactory>(
65+
Contract: F,
5766
args: unknown[] | DeployContractOptions = [],
5867
opts: DeployContractOptions = {},
59-
) {
68+
): Promise<ContractTypeOfFactory<F>> {
6069
if (!Array.isArray(args)) {
6170
opts = args;
6271
args = [];

packages/plugin-hardhat/src/deploy-proxy.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { HardhatRuntimeEnvironment } from 'hardhat/types';
2-
import type { ContractFactory, Contract } from 'ethers';
2+
import type { ContractFactory } from 'ethers';
33

44
import {
55
Manifest,
@@ -25,18 +25,23 @@ import {
2525
import { enableDefender } from './defender/utils';
2626
import { getContractInstance } from './utils/contract-instance';
2727
import { getInitialOwner } from './utils/initial-owner';
28+
import { ContractTypeOfFactory } from './type-extensions';
2829

2930
export interface DeployFunction {
30-
(ImplFactory: ContractFactory, args?: unknown[], opts?: DeployProxyOptions): Promise<Contract>;
31-
(ImplFactory: ContractFactory, opts?: DeployProxyOptions): Promise<Contract>;
31+
<F extends ContractFactory>(
32+
ImplFactory: F,
33+
args?: unknown[],
34+
opts?: DeployProxyOptions,
35+
): Promise<ContractTypeOfFactory<F>>;
36+
<F extends ContractFactory>(ImplFactory: F, opts?: DeployProxyOptions): Promise<ContractTypeOfFactory<F>>;
3237
}
3338

3439
export function makeDeployProxy(hre: HardhatRuntimeEnvironment, defenderModule: boolean): DeployFunction {
35-
return async function deployProxy(
36-
ImplFactory: ContractFactory,
40+
return async function deployProxy<F extends ContractFactory>(
41+
ImplFactory: F,
3742
args: unknown[] | DeployProxyOptions = [],
3843
opts: DeployProxyOptions = {},
39-
) {
44+
): Promise<ContractTypeOfFactory<F>> {
4045
if (!Array.isArray(args)) {
4146
opts = args;
4247
args = [];

packages/plugin-hardhat/src/type-extensions.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import 'hardhat/types/runtime';
22
import 'hardhat/types/config';
33

44
import type { HardhatUpgrades, DefenderHardhatUpgrades } from '.';
5+
import { ContractFactory } from 'ethers';
6+
7+
export type ContractTypeOfFactory<F extends ContractFactory> = ReturnType<F['attach']> & ReturnType<F['deploy']>;
58

69
declare module 'hardhat/types/runtime' {
710
export interface HardhatRuntimeEnvironment {

packages/plugin-hardhat/src/upgrade-proxy.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { HardhatRuntimeEnvironment } from 'hardhat/types';
2-
import type { ethers, ContractFactory, Contract, Signer } from 'ethers';
2+
import type { ethers, ContractFactory, Signer } from 'ethers';
33
import debug from './utils/debug';
44
import { getAdminAddress, getCode, getUpgradeInterfaceVersion, isEmptySlot } from '@openzeppelin/upgrades-core';
55

@@ -18,19 +18,24 @@ import {
1818
attachProxyAdminV4,
1919
attachProxyAdminV5,
2020
} from './utils/attach-abi';
21+
import { ContractTypeOfFactory } from './type-extensions';
2122

22-
export type UpgradeFunction = (
23+
export type UpgradeFunction = <F extends ContractFactory>(
2324
proxy: ContractAddressOrInstance,
24-
ImplFactory: ContractFactory,
25+
ImplFactory: F,
2526
opts?: UpgradeProxyOptions,
26-
) => Promise<Contract>;
27+
) => Promise<ContractTypeOfFactory<F>>;
2728

2829
export function makeUpgradeProxy(
2930
hre: HardhatRuntimeEnvironment,
3031
defenderModule: boolean,
3132
log = debug,
3233
): UpgradeFunction {
33-
return async function upgradeProxy(proxy, ImplFactory, opts: UpgradeProxyOptions = {}) {
34+
return async function upgradeProxy<F extends ContractFactory>(
35+
proxy: ContractAddressOrInstance,
36+
ImplFactory: F,
37+
opts: UpgradeProxyOptions = {},
38+
): Promise<ContractTypeOfFactory<F>> {
3439
disableDefender(hre, defenderModule, opts, upgradeProxy.name);
3540

3641
const proxyAddress = await getContractAddress(proxy);
@@ -44,7 +49,7 @@ export function makeUpgradeProxy(
4449
const inst = attach(ImplFactory, proxyAddress);
4550
// @ts-ignore Won't be readonly because inst was created through attach.
4651
inst.deployTransaction = upgradeTx;
47-
return inst;
52+
return inst as ContractTypeOfFactory<F>;
4853
};
4954

5055
type Upgrader = (nextImpl: string, call?: string) => Promise<ethers.TransactionResponse>;

packages/plugin-hardhat/src/utils/contract-instance.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { DeployTransaction, DefenderDeploy } from '.';
66
import { waitForDeployment } from '../defender/utils';
77
import { Deployment, RemoteDeploymentId, DeployOpts } from '@openzeppelin/upgrades-core';
88
import { attach } from './ethers';
9+
import { ContractTypeOfFactory } from '../type-extensions';
910

1011
/**
1112
* Gets a contract instance from a deployment, where the deployment may be remote.
@@ -19,13 +20,13 @@ import { attach } from './ethers';
1920
* @param deployTransaction The transaction that deployed the contract, if available
2021
* @returns The contract instance
2122
*/
22-
export function getContractInstance(
23+
export function getContractInstance<F extends ContractFactory>(
2324
hre: HardhatRuntimeEnvironment,
24-
contract: ContractFactory,
25+
contract: F,
2526
opts: DeployOpts & DefenderDeploy,
2627
deployment: Deployment & DeployTransaction & RemoteDeploymentId,
27-
) {
28-
const instance = attach(contract, deployment.address);
28+
): ContractTypeOfFactory<F> {
29+
const instance = attach(contract, deployment.address) as ContractTypeOfFactory<F>;
2930

3031
// @ts-ignore Won't be readonly because instance was created through attach.
3132
instance.deploymentTransaction = () => deployment.deployTransaction ?? null; // Convert undefined to null to conform to ethers.js types.

0 commit comments

Comments
 (0)