@openzeppelin/upgrades-core 1.31.3 → 1.32.0

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 (35) hide show
  1. package/artifacts/@openzeppelin/contracts-v5/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json +76 -0
  2. package/artifacts/@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol/BeaconProxy.json +87 -0
  3. package/artifacts/@openzeppelin/contracts-v5/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json +151 -0
  4. package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json +132 -0
  5. package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/ITransparentUpgradeableProxy.json +74 -0
  6. package/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +116 -0
  7. package/artifacts/build-info-v5.json +13993 -0
  8. package/dist/impl-store.d.ts.map +1 -1
  9. package/dist/impl-store.js +24 -14
  10. package/dist/impl-store.js.map +1 -1
  11. package/dist/impl-store.test.js +73 -4
  12. package/dist/impl-store.test.js.map +1 -1
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/scripts/migratable-manifest.test.json +175 -0
  18. package/dist/scripts/project-file.test.json +25 -0
  19. package/dist/solidity-version.json +1 -0
  20. package/dist/standalone.test.js +9 -8
  21. package/dist/standalone.test.js.map +1 -1
  22. package/dist/usage-error.d.ts +3 -0
  23. package/dist/usage-error.d.ts.map +1 -1
  24. package/dist/usage-error.js +7 -1
  25. package/dist/usage-error.js.map +1 -1
  26. package/package.json +20 -13
  27. package/src/impl-store.test.ts +128 -4
  28. package/src/impl-store.ts +27 -16
  29. package/src/index.ts +1 -0
  30. package/src/solidity-version.json +1 -0
  31. package/src/standalone.test.ts +41 -7
  32. package/src/usage-error.ts +9 -0
  33. package/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.dbg.json +0 -4
  34. package/artifacts/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.dbg.json +0 -4
  35. package/artifacts/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.dbg.json +0 -4
