Since 2009, we have been utilizing our extensive expertise in blockchain technologies to help businesses, both large and small, maximize their efficiency.
Explore More
With more than 400+ experts, Oodles comprises a fantastic resource of business knowledge that spans multiple industries. Whatever the circumstances, we keep to our obligations.
Explore More
At Oodles, we help our clients work with a human understanding but at superhuman speed something that others can't. They thus advance and maintain their lead
4th November 2024
4 min read
Associate Consultant L2- Development
Once deployed, smart contracts cannot be changed or tampered with since they are immutable. However, a contemporary method of smart contract development that can be upgraded is the Ethereum blockchain's Universal Upgradeable Proxy Standard (UUPS). By making the upgrading process easier and improving gas efficiency, it overcomes some drawbacks of earlier proxy patterns, most notably the Transparent Proxy Pattern.
UUPS consists of two main components: the proxy and implementation contracts.
`When deploying a UUPS setup, it's essential to initialize the implementation through the proxy to ensure that state variables are stored correctly in the proxy's storage rather than in the implementation's storage, which is essential for maintaining the integrity and upgradeability of the contract.
All the versions of the implementation contract share the same storage space so that`s why sequencing matters while initializing variables.
In the UUPS pattern, constructors are generally not used due to the proxy design.
The implementation contract does not directly manage state variables; instead, these variables are stored in the proxy's storage. Since constructors are executed during contract deployment and would initialize state variables in the implementation contract, using them would lead to incorrect storage allocation and could result in state variables being stored in the implementation rather than the proxy.
Also, Check | How to Create a Simple Supply Chain Smart Contract
These contracts utilize an initializer function that is called after deployment. This function is designed to set up state variables and can include security mechanisms to ensure it is only called once, preventing re-initialization attacks.
// SPDX-License-Identifier: MIT
pragma solidity 0.8.28;
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol';
import '@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol';
contract Version1 is
Initializable,
ERC20Upgradeable,
UUPSUpgradeable,
OwnableUpgradeable
{
uint256 public value;
// Initializer function to replace constructor
function initialize() public initializer {
__ERC20_init('Mars', 'MARS');
__Ownable_init(_msgSender()); // Pass the owner address here
value = 5;
__UUPSUpgradeable_init();
_mint(msg.sender, 10000000 * 10 ** decimals());
}
// Upgradeable authorization for upgrades (only owner can upgrade)
function _authorizeUpgrade(
address newImplementation
) internal override onlyOwner {}
function getValue() public view returns (uint256) {
return value;
}
}
contract Version2 is Version1 {
function version() public pure returns (string memory) {
return 'V2';
}
}
contract Version3 is Version1 {
function version() public pure returns (string memory) {
return 'V3';
}
}
For the above contract we are upgrading the contract versions from 'V`1' to 'V3', below are the test cases for the proxy contract.
Also, Explore | How to Write and Deploy Modular Smart Contracts
const {
loadFixture,
} = require('@nomicfoundation/hardhat-toolbox/network-helpers');
const hardhat = require('hardhat');
const assert = require('assert');
describe('Proxy', function () {
describe('Deployment', async function () {
async function deployOneYearLockFixture() {
const contract = await hardhat.ethers.getContractFactory('Version1');
const contractVersion2 = await hardhat.ethers.getContractFactory('Version2');
const contractVersion3 = await hardhat.ethers.getContractFactory('Version3');
const proxyContract = await hardhat.upgrades.deployProxy(contract, { kind: 'uups' })
return { proxyContract, contractVersion3, contractVersion2 }
}
describe('Versions', function () {
it('Should set the right output', async function () {
const { contractVersion3, proxyContract, contractVersion2 } = await loadFixture(deployOneYearLockFixture);
assert(await proxyContract.name() == 'Mars')
assert(await proxyContract.getValue() == 5n)
const contractV2 = await hardhat.upgrades.upgradeProxy(proxyContract, contractVersion2)
assert(await contractV2.getValue() == 5n)
assert(await contractV2.version() == 'V2')
const contractV3 = await hardhat.upgrades.upgradeProxy(proxyContract, contractVersion3)
assert(await contractV3.getValue() == 5n)
assert(await contractV3.version() == 'V3')
});
});
})
})
Use the following command to run and verify the test cases for the proxy contract
- npx hardhat test
Also, Read | How to Create Play-to-Earn Gaming Smart Contracts
In conclusion, the Universal Upgradeable Proxy Standard (UUPS) provides a robust framework for developing upgradeable smart contracts on Ethereum. By leveraging a proxy architecture that separates logic from state, it allows for efficient upgrades while maintaining critical aspects of security and decentralization inherent to blockchain technology. As smart contract developers continue to navigate the complexities of smart contract deployment and management, UUPS stands out as a preferred method for ensuring that decentralized applications can evolve over time without compromising their foundational integrity.
Sarthak Saxena
Sarthak, an experienced back-end developer, specializes in Node.js and possesses a profound understanding of web3 technology. He has hands-on experience with a plethora of tools and frameworks, including Solidity, Express.js, Remix, Twilio, and databases such as MongoDB and Postgres. Leveraging his extensive expertise in Solidity and back-end development, Sarthak consistently delivers exceptional results in any project related to his field.
Associate Consultant L2- Development
By using this site, you allow our use of cookies. For more information on the cookies we use and how to delete or block them, please read our cookie notice.
We would love to
hear from you!
Innovate with confidence!