@openzeppelin/upgrades-core 1.25.0 → 1.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.dbg.json +1 -1
  2. package/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json +2 -2
  3. package/artifacts/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.dbg.json +1 -1
  4. package/artifacts/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json +2 -2
  5. package/artifacts/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.dbg.json +1 -1
  6. package/artifacts/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json +2 -2
  7. package/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json +7 -7
  8. package/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +2 -72
  9. package/artifacts/AdminUpgradeabilityProxy.json +2 -72
  10. package/artifacts/ProxyAdmin.json +7 -7
  11. package/artifacts/build-info.json +21225 -12
  12. package/artifacts/contracts/proxy/AdminUpgradeabilityProxy.sol/AdminUpgradeabilityProxy.json +2 -72
  13. package/artifacts/contracts/proxy/ProxyAdmin.sol/ProxyAdmin.json +7 -7
  14. package/dist/deployment.d.ts +28 -4
  15. package/dist/deployment.d.ts.map +1 -1
  16. package/dist/deployment.js +106 -25
  17. package/dist/deployment.js.map +1 -1
  18. package/dist/deployment.test.js +116 -0
  19. package/dist/deployment.test.js.map +1 -1
  20. package/dist/impl-store.d.ts +27 -2
  21. package/dist/impl-store.d.ts.map +1 -1
  22. package/dist/impl-store.js +39 -8
  23. package/dist/impl-store.js.map +1 -1
  24. package/dist/impl-store.test.js +30 -0
  25. package/dist/impl-store.test.js.map +1 -1
  26. package/dist/manifest.d.ts +3 -3
  27. package/dist/manifest.d.ts.map +1 -1
  28. package/dist/manifest.js +1 -1
  29. package/dist/manifest.js.map +1 -1
  30. package/dist/manifest.test.js +1 -0
  31. package/dist/manifest.test.js.map +1 -1
  32. package/dist/validate/error.d.ts +3 -0
  33. package/dist/validate/error.d.ts.map +1 -1
  34. package/dist/validate/error.js +7 -1
  35. package/dist/validate/error.js.map +1 -1
  36. package/dist/validate/index.d.ts +1 -1
  37. package/dist/validate/index.d.ts.map +1 -1
  38. package/dist/validate/index.js +2 -1
  39. package/dist/validate/index.js.map +1 -1
  40. package/dist/validate/query.js +1 -1
  41. package/dist/validate/query.js.map +1 -1
  42. package/package.json +5 -4
  43. package/src/deployment.test.ts +182 -1
  44. package/src/deployment.ts +134 -26
  45. package/src/impl-store.test.ts +52 -1
  46. package/src/impl-store.ts +69 -11
  47. package/src/manifest.test.ts +1 -0
  48. package/src/manifest.ts +11 -8
  49. package/src/validate/error.ts +6 -0
  50. package/src/validate/index.ts +1 -1
  51. package/src/validate/query.ts +2 -2
package/src/impl-store.ts CHANGED
@@ -1,7 +1,14 @@
1
1
  import debug from './utils/debug';
2
2
  import { Manifest, ManifestData, ImplDeployment } from './manifest';
3
3
  import { EthereumProvider, isDevelopmentNetwork } from './provider';
4
- import { Deployment, InvalidDeployment, resumeOrDeploy, waitAndValidateDeployment } from './deployment';
4
+ import {
5
+ Deployment,
6
+ RemoteDeploymentId,
7
+ RemoteDeployment,
8
+ InvalidDeployment,
9
+ resumeOrDeploy,
10
+ waitAndValidateDeployment,
11
+ } from './deployment';
5
12
  import { Version } from './version';
6
13
  import assert from 'assert';
7
14
  import { DeployOpts } from '.';
