The ERC-1450 reference implementation now includes upgradeable versions of both the main contracts using OpenZeppelin's UUPS (Universal Upgradeable Proxy Standard) pattern. This ensures that critical bugs can be fixed post-deployment without requiring any action from token holders.
- Bug Fixes: Critical vulnerabilities can be patched without token migration
- Regulatory Compliance: New compliance requirements can be implemented
- Feature Additions: New functionality can be added as the standard evolves
- Gas Optimizations: Performance improvements can be deployed
- No Investor Action Required: Upgrades are transparent to token holders
contracts/ERC1450.sol- Original immutable implementationcontracts/RTAProxy.sol- Original immutable multi-sig
contracts/upgradeable/ERC1450Upgradeable.sol- UUPS upgradeable tokencontracts/upgradeable/RTAProxyUpgradeable.sol- UUPS upgradeable multi-sig
- Upgrade Authority: Multi-signature approval required
- Process: Requires M-of-N RTA signers to approve upgrade
- Protection: Prevents single point of failure
- Upgrade Authority: Only the RTA (RTAProxyUpgradeable)
- Process: RTA multi-sig must approve through RTAProxy
- Protection: Even if issuer keys are compromised, they cannot upgrade
# Deploy upgradeable contracts with proxy pattern
npx hardhat run scripts/deploy-upgradeable.js --network polygonThis deploys:
- RTAProxyUpgradeable (UUPS proxy + implementation)
- ERC1450Upgradeable (UUPS proxy + implementation)
The proxy addresses remain constant even after upgrades.
RTAProxyUpgradeable (Multi-sig):
- Proxy: 0x... (permanent address)
- Implementation: 0x... (can be upgraded)
ERC1450Upgradeable Token:
- Proxy: 0x... (permanent address)
- Implementation: 0x... (can be upgraded)
// Example: ERC1450UpgradeableV2.sol
contract ERC1450UpgradeableV2 is ERC1450Upgradeable {
// New features or bug fixes
function version() external pure override returns (string memory) {
return "2.0.0";
}
}# Run comprehensive tests
npx hardhat test
# Test upgrade locally
npx hardhat run scripts/test-upgrade.js --network hardhat# Run upgrade script
npx hardhat run scripts/upgrade.js --network polygon
# Select which contract to upgrade
# Follow multi-sig approval processFor RTAProxyUpgradeable upgrades:
- First signer submits upgrade operation
- Additional signers confirm operation
- Upgrade executes automatically when threshold reached
For ERC1450Upgradeable upgrades:
- RTA submits upgrade through RTAProxy multi-sig
- Additional RTA signers confirm
- Token upgrades when threshold reached
# Set environment variable for automation
export CONTRACT_TO_UPGRADE=2 # 1=RTAProxy, 2=ERC1450
npx hardhat run scripts/upgrade.js --network polygon// In scripts/check-upgrade-status.js
const { checkUpgradeStatus } = require('./upgrade');
async function main() {
await checkUpgradeStatus('upgrade-polygon-1234567890.json');
}- Audit: Have new implementation audited
- Test: Thoroughly test on testnets
- Simulate: Use hardhat fork to simulate upgrade
- Communicate: Notify stakeholders of planned upgrade
- Document: Record reason for upgrade
- Monitor: Watch for multi-sig confirmations
- Verify: Check upgrade executed correctly
- Test: Verify functionality post-upgrade
- Verify: Confirm new version is active
- Update: Update documentation
- Monitor: Watch for any issues
- Archive: Keep old implementation code
The upgradeable contracts include storage gaps to allow for future storage variables:
// Reserve storage slots for future use
uint256[45] private __gap;This prevents storage collisions when adding new state variables in upgrades.
If an issue is detected during multi-sig approval:
- Signers can revoke confirmations
- Operation can be abandoned
- New upgrade can be prepared
While not directly supported, a "rollback" can be achieved by:
- Deploying previous implementation as new version
- Following standard upgrade process
- Effectively "upgrading" to previous version
- UUPS pattern is more gas-efficient than transparent proxy
- Upgrade operations require one-time gas for multi-sig execution
- Day-to-day operations have minimal proxy overhead
| Aspect | Immutable | Upgradeable |
|---|---|---|
| Bug Fixes | Requires migration | In-place update |
| Gas Cost | Slightly lower | Minimal overhead |
| Complexity | Simple | More complex |
| Security | No upgrade risk | Multi-sig controlled |
| Production Ready | Yes, but risky | Recommended |
A: No. Only the RTA (through multi-sig) can authorize upgrades. This protects against compromised issuer keys.
A: Nothing. All storage (balances, ownership, etc.) remains intact. Only the logic implementation changes.
A: The upgrade is transparent to users. Their tokens and addresses remain the same. However, the RTA multi-sig requirement ensures upgrades are legitimate.
A: Once sufficient signatures are collected (typically 2-of-3), the upgrade executes immediately in the same transaction.
A: Yes. New functions can be added. Existing function signatures should be preserved for compatibility.
A: Use the storage gaps (__gap). Never reorder existing storage variables. Only append new ones or use gap slots.
- Node.js 16+
- Hardhat 2.22+
- OpenZeppelin Contracts Upgradeable 5.1.0+
- OpenZeppelin Hardhat Upgrades plugin
For questions about upgradeability:
- Review OpenZeppelin's Upgrades Documentation
- Check the UUPS Pattern Guide
- Contact the StartEngine engineering team
MIT - See LICENSE file for details