@@ -1 +1 @@
1
- {"version":3,"file":"usage-error.js","sourceRoot":"","sources":["../src/usage-error.ts"],"names":[],"mappings":";;;AAAA,wBAA+G;AAE/G,MAAa,2BAA4B,SAAQ,gBAAa;IAC5D;QACE,KAAK,CACH,6DAA6D,EAC7D,GAAG,EAAE,CAAC,sEAAsE,CAC7E,CAAC;IACJ,CAAC;CACF;AAPD,kEAOC;AAED,MAAa,0BAA2B,SAAQ,gBAAa;IAC3D,YAAY,IAAY;QACtB,KAAK,CACH,2BAA2B,IAAI,GAAG,EAClC,GAAG,EAAE,CAAC,6EAA6E,CACpF,CAAC;IACJ,CAAC;CACF;AAPD,gEAOC;AAED,MAAa,iCAAkC,SAAQ,gBAAa;IAClE,YAAY,aAAqB;QAC/B,KAAK,CAAC,eAAe,aAAa,6BAA6B,EAAE,GAAG,EAAE,CAAC,uCAAuC,CAAC,CAAC;IAClH,CAAC;CACF;AAJD,8EAIC;AAED,MAAa,iCAAkC,SAAQ,gBAAa;IAClE,YAAY,WAAmB;QAC7B,KAAK,CACH,sCAAsC,WAAW,aAAa,EAC9D,GAAG,EAAE,CAAC,wGAAwG,CAC/G,CAAC;IACJ,CAAC;CACF;AAPD,8EAOC;AAED,MAAa,yBAA0B,SAAQ,gBAAa;IAC1D,YAAY,YAAoB;QAC9B,KAAK,CACH,eAAe,YAAY,sCAAsC,EACjE,GAAG,EAAE,CAAC,wFAAwF,CAC/F,CAAC;IACJ,CAAC;CACF;AAPD,8DAOC;AAED;;GAEG;AACH,MAAa,8BAA+B,SAAQ,gBAAa;IAC/D,YAAY,oBAA4B;QACtC,KAAK,CACH,uBAAuB,oBAAoB,gDAAgD,EAC3F,GAAG,EAAE,CAAC,sGAAsG,CAC7G,CAAC;IACJ,CAAC;CACF;AAPD,wEAOC;AAED;;GAEG;AACH,MAAa,2BAA4B,SAAQ,gBAAa;IAC5D,YAAY,oBAA4B;QACtC,KAAK,CACH,uBAAuB,oBAAoB,gDAAgD,EAC3F,GAAG,EAAE,CAAC,mGAAmG,CAC1G,CAAC;IACJ,CAAC;CACF;AAPD,kEAOC;AAED,MAAa,qBAAsB,SAAQ,gBAAa;IACtD,YAAY,OAAe;QACzB,KAAK,CACH,0BAA0B,OAAO,EAAE,EACnC,GAAG,EAAE,CAAC,iFAAiF,CACxF,CAAC;IACJ,CAAC;CACF;AAPD,sDAOC;AAED,MAAa,+BAAgC,SAAQ,gBAAa;IAChE;QACE,KAAK,CACH,oCAAoC,EACpC,GAAG,EAAE,CACH,gIAAgI,CACnI,CAAC;IACJ,CAAC;CACF;AARD,0EAQC;AAED,MAAa,+BAAgC,SAAQ,gBAAa;IAChE;QACE,KAAK,CACH,oCAAoC,EACpC,GAAG,EAAE,CACH,+HAA+H,CAClI,CAAC;IACJ,CAAC;CACF;AARD,0EAQC;AAEM,KAAK,UAAU,cAAc,CAAC,QAA0B,EAAE,OAAe;IAC9E,IAAI,MAAM,IAAA,2BAAwB,EAAC,QAAQ,EAAE,OAAO,CAAC,EAAE;QACrD,MAAM,IAAI,gBAAa,CACrB,wFAAwF,EACxF,GAAG,EAAE,CAAC,6BAA6B,CACpC,CAAC;KACH;SAAM,IAAI,MAAM,IAAA,gBAAa,EAAC,QAAQ,EAAE,OAAO,CAAC,EAAE;QACjD,MAAM,aAAa,GAAG,MAAM,IAAA,mBAAgB,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,IAAI,gBAAa,CACrB,8DAA8D,EAC9D,GAAG,EAAE,CACH,gIAAgI,aAAa,WAAW,CAC3J,CAAC;KACH;AACH,CAAC;AAdD,wCAcC"}
1
+ {"version":3,"file":"usage-error.js","sourceRoot":"","sources":["../src/usage-error.ts"],"names":[],"mappings":";;;AAAA,wBAA+G;AAE/G,MAAa,2BAA4B,SAAQ,gBAAa;IAC5D;QACE,KAAK,CACH,6DAA6D,EAC7D,GAAG,EAAE,CAAC,sEAAsE,CAC7E,CAAC;IACJ,CAAC;CACF;AAPD,kEAOC;AAED,MAAa,0BAA2B,SAAQ,gBAAa;IAC3D,YAAY,IAAY;QACtB,KAAK,CACH,2BAA2B,IAAI,GAAG,EAClC,GAAG,EAAE,CAAC,6EAA6E,CACpF,CAAC;IACJ,CAAC;CACF;AAPD,gEAOC;AAED,MAAa,iCAAkC,SAAQ,gBAAa;IAClE,YAAY,aAAqB;QAC/B,KAAK,CAAC,eAAe,aAAa,6BAA6B,EAAE,GAAG,EAAE,CAAC,uCAAuC,CAAC,CAAC;IAClH,CAAC;CACF;AAJD,8EAIC;AAED,MAAa,iCAAkC,SAAQ,gBAAa;IAClE,YAAY,WAAmB;QAC7B,KAAK,CACH,sCAAsC,WAAW,aAAa,EAC9D,GAAG,EAAE,CAAC,wGAAwG,CAC/G,CAAC;IACJ,CAAC;CACF;AAPD,8EAOC;AAED,MAAa,yBAA0B,SAAQ,gBAAa;IAC1D,YAAY,YAAoB;QAC9B,KAAK,CACH,eAAe,YAAY,sCAAsC,EACjE,GAAG,EAAE,CAAC,wFAAwF,CAC/F,CAAC;IACJ,CAAC;CACF;AAPD,8DAOC;AAED;;GAEG;AACH,MAAa,8BAA+B,SAAQ,gBAAa;IAC/D,YAAY,oBAA4B;QACtC,KAAK,CACH,uBAAuB,oBAAoB,gDAAgD,EAC3F,GAAG,EAAE,CAAC,sGAAsG,CAC7G,CAAC;IACJ,CAAC;CACF;AAPD,wEAOC;AAED;;GAEG;AACH,MAAa,2BAA4B,SAAQ,gBAAa;IAC5D,YAAY,oBAA4B;QACtC,KAAK,CACH,uBAAuB,oBAAoB,gDAAgD,EAC3F,GAAG,EAAE,CAAC,mGAAmG,CAC1G,CAAC;IACJ,CAAC;CACF;AAPD,kEAOC;AAED,MAAa,qBAAsB,SAAQ,gBAAa;IACtD,YAAY,OAAe;QACzB,KAAK,CACH,0BAA0B,OAAO,EAAE,EACnC,GAAG,EAAE,CAAC,iFAAiF,CACxF,CAAC;IACJ,CAAC;CACF;AAPD,sDAOC;AAED,MAAa,+BAAgC,SAAQ,gBAAa;IAChE;QACE,KAAK,CACH,oCAAoC,EACpC,GAAG,EAAE,CACH,gIAAgI,CACnI,CAAC;IACJ,CAAC;CACF;AARD,0EAQC;AAED,MAAa,+BAAgC,SAAQ,gBAAa;IAChE;QACE,KAAK,CACH,oCAAoC,EACpC,GAAG,EAAE,CACH,+HAA+H,CAClI,CAAC;IACJ,CAAC;CACF;AARD,0EAQC;AAED,MAAa,gCAAiC,SAAQ,gBAAa;IACjE,YAAY,IAAY;QACtB,KAAK,CACH,yEAAyE,IAAI,IAAI,EACjF,GAAG,EAAE,CAAC,iFAAiF,CACxF,CAAC;IACJ,CAAC;CACF;AAPD,4EAOC;AAEM,KAAK,UAAU,cAAc,CAAC,QAA0B,EAAE,OAAe;IAC9E,IAAI,MAAM,IAAA,2BAAwB,EAAC,QAAQ,EAAE,OAAO,CAAC,EAAE;QACrD,MAAM,IAAI,gBAAa,CACrB,wFAAwF,EACxF,GAAG,EAAE,CAAC,6BAA6B,CACpC,CAAC;KACH;SAAM,IAAI,MAAM,IAAA,gBAAa,EAAC,QAAQ,EAAE,OAAO,CAAC,EAAE;QACjD,MAAM,aAAa,GAAG,MAAM,IAAA,mBAAgB,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAChE,MAAM,IAAI,gBAAa,CACrB,8DAA8D,EAC9D,GAAG,EAAE,CACH,gIAAgI,aAAa,WAAW,CAC3J,CAAC;KACH;AACH,CAAC;AAdD,wCAcC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openzeppelin/upgrades-core",
3
- "version": "1.31.3",
3
+ "version": "1.32.0",
4
4
  "description": "",
5
5
  "repository": "https://github.com/OpenZeppelin/openzeppelin-upgrades/tree/master/packages/core",
6
6
  "license": "MIT",
@@ -13,22 +13,29 @@
13
13
  "/artifacts/contracts/proxy/AdminUpgradeabilityProxy.sol/AdminUpgradeabilityProxy.json",
14
14
  "/artifacts/contracts/proxy/ProxyAdmin.sol/ProxyAdmin.json",
15
15
  "/contracts/Initializable.sol",
16
- "/artifacts/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol",
17
- "/artifacts/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol",
18
- "/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol",
16
+ "/artifacts/@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol/BeaconProxy.json",
17
+ "/artifacts/@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json",
18
+ "/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json",
19
19
  "/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json",
20
20
  "/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json",
21
21
  "/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/ITransparentUpgradeableProxy.json",
22
- "/artifacts/build-info.json"
22
+ "/artifacts/build-info.json",
23
+ "/artifacts/@openzeppelin/contracts-v5/proxy/beacon/BeaconProxy.sol/BeaconProxy.json",
24
+ "/artifacts/@openzeppelin/contracts-v5/proxy/beacon/UpgradeableBeacon.sol/UpgradeableBeacon.json",
25
+ "/artifacts/@openzeppelin/contracts-v5/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json",
26
+ "/artifacts/@openzeppelin/contracts-v5/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json",
27
+ "/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json",
28
+ "/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/ITransparentUpgradeableProxy.json",
29
+ "/artifacts/build-info-v5.json"
23
30
  ],
