Upgrade a Contract
You can upgrade a packaged contract from the command line.
The following steps show how to upgrade the sample Tokenized Deposit contract project. For other packaged contracts, see the README file bundled with the contract package.
An upgrade changes the implementation behind the existing proxy; it does not create a new proxy or reset its storage.
The Hardhat command-line interface supports upgrading contracts. If you deployed a smart contract using the RPC proxy API, it is immutable and cannot be upgraded.
- Token:
contracts/TokenizedDeposit/_testContracts/TokenizedDepositUpgradeableV2.sol - Account:
contracts/obp-sdk/accounts/modules/v1/_testContracts/AccountWithERC5982UUPSV2.sol
version() as v2.0.0, and include an empty initializeV2() reinitializer. Treat them as reference code; review and replace them with your own compatible implementation for an actual upgrade.
To upgrade a contract you need the proxy address for the contract, a configured Oracle Blockchain Platform Besu network, and authority to submit the governance proposal. The deployed contract must be active and eligible for its configured upgrade authorization path.
Before you modify an implementation, preserve storage compatibility. Append storage fields only. Do not reorder, remove, or change the type of existing fields, alter inherited storage layout, or bypass the upgrade validation. If the change is incompatible, deploy a new proxy and explicitly migrate the state instead.
Note:
You must point to the upgraded source. TheIMPLEMENTATION_CONTRACT variable is passed to Hardhat’s contract factory. Set it to the fully-qualified Solidity contract name for the upgraded version.<path-to-upgraded-contract>.sol:<upgraded-contract-name>Do not point the variable at the current V1 contract. For example, the Tokenized Deposit V2 reference implementation is shown in the following example.contracts/TokenizedDeposit/_testContracts/TokenizedDepositUpgradeableV2.sol:TokenizedDepositUpgradeableV2If you create a different V3 or custom implementation, replace both the path and contract name in the command with that upgraded source. Compile after the change and before running the prepare command.
Upgrade the Token Proxy
- Run the following command to prepare the token upgrade. Preparation validates the implementation and storage layout, deploys the exact new implementation, records its code hash and library addresses in an upgrade manifest, and submits the required governance intent. It does not upgrade the proxy yet.
UPGRADE_ACTION=prepare \ GOVERNANCE_INTENT_MODE=obp-besu \ TOKEN_PROXY=<token-proxy-address> \ IMPLEMENTATION_CONTRACT='contracts/TokenizedDeposit/_testContracts/TokenizedDepositUpgradeableV2.sol:TokenizedDepositUpgradeableV2' \ LIBRARIES_JSON='{"ERC20TokenHelperLib":null,"ERC20MultiLevelApprovalHelperLib":null}' \ DEPLOY_LIBRARIES=true \ INITIALIZER_DATA=0x \ UPGRADE_MANIFEST=.obp-da/upgrades/deposittoken-v2.json \ npx hardhat run scripts/upgrade/upgrade-deposittoken.ts --network obp-besuWith the
DEPLOY_LIBRARIESset totrue, a null library entry is deployed and its address becomes part of the reviewed implementation code hash. To reuse libraries, supply existing compatible library addresses in theLIBRARIES_JSONvariable. TheINITIALIZER_DATAvariable is raw ABI-encoded calldata passed to theupgradeToAndCallfunction. Use 0x for the supplied reference V2 contracts because theirinitializeV2()is empty. If your new implementation needs to be initialized, provide correctly encoded reinitializer calldata and review it as part of the upgrade proposal. - Approve the governance proposal. If the
GOVERNANCE_INTENT_MODEvariable is set toobp-besu, the prepare step submits the proposal through the Oracle Blockchain Platform RPC proxy. Obtain the approvals required by the target governance configuration. The proxy remains on its old implementation until the proposal is approved and the execute step completes. UseGOVERNANCE_INTENT_MODE=json-rpconly when the project is configured to submit the governance intent directly to the contract instead of through the Oracle Blockchain Platform endpoint. - Run the token upgrade. After approval, run the same manifest that the
preparecommand wrote.
The script verifies the manifest chain ID, deadline, and prepared implementation bytecode hash before calling theUPGRADE_ACTION=execute \ UPGRADE_MANIFEST=.obp-da/upgrades/deposittoken-v2.json \ npx hardhat run scripts/upgrade/upgrade-deposittoken.ts --network obp-besuupgradeToAndCallfunction.
Upgrade the Account Proxy
- Run the following command to prepare the account upgrade.
Replace the fully-qualified value of theUPGRADE_ACTION=prepare \ GOVERNANCE_INTENT_MODE=obp-besu \ ACCOUNT_PROXY=<account-proxy-address> \ IMPLEMENTATION_CONTRACT='contracts/obp-sdk/accounts/modules/v1/_testContracts/AccountWithERC5982UUPSV2.sol:AccountWithERC5982UUPSV2' \ LIBRARIES_JSON='{}' \ DEPLOY_LIBRARIES=false \ INITIALIZER_DATA=0x \ UPGRADE_MANIFEST=.obp-da/upgrades/deposittoken-account-v2.json \ npx hardhat run scripts/upgrade/upgrade-account.ts --network obp-besuIMPLEMENTATION_CONTRACTvariable with the path and contract name of your new account implementation. Do not reuse the token’s source path, proxy address, or manifest for an account upgrade. - After the Account upgrade proposal receives the required governance approvals, run the following command to approve and complete the account upgrade.
UPGRADE_ACTION=execute \ UPGRADE_MANIFEST=.obp-da/upgrades/deposittoken-account-v2.json \ npx hardhat run scripts/upgrade/upgrade-account.ts --network obp-besu
Troubleshooting
| Condition | Resolution |
|---|---|
| Prepare fails storage validation | Do not force the upgrade. Correct the incompatible layout change, or deploy a new proxy and migrate the state. |
| A previous prepare manifest has expired or targets a different implementation | Create a replacement deliberately by setting REPREPARE=true and retaining the old manifest as an audit record.
|
| Execute is run before approval | Obtain the governance approvals first. An approved intent is required before the prepared upgrade becomes executable. |
| The wrong implementation is selected | Verify that the IMPLEMENTATION_CONTRACT variable uses the upgraded source’s fully qualified path:contract value, then recompile and prepare a new manifest. Never execute a manifest prepared for a different implementation.
|
| Execute is rerun | The script detects a proxy that is already upgraded and records that outcome rather than sending a second upgrade transaction. For an older manifest that lacks implementationContract, supply the same IMPLEMENTATION_CONTRACT value when executing so that the implementation history can be synchronized.
|