@openzeppelin/upgrades-core 1.9.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 (336) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.dbg.json +4 -0
  3. package/artifacts/@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol/ERC1967Proxy.json +80 -0
  4. package/artifacts/@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol/ProxyAdmin.json +160 -0
  5. package/artifacts/@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json +155 -0
  6. package/artifacts/AdminUpgradeabilityProxy.json +155 -0
  7. package/artifacts/ProxyAdmin.json +160 -0
  8. package/artifacts/contracts/proxy/AdminUpgradeabilityProxy.sol/AdminUpgradeabilityProxy.json +155 -0
  9. package/artifacts/contracts/proxy/ProxyAdmin.sol/ProxyAdmin.json +160 -0
  10. package/contracts/Initializable.sol +64 -0
  11. package/dist/ast-dereferencer.d.ts +8 -0
  12. package/dist/ast-dereferencer.d.ts.map +1 -0
  13. package/dist/ast-dereferencer.js +29 -0
  14. package/dist/ast-dereferencer.js.map +1 -0
  15. package/dist/deployment.d.ts +18 -0
  16. package/dist/deployment.d.ts.map +1 -0
  17. package/dist/deployment.js +110 -0
  18. package/dist/deployment.js.map +1 -0
  19. package/dist/deployment.test.d.ts +2 -0
  20. package/dist/deployment.test.d.ts.map +1 -0
  21. package/dist/deployment.test.js +92 -0
  22. package/dist/deployment.test.js.map +1 -0
  23. package/dist/eip-1967.d.ts +7 -0
  24. package/dist/eip-1967.d.ts.map +1 -0
  25. package/dist/eip-1967.js +63 -0
  26. package/dist/eip-1967.js.map +1 -0
  27. package/dist/error.d.ts +21 -0
  28. package/dist/error.d.ts.map +1 -0
  29. package/dist/error.js +21 -0
  30. package/dist/error.js.map +1 -0
  31. package/dist/impl-store.d.ts +7 -0
  32. package/dist/impl-store.d.ts.map +1 -0
  33. package/dist/impl-store.js +94 -0
  34. package/dist/impl-store.js.map +1 -0
  35. package/dist/impl-store.test.d.ts +2 -0
  36. package/dist/impl-store.test.d.ts.map +1 -0
  37. package/dist/impl-store.test.js +55 -0
  38. package/dist/impl-store.test.js.map +1 -0
  39. package/dist/index.d.ts +16 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +32 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/levenshtein.d.ts +12 -0
  44. package/dist/levenshtein.d.ts.map +1 -0
  45. package/dist/levenshtein.js +89 -0
  46. package/dist/levenshtein.js.map +1 -0
  47. package/dist/levenshtein.test.d.ts +2 -0
  48. package/dist/levenshtein.test.d.ts.map +1 -0
  49. package/dist/levenshtein.test.js +88 -0
  50. package/dist/levenshtein.test.js.map +1 -0
  51. package/dist/link-refs.d.ts +11 -0
  52. package/dist/link-refs.d.ts.map +1 -0
  53. package/dist/link-refs.js +36 -0
  54. package/dist/link-refs.js.map +1 -0
  55. package/dist/link-refs.test.d.ts +2 -0
  56. package/dist/link-refs.test.d.ts.map +1 -0
  57. package/dist/link-refs.test.js +76 -0
  58. package/dist/link-refs.test.js.map +1 -0
  59. package/dist/manifest-storage-layout.d.ts +6 -0
  60. package/dist/manifest-storage-layout.d.ts.map +1 -0
  61. package/dist/manifest-storage-layout.js +95 -0
  62. package/dist/manifest-storage-layout.js.map +1 -0
  63. package/dist/manifest-storage-layout.test.d.ts +2 -0
  64. package/dist/manifest-storage-layout.test.d.ts.map +1 -0
  65. package/dist/manifest-storage-layout.test.js +105 -0
  66. package/dist/manifest-storage-layout.test.js.map +1 -0
  67. package/dist/manifest.d.ts +36 -0
  68. package/dist/manifest.d.ts.map +1 -0
  69. package/dist/manifest.js +154 -0
  70. package/dist/manifest.js.map +1 -0
  71. package/dist/manifest.test.d.ts +2 -0
  72. package/dist/manifest.test.d.ts.map +1 -0
  73. package/dist/manifest.test.js +17 -0
  74. package/dist/manifest.test.js.map +1 -0
  75. package/dist/provider.d.ts +37 -0
  76. package/dist/provider.d.ts.map +1 -0
  77. package/dist/provider.js +74 -0
  78. package/dist/provider.js.map +1 -0
  79. package/dist/provider.test.d.ts +2 -0
  80. package/dist/provider.test.d.ts.map +1 -0
  81. package/dist/provider.test.js +41 -0
  82. package/dist/provider.test.js.map +1 -0
  83. package/dist/scripts/migrate-oz-cli-project.d.ts +108 -0
  84. package/dist/scripts/migrate-oz-cli-project.d.ts.map +1 -0
  85. package/dist/scripts/migrate-oz-cli-project.js +321 -0
  86. package/dist/scripts/migrate-oz-cli-project.js.map +1 -0
  87. package/dist/scripts/migrate-oz-cli-project.test.d.ts +2 -0
  88. package/dist/scripts/migrate-oz-cli-project.test.d.ts.map +1 -0
  89. package/dist/scripts/migrate-oz-cli-project.test.js +60 -0
  90. package/dist/scripts/migrate-oz-cli-project.test.js.map +1 -0
  91. package/dist/set-proxy-kind.d.ts +5 -0
  92. package/dist/set-proxy-kind.d.ts.map +1 -0
  93. package/dist/set-proxy-kind.js +25 -0
  94. package/dist/set-proxy-kind.js.map +1 -0
  95. package/dist/solc-api.d.ts +39 -0
  96. package/dist/solc-api.d.ts.map +1 -0
  97. package/dist/solc-api.js +3 -0
  98. package/dist/solc-api.js.map +1 -0
  99. package/dist/src-decoder.d.ts +6 -0
  100. package/dist/src-decoder.d.ts.map +1 -0
  101. package/dist/src-decoder.js +36 -0
  102. package/dist/src-decoder.js.map +1 -0
  103. package/dist/src-decoder.test.d.ts +2 -0
  104. package/dist/src-decoder.test.d.ts.map +1 -0
  105. package/dist/src-decoder.test.js +29 -0
  106. package/dist/src-decoder.test.js.map +1 -0
  107. package/dist/storage/compare.d.ts +55 -0
  108. package/dist/storage/compare.d.ts.map +1 -0
  109. package/dist/storage/compare.js +181 -0
  110. package/dist/storage/compare.js.map +1 -0
  111. package/dist/storage/compat.d.ts +4 -0
  112. package/dist/storage/compat.d.ts.map +1 -0
  113. package/dist/storage/compat.js +9 -0
  114. package/dist/storage/compat.js.map +1 -0
  115. package/dist/storage/extract.d.ts +7 -0
  116. package/dist/storage/extract.d.ts.map +1 -0
  117. package/dist/storage/extract.js +86 -0
  118. package/dist/storage/extract.js.map +1 -0
  119. package/dist/storage/index.d.ts +8 -0
  120. package/dist/storage/index.d.ts.map +1 -0
  121. package/dist/storage/index.js +65 -0
  122. package/dist/storage/index.js.map +1 -0
  123. package/dist/storage/layout.d.ts +31 -0
  124. package/dist/storage/layout.d.ts.map +1 -0
  125. package/dist/storage/layout.js +46 -0
  126. package/dist/storage/layout.js.map +1 -0
  127. package/dist/storage/report.d.ts +8 -0
  128. package/dist/storage/report.d.ts.map +1 -0
  129. package/dist/storage/report.js +175 -0
  130. package/dist/storage/report.js.map +1 -0
  131. package/dist/storage/report.test.d.ts +2 -0
  132. package/dist/storage/report.test.d.ts.map +1 -0
  133. package/dist/storage/report.test.js +82 -0
  134. package/dist/storage/report.test.js.map +1 -0
  135. package/dist/storage.test.d.ts +2 -0
  136. package/dist/storage.test.d.ts.map +1 -0
  137. package/dist/storage.test.js +436 -0
  138. package/dist/storage.test.js.map +1 -0
  139. package/dist/stub-provider.d.ts +14 -0
  140. package/dist/stub-provider.d.ts.map +1 -0
  141. package/dist/stub-provider.js +128 -0
  142. package/dist/stub-provider.js.map +1 -0
  143. package/dist/utils/assert.d.ts +3 -0
  144. package/dist/utils/assert.d.ts.map +1 -0
  145. package/dist/utils/assert.js +14 -0
  146. package/dist/utils/assert.js.map +1 -0
  147. package/dist/utils/curry.d.ts +6 -0
  148. package/dist/utils/curry.d.ts.map +1 -0
  149. package/dist/utils/curry.js +16 -0
  150. package/dist/utils/curry.js.map +1 -0
  151. package/dist/utils/debug.d.ts +4 -0
  152. package/dist/utils/debug.d.ts.map +1 -0
  153. package/dist/utils/debug.js +8 -0
  154. package/dist/utils/debug.js.map +1 -0
  155. package/dist/utils/deep-array.d.ts +3 -0
  156. package/dist/utils/deep-array.d.ts.map +1 -0
  157. package/dist/utils/deep-array.js +13 -0
  158. package/dist/utils/deep-array.js.map +1 -0
  159. package/dist/utils/deep-array.test.d.ts +2 -0
  160. package/dist/utils/deep-array.test.d.ts.map +1 -0
  161. package/dist/utils/deep-array.test.js +23 -0
  162. package/dist/utils/deep-array.test.js.map +1 -0
  163. package/dist/utils/function.d.ts +4 -0
  164. package/dist/utils/function.d.ts.map +1 -0
  165. package/dist/utils/function.js +43 -0
  166. package/dist/utils/function.js.map +1 -0
  167. package/dist/utils/function.test.d.ts +2 -0
  168. package/dist/utils/function.test.d.ts.map +1 -0
  169. package/dist/utils/function.test.js +34 -0
  170. package/dist/utils/function.test.js.map +1 -0
  171. package/dist/utils/indent.d.ts +2 -0
  172. package/dist/utils/indent.d.ts.map +1 -0
  173. package/dist/utils/indent.js +8 -0
  174. package/dist/utils/indent.js.map +1 -0
  175. package/dist/utils/is-nullish.d.ts +2 -0
  176. package/dist/utils/is-nullish.d.ts.map +1 -0
  177. package/dist/utils/is-nullish.js +8 -0
  178. package/dist/utils/is-nullish.js.map +1 -0
  179. package/dist/utils/is-nullish.test.d.ts +2 -0
  180. package/dist/utils/is-nullish.test.d.ts.map +1 -0
  181. package/dist/utils/is-nullish.test.js +17 -0
  182. package/dist/utils/is-nullish.test.js.map +1 -0
  183. package/dist/utils/is-value-type.d.ts +3 -0
  184. package/dist/utils/is-value-type.d.ts.map +1 -0
  185. package/dist/utils/is-value-type.js +8 -0
  186. package/dist/utils/is-value-type.js.map +1 -0
  187. package/dist/utils/itemize.d.ts +3 -0
  188. package/dist/utils/itemize.d.ts.map +1 -0
  189. package/dist/utils/itemize.js +18 -0
  190. package/dist/utils/itemize.js.map +1 -0
  191. package/dist/utils/log.d.ts +4 -0
  192. package/dist/utils/log.d.ts.map +1 -0
  193. package/dist/utils/log.js +35 -0
  194. package/dist/utils/log.js.map +1 -0
  195. package/dist/utils/make-non-enumerable.d.ts +2 -0
  196. package/dist/utils/make-non-enumerable.d.ts.map +1 -0
  197. package/dist/utils/make-non-enumerable.js +9 -0
  198. package/dist/utils/make-non-enumerable.js.map +1 -0
  199. package/dist/utils/map-values.d.ts +2 -0
  200. package/dist/utils/map-values.d.ts.map +1 -0
  201. package/dist/utils/map-values.js +12 -0
  202. package/dist/utils/map-values.js.map +1 -0
  203. package/dist/utils/parse-type-id.d.ts +9 -0
  204. package/dist/utils/parse-type-id.d.ts.map +1 -0
  205. package/dist/utils/parse-type-id.js +92 -0
  206. package/dist/utils/parse-type-id.js.map +1 -0
  207. package/dist/utils/parse-type-id.test.d.ts +2 -0
  208. package/dist/utils/parse-type-id.test.d.ts.map +1 -0
  209. package/dist/utils/parse-type-id.test.js +25 -0
  210. package/dist/utils/parse-type-id.test.js.map +1 -0
  211. package/dist/utils/pick.d.ts +2 -0
  212. package/dist/utils/pick.d.ts.map +1 -0
  213. package/dist/utils/pick.js +12 -0
  214. package/dist/utils/pick.js.map +1 -0
  215. package/dist/utils/type-id.d.ts +4 -0
  216. package/dist/utils/type-id.d.ts.map +1 -0
  217. package/dist/utils/type-id.js +65 -0
  218. package/dist/utils/type-id.js.map +1 -0
  219. package/dist/validate/compat.d.ts +6 -0
  220. package/dist/validate/compat.d.ts.map +1 -0
  221. package/dist/validate/compat.js +4 -0
  222. package/dist/validate/compat.js.map +1 -0
  223. package/dist/validate/data.d.ts +14 -0
  224. package/dist/validate/data.d.ts.map +1 -0
  225. package/dist/validate/data.js +50 -0
  226. package/dist/validate/data.js.map +1 -0
  227. package/dist/validate/error.d.ts +7 -0
  228. package/dist/validate/error.d.ts.map +1 -0
  229. package/dist/validate/error.js +78 -0
  230. package/dist/validate/error.js.map +1 -0
  231. package/dist/validate/index.d.ts +8 -0
  232. package/dist/validate/index.d.ts.map +1 -0
  233. package/dist/validate/index.js +24 -0
  234. package/dist/validate/index.js.map +1 -0
  235. package/dist/validate/overrides.d.ts +14 -0
  236. package/dist/validate/overrides.d.ts.map +1 -0
  237. package/dist/validate/overrides.js +72 -0
  238. package/dist/validate/overrides.js.map +1 -0
  239. package/dist/validate/query.d.ts +15 -0
  240. package/dist/validate/query.d.ts.map +1 -0
  241. package/dist/validate/query.js +111 -0
  242. package/dist/validate/query.js.map +1 -0
  243. package/dist/validate/query.test.d.ts +2 -0
  244. package/dist/validate/query.test.d.ts.map +1 -0
  245. package/dist/validate/query.test.js +48 -0
  246. package/dist/validate/query.test.js.map +1 -0
  247. package/dist/validate/run.d.ts +39 -0
  248. package/dist/validate/run.d.ts.map +1 -0
  249. package/dist/validate/run.js +199 -0
  250. package/dist/validate/run.js.map +1 -0
  251. package/dist/validate.test.d.ts +2 -0
  252. package/dist/validate.test.d.ts.map +1 -0
  253. package/dist/validate.test.js +116 -0
  254. package/dist/validate.test.js.map +1 -0
  255. package/dist/version.d.ts +9 -0
  256. package/dist/version.d.ts.map +1 -0
  257. package/dist/version.js +66 -0
  258. package/dist/version.js.map +1 -0
  259. package/dist/version.test.d.ts +2 -0
  260. package/dist/version.test.d.ts.map +1 -0
  261. package/dist/version.test.js +53 -0
  262. package/dist/version.test.js.map +1 -0
  263. package/package.json +58 -0
  264. package/src/ast-dereferencer.ts +42 -0
  265. package/src/deployment.test.ts +98 -0
  266. package/src/deployment.ts +122 -0
  267. package/src/eip-1967.ts +77 -0
  268. package/src/error.ts +26 -0
  269. package/src/impl-store.test.ts +59 -0
  270. package/src/impl-store.ts +124 -0
  271. package/src/index.ts +18 -0
  272. package/src/levenshtein.test.ts +91 -0
  273. package/src/levenshtein.ts +116 -0
  274. package/src/link-refs.test.ts +77 -0
  275. package/src/link-refs.ts +41 -0
  276. package/src/manifest-storage-layout.test.ts +118 -0
  277. package/src/manifest-storage-layout.ts +107 -0
  278. package/src/manifest.test.ts +13 -0
  279. package/src/manifest.ts +178 -0
  280. package/src/provider.test.ts +43 -0
  281. package/src/provider.ts +103 -0
  282. package/src/scripts/migratable-manifest.test.json +175 -0
  283. package/src/scripts/migrate-oz-cli-project.test.ts +70 -0
  284. package/src/scripts/migrate-oz-cli-project.test.ts.md +146 -0
  285. package/src/scripts/migrate-oz-cli-project.test.ts.snap +0 -0
  286. package/src/scripts/migrate-oz-cli-project.ts +484 -0
  287. package/src/scripts/project-file.test.json +25 -0
  288. package/src/set-proxy-kind.ts +27 -0
  289. package/src/solc-api.ts +42 -0
  290. package/src/src-decoder.test.ts +30 -0
  291. package/src/src-decoder.ts +37 -0
  292. package/src/storage/compare.ts +249 -0
  293. package/src/storage/compat.ts +3 -0
  294. package/src/storage/extract.ts +110 -0
  295. package/src/storage/index.ts +73 -0
  296. package/src/storage/layout.ts +88 -0
  297. package/src/storage/report.test.ts +95 -0
  298. package/src/storage/report.test.ts.md +154 -0
  299. package/src/storage/report.test.ts.snap +0 -0
  300. package/src/storage/report.ts +215 -0
  301. package/src/storage.test.ts +479 -0
  302. package/src/storage.test.ts.md +643 -0
  303. package/src/storage.test.ts.snap +0 -0
  304. package/src/stub-provider.ts +120 -0
  305. package/src/utils/assert.ts +9 -0
  306. package/src/utils/curry.ts +17 -0
  307. package/src/utils/debug.ts +3 -0
  308. package/src/utils/deep-array.test.ts +21 -0
  309. package/src/utils/deep-array.ts +9 -0
  310. package/src/utils/function.test.ts +37 -0
  311. package/src/utils/function.ts +53 -0
  312. package/src/utils/indent.ts +3 -0
  313. package/src/utils/is-nullish.test.ts +15 -0
  314. package/src/utils/is-nullish.ts +3 -0
  315. package/src/utils/is-value-type.ts +5 -0
  316. package/src/utils/itemize.ts +16 -0
  317. package/src/utils/log.ts +34 -0
  318. package/src/utils/make-non-enumerable.ts +4 -0
  319. package/src/utils/map-values.ts +7 -0
  320. package/src/utils/parse-type-id.test.ts +22 -0
  321. package/src/utils/parse-type-id.test.ts.md +264 -0
  322. package/src/utils/parse-type-id.test.ts.snap +0 -0
  323. package/src/utils/parse-type-id.ts +104 -0
  324. package/src/utils/pick.ts +7 -0
  325. package/src/utils/type-id.ts +57 -0
  326. package/src/validate/compat.ts +9 -0
  327. package/src/validate/data.ts +55 -0
  328. package/src/validate/error.ts +75 -0
  329. package/src/validate/index.ts +17 -0
  330. package/src/validate/overrides.ts +93 -0
  331. package/src/validate/query.test.ts +48 -0
  332. package/src/validate/query.ts +127 -0
  333. package/src/validate/run.ts +278 -0
  334. package/src/validate.test.ts +133 -0
  335. package/src/version.test.ts +59 -0
  336. package/src/version.ts +71 -0