24
31
  "scripts": {
25
32
  "clean": "hardhat clean && rimraf dist *.tsbuildinfo",
26
33
  "compile": "tsc -b && yarn compile:contracts",
27
- "compile:contracts": "hardhat compile && node scripts/copy-build-info.js",
28
- "prepare": "yarn clean && yarn compile",
29
- "prepublishOnly": "bash scripts/copy-artifacts.sh",
30
- "test": "tsc -b && hardhat compile --force && node scripts/copy-build-info.js && ava",
31
- "test:watch": "hardhat compile --force && fgbg 'ava --watch' 'tsc -b --watch' --",
34
+ "compile:contracts": "hardhat compile",
35
+ "copyfiles": "node scripts/copy-build-info-v5.js && bash scripts/copy-legacy-artifacts.sh",
36
+ "prepare": "yarn clean && yarn compile && yarn copyfiles",
37
+ "test": "tsc -b && hardhat compile --force && yarn copyfiles && ava",
38
+ "test:watch": "hardhat compile --force && yarn copyfiles && fgbg 'ava --watch' 'tsc -b --watch' --",
32
39
  "version": "node ../../scripts/bump-changelog.js",
33
40
  "cli": "node ./dist/cli/cli.js"
34
41
  },
@@ -38,8 +45,8 @@
38
45
  "devDependencies": {
39
46
  "@ava/typescript": "^4.0.0",
40
47
  "@nomicfoundation/hardhat-ethers": "^3.0.5",
41
- "@openzeppelin/contracts": "4.8.3",
42
- "@openzeppelin/contracts-upgradeable": "4.8.3",
48
+ "@openzeppelin/contracts": "5.0.1",
49
+ "@openzeppelin/upgrades-core-legacy": "npm:@openzeppelin/upgrades-core@1.31.3",
43
50
  "@types/cbor": "^5.0.0",
44
51
  "@types/debug": "^4.1.5",
45
52
  "@types/mocha": "^7.0.2",
@@ -64,5 +71,5 @@
64
71
  "proper-lockfile": "^4.1.1",
65
72
  "solidity-ast": "^0.4.51"
66
73
  },
