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.

The reference project includes V2 implementations for demonstration and testing:
  • Token: contracts/TokenizedDeposit/_testContracts/TokenizedDepositUpgradeableV2.sol
  • Account: contracts/obp-sdk/accounts/modules/v1/_testContracts/AccountWithERC5982UUPSV2.sol
The V2 contracts preserve the V1 storage layout, expose 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. The IMPLEMENTATION_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:TokenizedDepositUpgradeableV2
If 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

  1. 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-besu

    With the DEPLOY_LIBRARIES set to true, 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 the LIBRARIES_JSON variable. The INITIALIZER_DATA variable is raw ABI-encoded calldata passed to the upgradeToAndCall function. Use 0x for the supplied reference V2 contracts because their initializeV2() is empty. If your new implementation needs to be initialized, provide correctly encoded reinitializer calldata and review it as part of the upgrade proposal.

  2. Approve the governance proposal. If the GOVERNANCE_INTENT_MODE variable is set to obp-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. Use GOVERNANCE_INTENT_MODE=json-rpc only when the project is configured to submit the governance intent directly to the contract instead of through the Oracle Blockchain Platform endpoint.
  3. Run the token upgrade. After approval, run the same manifest that the prepare command wrote.
    UPGRADE_ACTION=execute \
    UPGRADE_MANIFEST=.obp-da/upgrades/deposittoken-v2.json \
    npx hardhat run scripts/upgrade/upgrade-deposittoken.ts --network obp-besu
    The script verifies the manifest chain ID, deadline, and prepared implementation bytecode hash before calling the upgradeToAndCall function.

Upgrade the Account Proxy

  1. Run the following command to prepare the account upgrade.
    UPGRADE_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-besu
    
    Replace the fully-qualified value of the IMPLEMENTATION_CONTRACT variable 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.
  2. 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.