@@ -26,6 +33,7 @@ export interface ManifestField<T> {
26
33
  * @param deploy the deploy function
27
34
  * @param opts options containing the timeout and pollingInterval parameters. If undefined, assumes the timeout is not configurable and will not mention those parameters in the error message for TransactionMinedTimeout.
28
35
  * @param merge if true, adds a deployment to existing deployment by merging their addresses. Defaults to false.
36
+ * @param getRemoteDeployment a function to get the remote deployment status by id. If the deployment id is not found, returns undefined.
29
37
  * @returns the deployment
30
38
  * @throws {InvalidDeployment} if the deployment is invalid
31
39
  * @throws {TransactionMinedTimeout} if the transaction was not confirmed within the timeout period
@@ -36,6 +44,7 @@ async function fetchOrDeployGeneric<T extends Deployment, U extends T = T>(
36
44
  deploy: () => Promise<U>,
37
45
  opts?: DeployOpts,
38
46
  merge?: boolean,
47
+ getRemoteDeployment?: (remoteDeploymentId: string) => Promise<RemoteDeployment | undefined>,
39
48
  ): Promise<U | Deployment> {
40
49
  const manifest = await Manifest.forNetwork(provider);
41
50
 
@@ -51,7 +60,16 @@ async function fetchOrDeployGeneric<T extends Deployment, U extends T = T>(
51
60
  }
52
61
 
53
62
  const stored = deployment.get();
54
- const updated = await resumeOrDeploy(provider, stored, deploy, lens.type, opts, deployment, merge);
63
+ const updated = await resumeOrDeploy(
64
+ provider,
65
+ stored,
66
+ deploy,
67
+ lens.type,
68
+ opts,
69
+ deployment,
70
+ merge,
71
+ getRemoteDeployment,
72
+ );
55
73
  if (updated !== stored) {
56
74
  if (merge && deployment.merge) {
57
75
  // only check primary addresses for clashes, since the address could already exist in an allAddresses field
@@ -67,7 +85,7 @@ async function fetchOrDeployGeneric<T extends Deployment, U extends T = T>(
67
85
  return updated;
68
86
  });
69
87
 
70
- await waitAndValidateDeployment(provider, deployment, lens.type, opts);
88
+ await waitAndValidateDeployment(provider, deployment, lens.type, opts, getRemoteDeployment);
71
89
 
72
90
  return deployment;
73
91
  } catch (e) {
@@ -98,6 +116,18 @@ export function deleteDeployment(deployment: ManifestField<Deployment>) {
98
116
  deployment.set(undefined);
99
117
  }
100
118
 
119
+ /**
120
+ * Fetches the deployment address from the manifest, or deploys it if not found and returns the address.
121
+ *
122
+ * @param version the contract version
123
+ * @param provider the Ethereum provider
124
+ * @param deploy the deploy function
125
+ * @param opts options containing the timeout and pollingInterval parameters. If undefined, assumes the timeout is not configurable and will not mention those parameters in the error message for TransactionMinedTimeout.
126
+ * @param merge if true, adds a deployment to existing deployment by merging their addresses. Defaults to false.
127
+ * @returns the deployment address
128
+ * @throws {InvalidDeployment} if the deployment is invalid
129
+ * @throws {TransactionMinedTimeout} if the transaction was not confirmed within the timeout period
130
+ */
101
131
  export async function fetchOrDeploy(
102
132
  version: Version,
103
133
  provider: EthereumProvider,
@@ -108,14 +138,35 @@ export async function fetchOrDeploy(
108
138
  return (await fetchOrDeployGeneric(implLens(version.linkedWithoutMetadata), provider, deploy, opts, merge)).address;
109
139
  }
110
140
 
141
+ /**
142
+ * Fetches the deployment from the manifest, or deploys it if not found and returns the deployment.
143
+ *
144
+ * @param version the contract version
145
+ * @param provider the Ethereum provider
146
+ * @param deploy the deploy function
147
+ * @param opts options containing the timeout and pollingInterval parameters. If undefined, assumes the timeout is not configurable and will not mention those parameters in the error message for TransactionMinedTimeout.
148
+ * @param merge if true, adds a deployment to existing deployment by merging their addresses. Defaults to false.
149
+ * @param getRemoteDeployment a function to get the remote deployment status by id. If the deployment id is not found, returns undefined.
150
+ * @returns the deployment
151
+ * @throws {InvalidDeployment} if the deployment is invalid
152
+ * @throws {TransactionMinedTimeout} if the transaction was not confirmed within the timeout period
153
+ */
111
154
  export async function fetchOrDeployGetDeployment<T extends ImplDeployment>(
112
155
  version: Version,
113
156
  provider: EthereumProvider,
114
157
  deploy: () => Promise<T>,
115
158
  opts?: DeployOpts,
116
159
  merge?: boolean,
160
+ getRemoteDeployment?: (remoteDeploymentId: string) => Promise<RemoteDeployment | undefined>,
117
161
  ): Promise<T | Deployment> {
118
- return fetchOrDeployGeneric(implLens(version.linkedWithoutMetadata), provider, deploy, opts, merge);
162
+ return fetchOrDeployGeneric(
163
+ implLens(version.linkedWithoutMetadata),
164
+ provider,
165
+ deploy,
166
+ opts,
167
+ merge,
168
+ getRemoteDeployment,
169
+ );
119
170
  }
120
171
 
121
172
  const implLens = (versionWithoutMetadata: string) =>
@@ -171,7 +222,7 @@ function lens<T>(description: string, type: string, fn: (data: ManifestData) =>
171
222
  async function checkForAddressClash(
172
223
  provider: EthereumProvider,
173
224
  data: ManifestData,
174
- updated: Deployment,
225
+ updated: Deployment & RemoteDeploymentId,
175
226
  checkAllAddresses: boolean,
176
227
  ): Promise<void> {
177
228
  const clash = lookupDeployment(data, updated.address, checkAllAddresses);
@@ -180,11 +231,18 @@ async function checkForAddressClash(
180
231
  debug('deleting a previous deployment at address', updated.address);
181
232
  clash.set(undefined);
182
233
  } else {
183
- throw new Error(
184
- `The following deployment clashes with an existing one at ${updated.address}\n\n` +
185
- JSON.stringify(updated, null, 2) +
186
- `\n\n`,
187
- );
234
+ const existing = clash.get();
235
+ // it's a clash if there is no deployment id or if deployment ids don't match
236
+ if (
237
+ existing !== undefined &&
238
+ (existing.remoteDeploymentId === undefined || existing.remoteDeploymentId !== updated.remoteDeploymentId)
239
+ ) {
240
+ throw new Error(
241
+ `The following deployment clashes with an existing one at ${updated.address}\n\n` +
242
+ JSON.stringify(updated, null, 2) +
243
+ `\n\n`,
244
+ );
245
+ }
188
246
  }
189
247
  }
190
248
  }
@@ -193,7 +251,7 @@ function lookupDeployment(
193
251
  data: ManifestData,
194
252
  address: string,
195
253
  checkAllAddresses: boolean,
196
- ): ManifestField<Deployment> | undefined {
254
+ ): ManifestField<Deployment & RemoteDeploymentId> | undefined {
197
255
  if (data.admin?.address === address) {
198
256
  return adminLens(data);
199
257
  }
@@ -434,6 +434,7 @@ test('normalize manifest', t => {
434
434
  const deployment = {
435
435
  address: '0x1234',
436
436
  txHash: '0x1234',
437
+ remoteDeploymentId: 'abc',
437
438
  kind: 'uups' as const,
438
439
  layout: { solcVersion: '0.8.9', types: {}, storage: [] },
439
440
  deployTransaction: {},
package/src/manifest.ts CHANGED
@@ -5,7 +5,7 @@ import { EthereumProvider, getChainId, getHardhatMetadata, networkNames } from '
5
5
  import lockfile from 'proper-lockfile';
6
6
  import { compare as compareVersions } from 'compare-versions';
7
7
 
8
- import type { Deployment } from './deployment';
8
+ import type { Deployment, RemoteDeploymentId } from './deployment';
9
9
  import type { StorageLayout } from './storage';
10
10
  import { pick } from './utils/pick';
11
11
  import { mapValues } from './utils/map-values';
@@ -18,9 +18,9 @@ const currentManifestVersion = '3.2';
18
18
  export interface ManifestData {
19
19
  manifestVersion: string;
20
20
  impls: {
21
- [version in string]?: ImplDeployment;
21
+ [version in string]?: ImplDeployment & RemoteDeploymentId;
22
22
  };
23
- proxies: ProxyDeployment[];
23
+ proxies: (ProxyDeployment & RemoteDeploymentId)[];
24
24
  admin?: Deployment;
25
25
  }
26
26
 
@@ -318,11 +318,14 @@ export function normalizeManifestData(input: ManifestData): ManifestData {
318
318
  };
319
319
  }
320
320
 
321
- function normalizeDeployment<D extends Deployment>(input: D): Deployment;
322
- function normalizeDeployment<D extends Deployment, K extends keyof D>(input: D, include: K[]): Deployment & Pick<D, K>;
323
- function normalizeDeployment<D extends Deployment, K extends keyof D>(
321
+ function normalizeDeployment<D extends Deployment & RemoteDeploymentId>(input: D): Deployment & RemoteDeploymentId;
322
+ function normalizeDeployment<D extends Deployment & RemoteDeploymentId, K extends keyof D>(
323
+ input: D,
324
+ include: K[],
325
+ ): Deployment & RemoteDeploymentId & Pick<D, K>;
326
+ function normalizeDeployment<D extends Deployment & RemoteDeploymentId, K extends keyof D>(
324
327
  input: D,
325
328
  include: K[] = [],
326
- ): Deployment & Pick<D, K> {
327
- return pick(input, ['address', 'txHash', ...include]);
329
+ ): Deployment & RemoteDeploymentId & Pick<D, K> {
330
+ return pick(input, ['address', 'txHash', 'remoteDeploymentId', ...include]);
328
331
  }
@@ -9,3 +9,9 @@ export class ValidationErrors extends UpgradesError {
9
9
  );
10
10
  }
11
11
  }
12
+
13
+ export class ContractSourceNotFoundError extends UpgradesError {
14
+ constructor() {
15
+ super('The requested contract was not found. Make sure the source code is available for compilation');
16
+ }
17
+ }
@@ -1,6 +1,6 @@
1
1
  export { validate, ValidationRunData, ContractValidation } from './run';
2
2
  export { ProxyKindOption, StandaloneValidationOptions, ValidationOptions, withValidationDefaults } from './overrides';
3
- export { ValidationErrors } from './error';
3
+ export { ValidationErrors, ContractSourceNotFoundError } from './error';
4
4
  export { RunValidation, ValidationLog, Validation, ValidationResult } from './compat';
5
5
  export { ValidationData, ValidationDataCurrent, isCurrentValidationData, concatRunData } from './data';
6
6
  export {
@@ -3,7 +3,7 @@ import { ValidationRunData, ValidationError, isOpcodeError } from './run';
3
3
  import { StorageLayout } from '../storage/layout';
4
4
  import { unlinkBytecode } from '../link-refs';
5
5
  import { ValidationOptions, processExceptions } from './overrides';
6
- import { ValidationErrors } from './error';
6
+ import { ContractSourceNotFoundError, ValidationErrors } from './error';
7
7
  import { ValidationData, normalizeValidationData } from './data';
8
8
  import { ProxyDeployment } from '../manifest';
9
9
 
@@ -72,7 +72,7 @@ export function getContractNameAndRunValidation(data: ValidationData, version: V
72
72
  }
73
73
 
74
74
  if (fullContractName === undefined || runValidation === undefined) {
75
- throw new Error('The requested contract was not found. Make sure the source code is available for compilation');
75
+ throw new ContractSourceNotFoundError();
76
76
  }
77
77
 
78
78
  return [fullContractName, runValidation];