67
- "gitHead": "40943810bbb60721f9a1f2a566e5e17b96e63fbc"
74
+ "gitHead": "3b113ee12d1bb47cd3cf736f1c70b1302289e8d2"
68
75
  }
@@ -10,6 +10,7 @@ import { fetchOrDeploy, fetchOrDeployGetDeployment, mergeAddresses } from './imp
10
10
  import { getVersion } from './version';
11
11
  import { stubProvider } from './stub-provider';
12
12
  import { ImplDeployment } from './manifest';
13
+ import { RemoteDeploymentId } from './deployment';
13
14
 
14
15
  test.before(async () => {
15
16
  process.chdir(await fs.mkdtemp(path.join(os.tmpdir(), 'upgrades-core-test-')));
@@ -61,7 +62,7 @@ test('merge addresses', async t => {
61
62
  const depl1 = { address: '0x1' } as ImplDeployment;
62
63
  const depl2 = { address: '0x2' } as ImplDeployment;
63
64
 
64
- const { address, allAddresses } = await mergeAddresses(depl1, depl2);
65
+ const { address, allAddresses } = mergeAddresses(depl1, depl2);
65
66
  t.is(address, '0x1');
66
67
  t.true(unorderedEqual(allAddresses, ['0x1', '0x2']), allAddresses.toString());
67
68
  });
@@ -70,7 +71,7 @@ test('merge multiple existing addresses', async t => {
70
71
  const depl1 = { address: '0x1', allAddresses: ['0x1a', '0x1b'] } as ImplDeployment;
71
72
  const depl2 = { address: '0x2' } as ImplDeployment;
72
73
 
73
- const { address, allAddresses } = await mergeAddresses(depl1, depl2);
74
+ const { address, allAddresses } = mergeAddresses(depl1, depl2);
74
75
  t.is(address, '0x1');
75
76
  t.true(unorderedEqual(allAddresses, ['0x1', '0x1a', '0x1b', '0x2']), allAddresses.toString());
76
77
  });
@@ -79,7 +80,7 @@ test('merge all addresses', async t => {
79
80
  const depl1 = { address: '0x1', allAddresses: ['0x1a', '0x1b'] } as ImplDeployment;
80
81
  const depl2 = { address: '0x2', allAddresses: ['0x2a', '0x2b'] } as ImplDeployment;
81
82
 
82
- const { address, allAddresses } = await mergeAddresses(depl1, depl2);
83
+ const { address, allAddresses } = mergeAddresses(depl1, depl2);
83
84
  t.is(address, '0x1');
84
85
  t.true(unorderedEqual(allAddresses, ['0x1', '0x1a', '0x1b', '0x2', '0x2a', '0x2b']), allAddresses.toString());
85
86
  });
@@ -88,7 +89,7 @@ function unorderedEqual(arr1: string[], arr2: string[]) {
88
89
  return arr1.every(i => arr2.includes(i)) && arr2.every(i => arr1.includes(i));
89
90
  }
90
91
 
91
- test('platform - replace tx hash for deployment', async t => {
92
+ test('defender - replace tx hash for deployment', async t => {
92
93
  const provider = stubProvider();
93
94
 
94
95
  // create a pending deployment with id
@@ -137,3 +138,126 @@ test('platform - replace tx hash for deployment', async t => {
137
138
  t.is(deployment.address, fakeDeploy.address);
138
139
  t.is(deployment.txHash, '0x2');
139
140
  });
141
+
142
+ test('defender - address clash', async t => {
143
+ const provider = stubProvider();
144
+
145
+ // create a pending deployment with id
146
+ const fakeDeploy = await provider.deployPending();
147
+ provider.removeContract(fakeDeploy.address);
148
+
149
+ async function deployment1() {
150
+ return {
151
+ ...fakeDeploy,
152
+ txHash: '0x1',
153
+ remoteDeploymentId: 'abc',
154
+ };
155
+ }
156
+
157
+ const mockPendingDeployment = sinon.stub().returns({
158
+ status: 'submitted',
159
+ txHash: '0x1',
160
+ });
161
+ // let it timeout
162
+ await t.throwsAsync(
163
+ fetchOrDeployGetDeployment(
164
+ version1,
165
+ provider,
166
+ deployment1,
167
+ { timeout: 1, pollingInterval: 0 },
168
+ undefined,
169
+ mockPendingDeployment,
170
+ ),
171
+ );
172
+
173
+ // simulate a new deployment with the same address, but different tx hash and deployment id
174
+ async function deployment2() {
175
+ return {
176
+ ...fakeDeploy,
177
+ txHash: '0x2',
178
+ remoteDeploymentId: 'def',
179
+ };
180
+ }
181
+
182
+ // deploy with a different version hash
183
+ const error = await t.throwsAsync(
184
+ fetchOrDeployGetDeployment(
185
+ version2,
186
+ provider,
187
+ deployment2,
188
+ { timeout: 1, pollingInterval: 0 },
189
+ undefined,
190
+ mockPendingDeployment,
191
+ ),
192
+ );
193
+
194
+ t.true(
195
+ error?.message.startsWith(`The deployment clashes with an existing one at ${fakeDeploy.address}`),
196
+ error?.message,
197
+ );
198
+ });
199
+
200
+ test('defender - merge avoids address clash, replaces deployment id', async t => {
201
+ const provider = stubProvider();
202
+
203
+ const MERGE = true;
204
+
205
+ // create a pending deployment with id
206
+ const fakeDeploy = await provider.deployPending();
207
+ provider.removeContract(fakeDeploy.address);
208
+
209
+ async function deployment1() {
210
+ return {
211
+ ...fakeDeploy,
212
+ txHash: '0x1',
213
+ remoteDeploymentId: 'abc',
214
+ };
215
+ }
216
+
217
+ const getDeploymentResponse1 = sinon.stub().returns({
218
+ status: 'submitted',
219
+ txHash: '0x1',
220
+ });
221
+ // let it timeout
222
+ await t.throwsAsync(
223
+ fetchOrDeployGetDeployment(
224
+ version1,
225
+ provider,
226
+ deployment1,
227
+ { timeout: 1, pollingInterval: 0 },
228
+ MERGE,
229
+ getDeploymentResponse1,
230
+ ),
231
+ );
232
+
233
+ // simulate a failed previous deployment
234
+ const getDeploymentResponse2 = sinon.stub().returns({
235
+ status: 'failed',
236
+ txHash: '0x1',
237
+ });
238
+
239
+ // redeploy with a new deployment id
240
+ async function deployment2() {
241
+ return {
242
+ ...fakeDeploy,
243
+ txHash: '0x2',
244
+ remoteDeploymentId: 'def',
245
+ };
246
+ }
247
+
248
+ // make the contract code exist
249
+ provider.addContract(fakeDeploy.address);
250
+
251
+ const deployment = await fetchOrDeployGetDeployment(
252
+ version1,
253
+ provider,
254
+ deployment2,
255
+ { timeout: 1, pollingInterval: 0 },
256
+ MERGE,
257
+ getDeploymentResponse2,
258
+ );
259
+
260
+ t.is(deployment.address, fakeDeploy.address);
261
+ t.is(deployment.txHash, '0x2');
262
+ t.is((deployment as RemoteDeploymentId).remoteDeploymentId, 'def');
263
+ });
package/src/impl-store.ts CHANGED
@@ -72,12 +72,10 @@ async function fetchOrDeployGeneric<T extends Deployment, U extends T = T>(
72
72
  );
73
73
  if (updated !== stored) {
74
74
  if (merge && deployment.merge) {
75
- // only check primary addresses for clashes, since the address could already exist in an allAddresses field
76
- // but the above updated and stored objects are different instances representing the same entry
77
- await checkForAddressClash(provider, data, updated, false);
75
+ await checkForAddressClash(provider, data, updated, true);
78
76
  deployment.merge(updated);
79
77
  } else {
80
- await checkForAddressClash(provider, data, updated, true);
78
+ await checkForAddressClash(provider, data, updated, false);
81
79
  deployment.set(updated);
82
80
  }
83
81
  await manifest.write(data);
@@ -172,12 +170,17 @@ export async function fetchOrDeployGetDeployment<T extends ImplDeployment>(
172
170
  const implLens = (versionWithoutMetadata: string) =>
173
171
  lens(`implementation ${versionWithoutMetadata}`, 'implementation', data => ({
174
172
  get: () => data.impls[versionWithoutMetadata],
175
- set: (value?: ImplDeployment) => (data.impls[versionWithoutMetadata] = value),
176
- merge: (value?: ImplDeployment) => {
173
+ set: (value?: ImplDeployment & RemoteDeploymentId) => (data.impls[versionWithoutMetadata] = value),
174
+ merge: (value?: ImplDeployment & RemoteDeploymentId) => {
177
175
  const existing = data.impls[versionWithoutMetadata];
178
176
  if (existing !== undefined && value !== undefined) {
179
177
  const { address, allAddresses } = mergeAddresses(existing, value);
180
- data.impls[versionWithoutMetadata] = { ...existing, address, allAddresses };
178
+ data.impls[versionWithoutMetadata] = {
179
+ ...existing,
180
+ address,
181
+ allAddresses,
182
+ remoteDeploymentId: value.remoteDeploymentId,
183
+ };
181
184
  } else {
182
185
  data.impls[versionWithoutMetadata] = value;
183
186
  }
@@ -223,14 +226,23 @@ async function checkForAddressClash(
223
226
  provider: EthereumProvider,
224
227
  data: ManifestData,
225
228
  updated: Deployment & RemoteDeploymentId,
226
- checkAllAddresses: boolean,
229
+ merge: boolean,
227
230
  ): Promise<void> {
228
- const clash = lookupDeployment(data, updated.address, checkAllAddresses);
229
- if (clash !== undefined) {
230
- if (await isDevelopmentNetwork(provider)) {
231
+ let clash;
232
+ const findClash = () => lookupDeployment(data, updated.address, !merge);
233
+
234
+ if (await isDevelopmentNetwork(provider)) {
235
+ // Look for clashes so that we can delete deployments from older runs.
236
+ // `merge` only checks primary addresses for clashes, since the address could already exist in an allAddresses field
237
+ // but the updated and stored objects are different instances representing the same entry.
238
+ clash = findClash();
239
+ if (clash !== undefined) {
231
240
  debug('deleting a previous deployment at address', updated.address);
232
241
  clash.set(undefined);
233
- } else {
242
+ }
243
+ } else if (!merge) {
244
+ clash = findClash();
245
+ if (clash !== undefined) {
234
246
  const existing = clash.get();
235
247
  // it's a clash if there is no deployment id or if deployment ids don't match
236
248
  if (
@@ -238,13 +250,12 @@ async function checkForAddressClash(
238
250
  (existing.remoteDeploymentId === undefined || existing.remoteDeploymentId !== updated.remoteDeploymentId)
239
251
  ) {
240
252
  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`,
253
+ `The deployment clashes with an existing one at ${updated.address}.\n\n` +
254
+ `Deployments: ${JSON.stringify({ existing, updated }, null, 2)}\n\n`,
244
255
  );
245
256
  }
246
257
  }
247
- }
258
+ } // else, merge indicates that the user is force-importing or redeploying an implementation, so we simply allow merging the entries
248
259
  }
249
260
 
250
261
  function lookupDeployment(
package/src/index.ts CHANGED
@@ -53,6 +53,7 @@ export {
53
53
  NoContractImportError,
54
54
  ValidateUpdateRequiresKindError,
55
55
  PrepareUpgradeRequiresKindError,
56
+ InitialOwnerUnsupportedKindError,
56
57
  assertNotProxy,
57
58
  } from './usage-error';
58
59
 
@@ -0,0 +1 @@
1
+ "0.8.20"
@@ -1,6 +1,8 @@
1
1
  import _test, { TestFn } from 'ava';
2
2
  import { artifacts } from 'hardhat';
3
3
 
4
+ import SOLIDITY_VERSION from './solidity-version.json';
5
+
4
6
  import { SolcInput, SolcOutput } from './solc-api';
5
7
  import { UpgradeableContract } from './standalone';
6
8
 
@@ -21,7 +23,7 @@ test.before(async t => {
21
23
  });
22
24
 
23
25
  test('reports unsafe operation', t => {
24
- const impl = new UpgradeableContract('StandaloneV1', t.context.solcInput, t.context.solcOutput);
26
+ const impl = new UpgradeableContract('StandaloneV1', t.context.solcInput, t.context.solcOutput, {}, SOLIDITY_VERSION);
25
27
  const report = impl.getErrorReport();
26
28
  t.false(report.ok);
27
29
  t.true(report.errors[0].kind === 'delegatecall');
@@ -32,6 +34,8 @@ test('reports unsafe operation - fully qualified name', t => {
32
34
  'contracts/test/Standalone.sol:StandaloneV1',
33
35
  t.context.solcInput,
34
36
  t.context.solcOutput,
37
+ {},
38
+ SOLIDITY_VERSION,
35
39
  );
36
40
  const report = impl.getErrorReport();
37
41
  t.false(report.ok);
@@ -39,25 +43,55 @@ test('reports unsafe operation - fully qualified name', t => {
39
43
  });
40
44
 
41
45
  test('reports storage upgrade errors', t => {
42
- const v1 = new UpgradeableContract('StandaloneV1', t.context.solcInput, t.context.solcOutput);
46
+ const v1 = new UpgradeableContract('StandaloneV1', t.context.solcInput, t.context.solcOutput, {}, SOLIDITY_VERSION);
43
47
 
44
- const v2Good = new UpgradeableContract('StandaloneV2Good', t.context.solcInput, t.context.solcOutput);
48
+ const v2Good = new UpgradeableContract(
49
+ 'StandaloneV2Good',
50
+ t.context.solcInput,
51
+ t.context.solcOutput,
52
+ {},
53
+ SOLIDITY_VERSION,
54
+ );
45
55
  const goodReport = v1.getStorageUpgradeReport(v2Good);
46
56
  t.true(goodReport.ok);
47
57
 
48
- const v2Bad = new UpgradeableContract('StandaloneV2Bad', t.context.solcInput, t.context.solcOutput);
58
+ const v2Bad = new UpgradeableContract(
59
+ 'StandaloneV2Bad',
60
+ t.context.solcInput,
61
+ t.context.solcOutput,
62
+ {},
63
+ SOLIDITY_VERSION,
64
+ );
49
65
  const badReport = v1.getStorageUpgradeReport(v2Bad);
50
66
  t.false(badReport.ok);
51
67
  });
52
68
 
53
69
  test('dont report renamed version update', t => {
54
- const v1 = new UpgradeableContract('StandaloneRenameV1', t.context.solcInput, t.context.solcOutput);
70
+ const v1 = new UpgradeableContract(
71
+ 'StandaloneRenameV1',
72
+ t.context.solcInput,
73
+ t.context.solcOutput,
74
+ {},
75
+ SOLIDITY_VERSION,
76
+ );
55
77
 
56
- const v2 = new UpgradeableContract('StandaloneRenameV2', t.context.solcInput, t.context.solcOutput);
78
+ const v2 = new UpgradeableContract(
79
+ 'StandaloneRenameV2',
80
+ t.context.solcInput,
81
+ t.context.solcOutput,
82
+ {},
83
+ SOLIDITY_VERSION,
84
+ );
57
85
  const goodReport = v1.getStorageUpgradeReport(v2);
58
86
  t.true(goodReport.ok);
59
87
 
60
- const v3 = new UpgradeableContract('StandaloneRenameV3', t.context.solcInput, t.context.solcOutput);
88
+ const v3 = new UpgradeableContract(
89
+ 'StandaloneRenameV3',
90
+ t.context.solcInput,
91
+ t.context.solcOutput,
92
+ {},
93
+ SOLIDITY_VERSION,
94
+ );
61
95
  const goodReport2 = v2.getStorageUpgradeReport(v3);
62
96
  t.true(goodReport2.ok);
63
97
  });
@@ -95,6 +95,15 @@ export class PrepareUpgradeRequiresKindError extends UpgradesError {
95
95
  }
96
96
  }
97
97
 
98
+ export class InitialOwnerUnsupportedKindError extends UpgradesError {
99
+ constructor(kind: string) {
100
+ super(
101
+ `The \`initialOwner\` option is not supported for this kind of proxy ('${kind}')`,
102
+ () => `Set the initial owner as part of your contract's initializer arguments instead.`,
103
+ );
104
+ }
105
+ }
106
+
98
107
  export async function assertNotProxy(provider: EthereumProvider, address: string) {
99
108
  if (await isTransparentOrUUPSProxy(provider, address)) {
100
109
  throw new UpgradesError(
@@ -1,4 +0,0 @@
1
- {
2
- "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../../../build-info/966b1f437e942115ba46359eb293018c.json"
4
- }
@@ -1,4 +0,0 @@
1
- {
2
- "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../../../build-info/966b1f437e942115ba46359eb293018c.json"
4
- }
@@ -1,4 +0,0 @@
1
- {
2
- "_format": "hh-sol-dbg-1",
3
- "buildInfo": "../../../../../build-info/966b1f437e942115ba46359eb293018c.json"
4
- }