@@ -0,0 +1,25 @@
1
+ {
2
+ "manifestVersion": "2.2",
3
+ "contracts": {
4
+ "Box": "Box"
5
+ },
6
+ "dependencies": {},
7
+ "name": "my-project",
8
+ "version": "1.0.0",
9
+ "compiler": {
10
+ "compilerSettings": {
11
+ "optimizer": {
12
+ "enabled": false,
13
+ "runs": "200"
14
+ }
15
+ },
16
+ "typechain": {
17
+ "enabled": false
18
+ },
19
+ "manager": "openzeppelin",
20
+ "solcVersion": "0.6.12",
21
+ "artifactsDir": "build/contracts",
22
+ "contractsDir": "contracts"
23
+ },
24
+ "telemetryOptIn": false
25
+ }
@@ -0,0 +1,27 @@
1
+ import { EthereumProvider } from './provider';
2
+ import { ValidationOptions } from './validate';
3
+ import { Manifest, DeploymentNotFound, ProxyDeployment } from './manifest';
4
+
5
+ export async function setProxyKind(
6
+ provider: EthereumProvider,
7
+ proxyAddress: string,
8
+ opts: ValidationOptions,
9
+ ): Promise<ProxyDeployment['kind']> {
10
+ const manifest = await Manifest.forNetwork(provider);
11
+
12
+ const manifestDeployment = await manifest.getProxyFromAddress(proxyAddress).catch(e => {
13
+ if (e instanceof DeploymentNotFound) {
14
+ return undefined;
15
+ } else {
16
+ throw e;
17
+ }
18
+ });
19
+
20
+ if (opts.kind === undefined) {
21
+ opts.kind = manifestDeployment?.kind ?? 'transparent';
22
+ } else if (manifestDeployment && opts.kind !== manifestDeployment.kind) {
23
+ throw new Error(`Requested an upgrade of kind ${opts.kind} but proxy is ${manifestDeployment.kind}`);
24
+ }
25
+
26
+ return opts.kind;
27
+ }
@@ -0,0 +1,42 @@
1
+ import type { SourceUnit } from 'solidity-ast';
2
+
3
+ export interface SolcOutput {
4
+ contracts: {
5
+ [file in string]: {
6
+ [contract in string]: {
7
+ evm: {
8
+ bytecode: SolcBytecode;
9
+ methodIdentifiers?: Record<string, string>;
10
+ };
11
+ };
12
+ };
13
+ };
14
+ sources: {
15
+ [file in string]: {
16
+ ast: SourceUnit;
17
+ id: number;
18
+ };
19
+ };
20
+ }
21
+
22
+ export interface SolcInput {
23
+ sources: {
24
+ [source in string]: {
25
+ content?: string;
26
+ };
27
+ };
28
+ }
29
+
30
+ export type SolcLinkReferences = {
31
+ [file in string]: {
32
+ [library in string]: {
33
+ length: number;
34
+ start: number;
35
+ }[];
36
+ };
37
+ };
38
+
39
+ export interface SolcBytecode {
40
+ linkReferences: SolcLinkReferences;
41
+ object: string;
42
+ }
@@ -0,0 +1,30 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+
3
+ import test from 'ava';
4
+
5
+ import { SolcInput, SolcOutput } from './solc-api';
6
+ import { solcInputOutputDecoder } from './src-decoder';
7
+
8
+ test('solcInputOutputDecoder', t => {
9
+ const solcInput: SolcInput = {
10
+ sources: {
11
+ 'a.sol': { content: '\n\n' },
12
+ 'b.sol': { content: '\n\n' },
13
+ },
14
+ };
15
+
16
+ const solcOutput: SolcOutput = {
17
+ contracts: {},
18
+ sources: {
19
+ 'a.sol': { id: 0, ast: undefined as any },
20
+ 'b.sol': { id: 1, ast: undefined as any },
21
+ },
22
+ };
23
+
24
+ const decodeSrc = solcInputOutputDecoder(solcInput, solcOutput);
25
+
26
+ t.is(decodeSrc({ src: '0:0:0' }), 'a.sol:1');
27
+ t.is(decodeSrc({ src: '1:0:0' }), 'a.sol:2');
28
+ t.is(decodeSrc({ src: '1:0:1' }), 'b.sol:2');
29
+ t.is(decodeSrc({ src: '2:0:1' }), 'b.sol:3');
30
+ });
@@ -0,0 +1,37 @@
1
+ import path from 'path';
2
+ import { SolcOutput, SolcInput } from './solc-api';
3
+
4
+ export type SrcDecoder = (node: { src: string }) => string;
5
+
6
+ interface Source {
7
+ name: string;
8
+ content: string;
9
+ }
10
+
11
+ export function solcInputOutputDecoder(solcInput: SolcInput, solcOutput: SolcOutput, basePath = '.'): SrcDecoder {
12
+ const sources: Record<number, Source> = {};
13
+
14
+ function getSource(sourceId: number): Source {
15
+ if (sourceId in sources) {
16
+ return sources[sourceId];
17
+ } else {
18
+ const sourcePath = Object.entries(solcOutput.sources).find(([, { id }]) => sourceId === id)?.[0];
19
+ if (sourcePath === undefined) {
20
+ throw new Error(`Source file not available`);
21
+ }
22
+ const content = solcInput.sources[sourcePath].content;
23
+ const name = path.relative(basePath, sourcePath);
24
+ if (content === undefined) {
25
+ throw new Error(`Content for ${name} not available`);
26
+ }
27
+ return (sources[sourceId] = { name, content });
28
+ }
29
+ }
30
+
31
+ return ({ src }) => {
32
+ const [begin, , sourceId] = src.split(':').map(Number);
33
+ const { name, content } = getSource(sourceId);
34
+ const line = content.substr(0, begin).split('\n').length;
35
+ return name + ':' + line;
36
+ };
37
+ }
@@ -0,0 +1,249 @@
1
+ import { levenshtein, Operation } from '../levenshtein';
2
+ import { ParsedTypeDetailed, StorageItem as _StorageItem } from './layout';
3
+ import { UpgradesError } from '../error';
4
+ import { StructMember as _StructMember, isEnumMembers, isStructMembers } from './layout';
5
+ import { LayoutCompatibilityReport } from './report';
6
+ import { assert } from '../utils/assert';
7
+ import { isValueType } from '../utils/is-value-type';
8
+
9
+ export type StorageItem = _StorageItem<ParsedTypeDetailed>;
10
+ type StructMember = _StructMember<ParsedTypeDetailed>;
11
+
12
+ export type StorageField = StorageItem | StructMember;
13
+ export type StorageOperation<F extends StorageField> = Operation<F, StorageFieldChange<F>>;
14
+
15
+ export type EnumOperation = Operation<string, { kind: 'replace'; original: string; updated: string }>;
16
+
17
+ type StorageFieldChange<F extends StorageField> = (
18
+ | { kind: 'replace' | 'rename' }
19
+ | { kind: 'typechange'; change: TypeChange }
20
+ ) & {
21
+ original: F;
22
+ updated: F;
23
+ };
24
+
25
+ export type TypeChange = (
26
+ | {
27
+ kind:
28
+ | 'obvious mismatch'
29
+ | 'unknown'
30
+ | 'array grow'
31
+ | 'array shrink'
32
+ | 'array dynamic'
33
+ | 'enum resize'
34
+ | 'missing members';
35
+ }
36
+ | {
37
+ kind: 'mapping key' | 'mapping value' | 'array value';
38
+ inner: TypeChange;
39
+ }
40
+ | {
41
+ kind: 'enum members';
42
+ ops: EnumOperation[];
43
+ }
44
+ | {
45
+ kind: 'struct members';
46
+ ops: StorageOperation<StructMember>[];
47
+ allowAppend: boolean;
48
+ }
49
+ ) & {
50
+ original: ParsedTypeDetailed;
51
+ updated: ParsedTypeDetailed;
52
+ };
53
+
54
+ export class StorageLayoutComparator {
55
+ hasAllowedUncheckedCustomTypes = false;
56
+
57
+ // Holds a stack of type comparisons to detect recursion
58
+ stack = new Set<string>();
59
+ cache = new Map<string, TypeChange | undefined>();
60
+
61
+ constructor(readonly unsafeAllowCustomTypes = false, readonly unsafeAllowRenames = false) {}
62
+
63
+ compareLayouts(original: StorageItem[], updated: StorageItem[]): LayoutCompatibilityReport {
64
+ return new LayoutCompatibilityReport(this.layoutLevenshtein(original, updated, { allowAppend: true }));
65
+ }
66
+
67
+ private layoutLevenshtein<F extends StorageField>(
68
+ original: F[],
69
+ updated: F[],
70
+ { allowAppend }: { allowAppend: boolean },
71
+ ): StorageOperation<F>[] {
72
+ const ops = levenshtein(original, updated, (a, b) => this.getFieldChange(a, b));
73
+
74
+ if (allowAppend) {
75
+ return ops.filter(o => o.kind !== 'append');
76
+ } else {
77
+ return ops;
78
+ }
79
+ }
80
+
81
+ getFieldChange<F extends StorageField>(original: F, updated: F): StorageFieldChange<F> | undefined {
82
+ const nameChange = !this.unsafeAllowRenames && original.label !== updated.label;
83
+ const typeChange = this.getTypeChange(original.type, updated.type, { allowAppend: false });
84
+
85
+ if (typeChange && nameChange) {
86
+ return { kind: 'replace', original, updated };
87
+ } else if (nameChange) {
88
+ return { kind: 'rename', original, updated };
89
+ } else if (typeChange) {
90
+ return { kind: 'typechange', change: typeChange, original, updated };
91
+ }
92
+ }
93
+
94
+ getTypeChange(
95
+ original: ParsedTypeDetailed,
96
+ updated: ParsedTypeDetailed,
97
+ { allowAppend }: { allowAppend: boolean },
98
+ ): TypeChange | undefined {
99
+ const key = JSON.stringify({ original: original.id, updated: updated.id, allowAppend });
100
+
101
+ if (this.cache.has(key)) {
102
+ return this.cache.get(key);
103
+ }
104
+
105
+ if (this.stack.has(key)) {
106
+ throw new UpgradesError(`Recursive types are not supported`, () => `Recursion found in ${updated.item.label}\n`);
107
+ }
108
+
109
+ try {
110
+ this.stack.add(key);
111
+ const result = this.uncachedGetTypeChange(original, updated, { allowAppend });
112
+ this.cache.set(key, result);
113
+ return result;
114
+ } finally {
115
+ this.stack.delete(key);
116
+ }
117
+ }
118
+
119
+ private uncachedGetTypeChange(
120
+ original: ParsedTypeDetailed,
121
+ updated: ParsedTypeDetailed,
122
+ { allowAppend }: { allowAppend: boolean },
123
+ ): TypeChange | undefined {
124
+ if (original.head !== updated.head) {
125
+ return { kind: 'obvious mismatch', original, updated };
126
+ }
127
+
128
+ if (original.args === undefined || updated.args === undefined) {
129
+ // both should be undefined at the same time
130
+ assert(original.args === updated.args);
131
+ return undefined;
132
+ }
133
+
134
+ switch (original.head) {
135
+ case 't_contract':
136
+ // no storage layout errors can be introduced here since it is just an address
137
+ return undefined;
138
+
139
+ case 't_struct': {
140
+ const originalMembers = original.item.members;
141
+ const updatedMembers = updated.item.members;
142
+ if (originalMembers === undefined || updatedMembers === undefined) {
143
+ if (this.unsafeAllowCustomTypes) {
144
+ this.hasAllowedUncheckedCustomTypes = true;
145
+ return undefined;
146
+ } else {
147
+ return { kind: 'missing members', original, updated };
148
+ }
149
+ }
150
+ assert(isStructMembers(originalMembers) && isStructMembers(updatedMembers));
151
+ const ops = this.layoutLevenshtein(originalMembers, updatedMembers, { allowAppend });
152
+ if (ops.length > 0) {
153
+ return { kind: 'struct members', ops, original, updated, allowAppend };
154
+ } else {
155
+ return undefined;
156
+ }
157
+ }
158
+
159
+ case 't_enum': {
160
+ const originalMembers = original.item.members;
161
+ const updatedMembers = updated.item.members;
162
+ if (originalMembers === undefined || updatedMembers === undefined) {
163
+ if (this.unsafeAllowCustomTypes) {
164
+ this.hasAllowedUncheckedCustomTypes = true;
165
+ return undefined;
166
+ } else {
167
+ return { kind: 'missing members', original, updated };
168
+ }
169
+ }
170
+ assert(isEnumMembers(originalMembers) && isEnumMembers(updatedMembers));
171
+ if (enumSize(originalMembers.length) !== enumSize(updatedMembers.length)) {
172
+ return { kind: 'enum resize', original, updated };
173
+ } else {
174
+ const ops = levenshtein(originalMembers, updatedMembers, (a, b) =>
175
+ a === b ? undefined : { kind: 'replace' as const, original: a, updated: b },
176
+ ).filter(o => o.kind !== 'append');
177
+ if (ops.length > 0) {
178
+ return { kind: 'enum members', ops, original, updated };
179
+ } else {
180
+ return undefined;
181
+ }
182
+ }
183
+ }
184
+
185
+ case 't_mapping': {
186
+ const [originalKey, originalValue] = original.args;
187
+ const [updatedKey, updatedValue] = updated.args;
188
+
189
+ // validate an invariant we assume from solidity: key types are always simple value types
190
+ assert(isValueType(originalKey) && isValueType(updatedKey));
191
+
192
+ // network files migrated from the OZ CLI have an unknown key type
193
+ // we allow it to match with any other key type, carrying over the semantics of OZ CLI
194
+ const keyChange =
195
+ originalKey.head === 'unknown'
196
+ ? undefined
197
+ : this.getTypeChange(originalKey, updatedKey, { allowAppend: false });
198
+
199
+ if (keyChange) {
200
+ return { kind: 'mapping key', inner: keyChange, original, updated };
201
+ } else {
202
+ // mapping value types are allowed to grow
203
+ const inner = this.getTypeChange(originalValue, updatedValue, { allowAppend: true });
204
+ if (inner) {
205
+ return { kind: 'mapping value', inner, original, updated };
206
+ } else {
207
+ return undefined;
208
+ }
209
+ }
210
+ }
211
+
212
+ case 't_array': {
213
+ const originalLength = original.tail?.match(/^(\d+|dyn)/)?.[0];
214
+ const updatedLength = updated.tail?.match(/^(\d+|dyn)/)?.[0];
215
+ assert(originalLength !== undefined && updatedLength !== undefined);
216
+
217
+ if (originalLength === 'dyn' || updatedLength === 'dyn') {
218
+ if (originalLength !== updatedLength) {
219
+ return { kind: 'array dynamic', original, updated };
220
+ }
221
+ }
222
+
223
+ const originalLengthInt = parseInt(originalLength, 10);
224
+ const updatedLengthInt = parseInt(updatedLength, 10);
225
+
226
+ if (updatedLengthInt < originalLengthInt) {
227
+ return { kind: 'array shrink', original, updated };
228
+ } else if (!allowAppend && updatedLengthInt > originalLengthInt) {
229
+ return { kind: 'array grow', original, updated };
230
+ }
231
+
232
+ const inner = this.getTypeChange(original.args[0], updated.args[0], { allowAppend: false });
233
+
234
+ if (inner) {
235
+ return { kind: 'array value', inner, original, updated };
236
+ } else {
237
+ return undefined;
238
+ }
239
+ }
240
+
241
+ default:
242
+ return { kind: 'unknown', original, updated };
243
+ }
244
+ }
245
+ }
246
+
247
+ function enumSize(memberCount: number): number {
248
+ return Math.ceil(Math.log2(Math.max(2, memberCount)) / 8);
249
+ }
@@ -0,0 +1,3 @@
1
+ export { StorageItem, StorageLayout, TypeItem, TypeItemMembers, StructMember } from './layout';
2
+ export { extractStorageLayout } from './extract';
3
+ export { decodeTypeIdentifier, stabilizeTypeIdentifier } from '../utils/type-id';
@@ -0,0 +1,110 @@
1
+ import assert from 'assert';
2
+ import { ContractDefinition, StructDefinition, EnumDefinition, TypeDescriptions } from 'solidity-ast';
3
+ import { isNodeType, findAll } from 'solidity-ast/utils';
4
+
5
+ import { StorageLayout, TypeItem } from './layout';
6
+ import { normalizeTypeIdentifier } from '../utils/type-id';
7
+ import { SrcDecoder } from '../src-decoder';
8
+ import { ASTDereferencer } from '../ast-dereferencer';
9
+
10
+ const currentLayoutVersion = '1.1';
11
+
12
+ export function isCurrentLayoutVersion(layout: StorageLayout): boolean {
13
+ return layout?.layoutVersion === currentLayoutVersion;
14
+ }
15
+
16
+ export function extractStorageLayout(
17
+ contractDef: ContractDefinition,
18
+ decodeSrc: SrcDecoder,
19
+ deref: ASTDereferencer,
20
+ ): StorageLayout {
21
+ const layout: StorageLayout = { storage: [], types: {}, layoutVersion: currentLayoutVersion };
22
+
23
+ // Note: A UserDefinedTypeName can also refer to a ContractDefinition but we won't care about those.
24
+ const derefUserDefinedType = deref(['StructDefinition', 'EnumDefinition']);
25
+
26
+ for (const varDecl of contractDef.nodes) {
27
+ if (isNodeType('VariableDeclaration', varDecl)) {
28
+ if (!varDecl.constant && varDecl.mutability !== 'immutable') {
29
+ const type = normalizeTypeIdentifier(typeDescriptions(varDecl).typeIdentifier);
30
+
31
+ layout.storage.push({
32
+ contract: contractDef.name,
33
+ label: varDecl.name,
34
+ type,
35
+ src: decodeSrc(varDecl),
36
+ });
37
+
38
+ assert(varDecl.typeName != null);
39
+
40
+ // We will recursively look for all types involved in this variable declaration in order to store their type
41
+ // information. We iterate over a Map that is indexed by typeIdentifier to ensure we visit each type only once.
42
+ // Note that there can be recursive types.
43
+ const typeNames = new Map(
44
+ [...findTypeNames(varDecl.typeName)].map(n => [typeDescriptions(n).typeIdentifier, n]),
45
+ );
46
+
47
+ for (const typeName of typeNames.values()) {
48
+ const { typeIdentifier, typeString: label } = typeDescriptions(typeName);
49
+
50
+ const type = normalizeTypeIdentifier(typeIdentifier);
51
+
52
+ if (type in layout.types) {
53
+ continue;
54
+ }
55
+
56
+ let members;
57
+
58
+ if ('referencedDeclaration' in typeName && !/^t_contract\b/.test(type)) {
59
+ const typeDef = derefUserDefinedType(typeName.referencedDeclaration);
60
+ members = getTypeMembers(typeDef);
61
+ // Recursively look for the types referenced in this definition and add them to the queue.
62
+ for (const typeName of findTypeNames(typeDef)) {
63
+ const { typeIdentifier } = typeDescriptions(typeName);
64
+ if (!typeNames.has(typeIdentifier)) {
65
+ typeNames.set(typeIdentifier, typeName);
66
+ }
67
+ }
68
+ }
69
+
70
+ layout.types[type] = { label, members };
71
+ }
72
+ }
73
+ }
74
+ }
75
+
76
+ return layout;
77
+ }
78
+
79
+ const findTypeNames = findAll([
80
+ 'ArrayTypeName',
81
+ 'ElementaryTypeName',
82
+ 'FunctionTypeName',
83
+ 'Mapping',
84
+ 'UserDefinedTypeName',
85
+ ]);
86
+
87
+ interface RequiredTypeDescriptions {
88
+ typeIdentifier: string;
89
+ typeString: string;
90
+ }
91
+
92
+ function typeDescriptions(x: { typeDescriptions: TypeDescriptions }): RequiredTypeDescriptions {
93
+ assert(typeof x.typeDescriptions.typeIdentifier === 'string');
94
+ assert(typeof x.typeDescriptions.typeString === 'string');
95
+ return x.typeDescriptions as RequiredTypeDescriptions;
96
+ }
97
+
98
+ function getTypeMembers(typeDef: StructDefinition | EnumDefinition): TypeItem['members'] {
99
+ if (typeDef.nodeType === 'StructDefinition') {
100
+ return typeDef.members.map(m => {
101
+ assert(typeof m.typeDescriptions.typeIdentifier === 'string');
102
+ return {
103
+ label: m.name,
104
+ type: normalizeTypeIdentifier(m.typeDescriptions.typeIdentifier),
105
+ };
106
+ });
107
+ } else {
108
+ return typeDef.members.map(m => m.name);
109
+ }
110
+ }