I am trying to run upgrade on smart-contracts that were deployed still using the ProxyAdmin <=v4 implementation. I still have my manifest file, from several years ago. I detect that there's a change on the information included in a storage slot in the storage layout section of an implementation. Example:
{
"contract": "Twin",
"label": "schainLinks",
"type": "t_mapping(t_bytes32,t_address)",
"src": "contracts/mainnet/Twin.sol:39"
}, // OLD
{
"label": "schainLinks",
"offset": 0,
"slot": "203",
"type": "t_mapping(t_bytes32,t_address)",
"contract": "Twin",
"src": "contracts/mainnet/Twin.sol:39"
}, // New
In this particular variable, I've changed t_bytes for a user defined Value (representing bytes32), and included the correct annotation: /// @custom:oz-retyped-from mapping(bytes32 => address).
The upgrade fails, with contracts/mainnet/Twin.sol:40: Layout could have changed for schainLinks (mapping(bytes32 => address) -> mapping(SchainHash => address)).
Notice that for other contracts that inherit from this one, and have their implementation entry in the manifest updated (using the newer details) this error is not thrown. It makes me wonder if this is indeed a manifest-only issue, and during validation the offset and slot sections are required in this particular case (because there's a re-typing).
If so, I would like to discuss some ideas on how could I go about this, making sure the upgrade is still safe, in the cleanest way possible.
Code to reproduce
Can provide privately if required, but don't think it is strictly required just yet.
Environment
Using hardhat v2, openzeppelin hardhat-upgrades v3+ and upgrades-code v1.39+.
As I understand this particular check is performed in upgrades-core. Maybe this is a recent change ?
Hi @Eduardo_Vasques, sorry for the late response. Your original implementation was deployed when the manifest stored only basic layout info, but newer versions of the plugin added the ability to track detailed storage layout information such as slot and offset. When you use /// @custom:oz-retyped-from ..., the plugin needs slot/offset data to ensure the retype is safe. Without that data, it reports “layout could have changed”.
If your current manifest file only has the one implementation contract:
-
Back up the current version of your manifest file .openzeppelin/<network>.json
-
Check out the old branch/commit that produced the currently deployed (old) implementation, and compile the contracts in your project, e.g. npx hardhat compile.
-
Temporarily rename/move .openzeppelin/<network>.json because the following steps will regenerate it from scratch to include the detailed storage layout information.
-
Create a script in scripts/force-import.ts with the following contents, and fill in your proxy address and the name of your implementation contract:
```
import { ethers, upgrades } from "hardhat";
async function main() {
const proxyAddress = "0x<YOUR_PROXY_ADDRESS>"; // replace with your proxy address
const ImplFactory = await ethers.getContractFactory("YOUR_CONTRACT_NAME"); // replace with your contract name
await upgrades.forceImport(proxyAddress, ImplFactory);
}
main().catch(error => {
console.error(error);
process.exit(1);
});
```
-
Run the script with npx hardhat run scripts/force-import.ts --network <network>
-
This creates a regenerated manifest file which includes detailed storage layout of the old implementation.
-
Switch back to your current branch (with the implementation version that you want to upgrade to) and retry the upgrade.
Or, if your manifest contains multiple implementations you care about:
- Back up the current version of your manifest file
.openzeppelin/<network>.json
- Check out the old branch/commit that produced the currently deployed (old) implementation, and compile the contracts in your project, e.g.
npx hardhat compile.
- In the manifest, find and delete the one entry under
impls whose address matches the currently deployed implementation, but keep everything else.
- Run the same
forceImport command from steps 4 and 5 above. It will recreate that single entry with slot/offset populated.
- Switch back to your current branch and retry the upgrade.
Once the manifest entry has the detailed storage layout using either of the above methods, the retype check should pass when you run the upgrade.
Already had moved on with Option 1. I wanted to avoid forceImport from the start, and confirm this was the issue and if there was another way around it.
Thank you for the response anyway! It confirms my suspicious 