Ver3.0 ๐ง ์ค๋งํธ ์ปจํธ๋ํธ ์ ๊ทธ๋ ์ด๋ ๋ฐฉ๋ฒ: Proxy ํจํด์ผ๋ก ๋ธ๋ก์ฒด์ธ์ ๋ถ๋ณ์ฑ ๊ทน๋ณตํ๊ธฐ

๐ง ์ค๋งํธ ์ปจํธ๋ํธ ์ ๊ทธ๋ ์ด๋ ๋ฐฉ๋ฒ: Proxy ํจํด์ผ๋ก ๋ธ๋ก์ฒด์ธ์ ๋ถ๋ณ์ฑ ๊ทน๋ณตํ๊ธฐ
๋ธ๋ก์ฒด์ธ ์์์ ์ฝ๋๋ฅผ ์ ๋ฐ์ดํธํ๋ค๊ณ ? ๊ฐ๋ฅํฉ๋๋ค! ๐
๐ฏ ์ ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ์ ๊ทธ๋ ์ด๋ํด์ผ ํ ๊น?
๋ธ๋ก์ฒด์ธ์ ์ฒ์ ์ ํ๋ ์ฌ๋๋ค์ด ๊ฐ์ฅ ๋๋ผ์ํ๋ ํน์ง ์ค ํ๋๊ฐ ๋ฐ๋ก ๋ถ๋ณ์ฑ(Immutability)์ด์์. ํ๋ฒ ๋ฐฐํฌ๋ ์ฝ๋๋ ์์ํ ๋ณ๊ฒฝํ ์ ์๋ค๋ ๊ฑฐ์ฃ . ์ด๊ฒ ๋ธ๋ก์ฒด์ธ์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ด๋ฉด์ ๋์์ ๊ฐ์ฅ ํฐ ๋จ์ ์ด๊ธฐ๋ ํด์. ๐
์๊ฐํด๋ณด์ธ์. ์ฌ๋ฌ๋ถ์ด ์ด์ฌํ ๊ฐ๋ฐํ ์ค๋งํธ ์ปจํธ๋ํธ๋ฅผ ์ด๋๋ฆฌ์ ๋ฉ์ธ๋ท์ ๋ฐฐํฌํ๋๋ฐ, ๊ฐ์๊ธฐ ์น๋ช
์ ์ธ ๋ฒ๊ทธ๋ฅผ ๋ฐ๊ฒฌํ๋ค๋ฉด? ์๋๋ฉด ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ๊ณ ์ถ๋ค๋ฉด? ์ผ๋ฐ์ ์ธ ์น ์๋น์ค๋ผ๋ฉด ๊ทธ๋ฅ ์ฝ๋๋ฅผ ์์ ํ๊ณ ์ฌ๋ฐฐํฌํ๋ฉด ๋์ง๋ง, ๋ธ๋ก์ฒด์ธ์์๋ ๊ทธ๊ฒ ๋ถ๊ฐ๋ฅํฉ๋๋ค.
์ค์ ๋ก 2016๋
The DAO ํดํน ์ฌ๊ฑด์์๋ ์ค๋งํธ ์ปจํธ๋ํธ์ ์ทจ์ฝ์ ์ผ๋ก ์ฝ 5์ฒ๋ง ๋ฌ๋ฌ ์๋น์ ์ด๋๋ฆฌ์์ด ํ์ทจ๋นํ์ด์. ๋ง์ฝ ๊ทธ๋ ์ปจํธ๋ํธ๋ฅผ ์
๊ทธ๋ ์ด๋ํ ์ ์์๋ค๋ฉด ์ด๋ ์๊น์? ๐ค
โข ์๋ก์ด ๊ธฐ๋ฅ ์ถ๊ฐ ๋๋ ๋น์ฆ๋์ค ๋ก์ง ๋ณ๊ฒฝ
โข ๊ฐ์ค ์ต์ ํ๋ฅผ ํตํ ๋น์ฉ ์ ๊ฐ
โข ์ธ๋ถ ํ๋กํ ์ฝ ๋ณ๊ฒฝ์ ๋ฐ๋ฅธ ํธํ์ฑ ์ ๋ฐ์ดํธ
โข ๊ท์ ์๊ตฌ์ฌํญ ๋ณ๊ฒฝ ๋์
๐ Proxy ํจํด์ด๋ ๋ฌด์์ธ๊ฐ?
Proxy ํจํด์ ์ค๋งํธ ์ปจํธ๋ํธ์ ๋ถ๋ณ์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฐ์ฅ ๋ํ์ ์ธ ๋ฐฉ๋ฒ์ด์์. ๊ฐ๋จํ ๋งํ๋ฉด, ์ปจํธ๋ํธ๋ฅผ ๋ ๊ฐ๋ก ๋ถ๋ฆฌํ๋ ๊ฑฐ์ฃ .
ํ๋๋ Proxy Contract(ํ๋ก์ ์ปจํธ๋ํธ)๋ก, ์ฌ์ฉ์์ ์ง์ ์ํธ์์ฉํ๊ณ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ์ญํ ์ ํด์. ๋ค๋ฅธ ํ๋๋ Implementation Contract(๊ตฌํ ์ปจํธ๋ํธ ๋๋ Logic Contract)๋ก, ์ค์ ๋น์ฆ๋์ค ๋ก์ง์ ๋ด๊ณ ์์ฃ .
ํ๋ก์ ์ปจํธ๋ํธ๋ ํ๋ฒ ๋ฐฐํฌ๋๋ฉด ์ฃผ์๊ฐ ๋ณํ์ง ์์์. ์ฌ์ฉ์๋ค์ ๊ณ์ ๊ฐ์ ์ฃผ์๋ก ์ ๊ทผํ์ง๋ง, ๋ด๋ถ์ ์ผ๋ก๋ ๊ตฌํ ์ปจํธ๋ํธ๋ฅผ ๊ต์ฒดํ ์ ์๋ ๊ตฌ์กฐ์์. ๋ง์น ๊ฑด๋ฌผ์ ์ธ๊ด์ ๊ทธ๋๋ก ๋๊ณ ๋ด๋ถ ์ธํ
๋ฆฌ์ด๋ง ๋ฐ๊พธ๋ ๊ฒ๊ณผ ๋น์ทํ๋ค๊ณ ํ ์ ์์ฃ ! ๐ข
๐ Proxy ํจํด์ ํต์ฌ ๋ฉ์ปค๋์ฆ
์ผ๋ฐ์ ์ธ call์ ๋ค๋ฅธ ์ฌ๋์ ์ง์ ๊ฐ์ ๊ทธ ์ฌ๋์ ๋ฌผ๊ฑด์ ์ฌ์ฉํ๋ ๊ฒ์ด๋ผ๋ฉด, delegatecall์ ๋ค๋ฅธ ์ฌ๋์ ๋๊ตฌ๋ฅผ ๋น๋ ค์์ ๋ด ์ง์์ ๋ด ๋ฌผ๊ฑด์ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๊ฐ์์! ๐ ๏ธ
์๋ฅผ ๋ค์ด ์ค๋ช
ํด๋ณผ๊ฒ์:
1. ์ฌ์ฉ์๊ฐ Proxy Contract์ ํจ์๋ฅผ ํธ์ถํฉ๋๋ค.
2. Proxy Contract๋ ํด๋น ํจ์ ํธ์ถ์ Implementation Contract๋ก delegatecallํฉ๋๋ค.
3. Implementation Contract์ ์ฝ๋๊ฐ ์คํ๋์ง๋ง, ๋ชจ๋ ์ํ ๋ณ๊ฒฝ์ Proxy Contract์ storage์ ์ ์ฅ๋ฉ๋๋ค.
4. ๊ฒฐ๊ณผ๊ฐ ์ฌ์ฉ์์๊ฒ ๋ฐํ๋ฉ๋๋ค.
์ด ๊ณผ์ ์์ ์ฌ์ฉ์๋ Proxy Contract์ ์ฃผ์๋ง ์๋ฉด ๋๊ณ , Implementation Contract๊ฐ ๋ฐ๋์ด๋ ์ ํ ์ ๊ฒฝ ์ธ ํ์๊ฐ ์์ด์. ๐
๐จ ์ฃผ์ Proxy ํจํด ์ข ๋ฅ
Proxy ํจํด์๋ ์ฌ๋ฌ ๊ฐ์ง ๋ณํ์ด ์์ด์. ๊ฐ๊ฐ์ ํน์ง๊ณผ ์ฅ๋จ์ ์ ์์๋ณด๋ฉด์, ์ด๋ค ์ํฉ์ ์ด๋ค ํจํด์ ์ฌ์ฉํด์ผ ํ๋์ง ์ดํด๋ณผ๊ฒ์! ๐ฏ
1๏ธโฃ Transparent Proxy Pattern (ํฌ๋ช ํ๋ก์ ํจํด)
OpenZeppelin์์ ์ ์ํ ๊ฐ์ฅ ๋๋ฆฌ ์ฌ์ฉ๋๋ ํจํด์ด์์. "ํฌ๋ช
ํ๋ค"๋ ์๋ฏธ๋ ์ฌ์ฉ์ ์
์ฅ์์ ํ๋ก์์ ์กด์ฌ๋ฅผ ์์ํ์ง ์์๋ ๋๋ค๋ ๋ป์ด์ฃ .
ํต์ฌ ํน์ง:
โข Admin(๊ด๋ฆฌ์)๊ณผ ์ผ๋ฐ ์ฌ์ฉ์๋ฅผ ๋ช
ํํ ๊ตฌ๋ถํด์.
โข Admin์ด ํธ์ถํ๋ฉด ํ๋ก์ ์์ฒด์ ๊ด๋ฆฌ ํจ์๊ฐ ์คํ๋๊ณ , ์ผ๋ฐ ์ฌ์ฉ์๊ฐ ํธ์ถํ๋ฉด ๊ตฌํ ์ปจํธ๋ํธ๋ก delegatecall ๋ฉ๋๋ค.
โข ํจ์ ์ ํ์ ์ถฉ๋(Function Selector Collision) ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ด์.
// Transparent Proxy ์์ (๋จ์ํ๋ ๋ฒ์ )
contract TransparentProxy {
address private _admin;
address private _implementation;
modifier ifAdmin() {
if (msg.sender == _admin) {
_;
} else {
_fallback();
}
}
function upgradeTo(address newImplementation) external ifAdmin {
_implementation = newImplementation;
}
function _fallback() internal {
address impl = _implementation;
assembly {
calldatacopy(0, 0, calldatasize())
let result := delegatecall(gas(), impl, 0, calldatasize(), 0, 0)
returndatacopy(0, 0, returndatasize())
switch result
case 0 { revert(0, returndatasize()) }
default { return(0, returndatasize()) }
}
}
fallback() external payable {
_fallback();
}
}
2๏ธโฃ UUPS (Universal Upgradeable Proxy Standard)
UUPS๋ ๋น๊ต์ ์ต๊ทผ์ ๋ฑ์ฅํ ํจํด์ผ๋ก, EIP-1822์์ ์ ์๋์์ด์. Transparent Proxy์ ๊ฐ์ค ๋นํจ์จ์ฑ์ ๊ฐ์ ํ ๋ฒ์ ์ด๋ผ๊ณ ๋ณผ ์ ์์ฃ .
ํต์ฌ ํน์ง:
โข ์
๊ทธ๋ ์ด๋ ๋ก์ง์ด ๊ตฌํ ์ปจํธ๋ํธ์ ํฌํจ๋์ด ์์ด์.
โข ํ๋ก์ ์ปจํธ๋ํธ๋ ๋งค์ฐ ๊ฐ๋จํ๊ณ ๊ฐ๋ฒผ์์.
โข ์ผ๋ฐ ์ฌ์ฉ์์ ํจ์ ํธ์ถ ์ ๊ฐ์ค ๋น์ฉ์ด ๋ ์ ๋ ดํด์.
โข ํ์ง๋ง ๊ตฌํ ์ปจํธ๋ํธ์ ์
๊ทธ๋ ์ด๋ ๋ก์ง์ ๋ฐ๋์ ํฌํจํด์ผ ํด์.
// UUPS ๊ตฌํ ์ปจํธ๋ํธ ์์
contract MyContractV1 is UUPSUpgradeable {
uint256 public value;
function initialize(uint256 _value) public initializer {
value = _value;
}
function setValue(uint256 _value) public {
value = _value;
}
// UUPS์์๋ ๊ตฌํ ์ปจํธ๋ํธ์ ์
๊ทธ๋ ์ด๋ ๋ก์ง์ด ์์ด์
function _authorizeUpgrade(address newImplementation) internal override {
require(msg.sender == owner(), "Only owner can upgrade");
}
}
3๏ธโฃ Beacon Proxy Pattern (๋น์ฝ ํ๋ก์ ํจํด)
์ฌ๋ฌ ๊ฐ์ ํ๋ก์ ์ปจํธ๋ํธ๋ฅผ ๋์์ ๊ด๋ฆฌํด์ผ ํ ๋ ์ ์ฉํ ํจํด์ด์์. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๋ง๋ค ๊ฐ๋ณ ํ๋ก์ ์ปจํธ๋ํธ๋ฅผ ๋ฐฐํฌํ๋ ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด๋ณด์ธ์.
ํต์ฌ ํน์ง:
โข Beacon ์ปจํธ๋ํธ๊ฐ ๊ตฌํ ์ปจํธ๋ํธ์ ์ฃผ์๋ฅผ ์ค์์์ ๊ด๋ฆฌํด์.
โข ์ฌ๋ฌ ํ๋ก์๊ฐ ํ๋์ Beacon์ ์ฐธ์กฐํด์.
โข Beacon์ ๊ตฌํ ์ฃผ์๋ง ๋ณ๊ฒฝํ๋ฉด ๋ชจ๋ ํ๋ก์๊ฐ ๋์์ ์
๊ทธ๋ ์ด๋๋ผ์.
โข ๋๊ท๋ชจ ์์คํ
์์ ํจ์จ์ ์ด์์.
| ํจํด | ์ฅ์ | ๋จ์ | ์ ํฉํ ์ํฉ |
|---|---|---|---|
| Transparent Proxy | ์์ ํ๊ณ ๊ฒ์ฆ๋จ ํจ์ ์ถฉ๋ ๋ฐฉ์ง |
๊ฐ์ค ๋น์ฉ์ด ๋์ ๋ณต์กํ ๊ตฌ์กฐ |
๋จ์ผ ์ปจํธ๋ํธ ๋ณด์์ด ์ต์ฐ์ |
| UUPS | ๊ฐ์ค ํจ์จ์ ๊ฐ๋จํ ํ๋ก์ |
๊ตฌํ ์ค์ ์ํ ์ ๊ทธ๋ ์ด๋ ๋ก์ง ํ์ |
๊ฐ์ค ์ต์ ํ ์ค์ ์๋ จ๋ ๊ฐ๋ฐ์ |
| Beacon Proxy | ๋ค์ค ํ๋ก์ ๊ด๋ฆฌ ์ผ๊ด ์ ๊ทธ๋ ์ด๋ |
์ถ๊ฐ ์ปจํธ๋ํธ ํ์ ๋ณต์ก๋ ์ฆ๊ฐ |
๋ค์์ ํ๋ก์ ๋์ผ ๋ก์ง ๊ณต์ |
๐ ๏ธ Proxy ํจํด ๊ตฌํํ๊ธฐ: ์ค์ ๊ฐ์ด๋
์ด์ ์ค์ ๋ก Proxy ํจํด์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ๋จ๊ณ๋ณ๋ก ์์๋ณผ๊ฒ์. OpenZeppelin์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ์ฉํ๋ฉด ํจ์ฌ ์ฝ๊ณ ์์ ํ๊ฒ ๊ตฌํํ ์ ์์ด์! ๐ช
๐ง Step 1: ํ๊ฒฝ ์ค์
๋จผ์ ํ์ํ ๋๊ตฌ๋ค์ ์ค์นํด์ผ ํด์. Hardhat์ด๋ Truffle ๊ฐ์ ๊ฐ๋ฐ ํ๋ ์์ํฌ์ OpenZeppelin Contracts๋ฅผ ์ฌ์ฉํ ๊ฑฐ์์.
// package.json ์ค์
npm install --save-dev hardhat
npm install @openzeppelin/contracts
npm install @openzeppelin/contracts-upgradeable
npm install @openzeppelin/hardhat-upgrades
๐ Step 2: ๊ตฌํ ์ปจํธ๋ํธ ์์ฑ
์ ๊ทธ๋ ์ด๋ ๊ฐ๋ฅํ ์ปจํธ๋ํธ๋ฅผ ์์ฑํ ๋๋ ๋ช ๊ฐ์ง ์ค์ํ ๊ท์น์ ๋ฐ๋ผ์ผ ํด์. ์ผ๋ฐ์ ์ธ ์ปจํธ๋ํธ์๋ ์กฐ๊ธ ๋ค๋ฅธ ์ ๋ค์ด ์๊ฑฐ๋ ์! ๐
2. Initializable ์ปจํธ๋ํธ๋ฅผ ์์๋ฐ์์ผ ํด์.
3. ์ํ ๋ณ์์ ์์๋ฅผ ์ ๋ ๋ฐ๊พธ๋ฉด ์ ๋ผ์.
4. ๊ธฐ์กด ์ํ ๋ณ์๋ฅผ ์ญ์ ํ๋ฉด ์ ๋ผ์.
5. ์ํ ๋ณ์์ ํ์ ์ ๋ณ๊ฒฝํ๋ฉด ์ ๋ผ์.
// MyContractV1.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
contract MyContractV1 is Initializable, OwnableUpgradeable {
uint256 public value;
string public name;
// constructor ๋์ initialize ์ฌ์ฉ
function initialize(string memory _name) public initializer {
__Ownable_init();
name = _name;
value = 0;
}
function setValue(uint256 _value) public {
value = _value;
}
function getValue() public view returns (uint256) {
return value;
}
}
๐ Step 3: ํ๋ก์ ๋ฐฐํฌํ๊ธฐ
OpenZeppelin์ Hardhat Upgrades ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํ๋ฉด ํ๋ก์ ๋ฐฐํฌ๊ฐ ์ ๋ง ๊ฐ๋จํด์ ธ์. ๋ณต์กํ ํ๋ก์ ๋ก์ง์ ์ง์ ์์ฑํ ํ์ ์์ด ๋ช ์ค์ ์ฝ๋๋ง์ผ๋ก ๊ฐ๋ฅํ๋ต๋๋ค! ๐
// scripts/deploy.js
const { ethers, upgrades } = require("hardhat");
async function main() {
// ๊ตฌํ ์ปจํธ๋ํธ ๊ฐ์ ธ์ค๊ธฐ
const MyContract = await ethers.getContractFactory("MyContractV1");
// ํ๋ก์์ ํจ๊ป ๋ฐฐํฌ (Transparent Proxy ์ฌ์ฉ)
const proxy = await upgrades.deployProxy(
MyContract,
["My First Contract"], // initialize ํจ์์ ํ๋ผ๋ฏธํฐ
{ initializer: 'initialize' }
);
await proxy.deployed();
console.log("Proxy deployed to:", proxy.address);
console.log("Implementation deployed to:", await upgrades.erc1967.getImplementationAddress(proxy.address));
}
main();
๐ Step 4: ์ปจํธ๋ํธ ์ ๊ทธ๋ ์ด๋ํ๊ธฐ
์ด์ ๊ฐ์ฅ ์ค์ํ ๋ถ๋ถ์ด์์! ์๋ก์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ V2 ์ปจํธ๋ํธ๋ฅผ ๋ง๋ค๊ณ ์ ๊ทธ๋ ์ด๋ํ๋ ๊ณผ์ ์ ์ดํด๋ณผ๊ฒ์. ๐ฏ
// MyContractV2.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./MyContractV1.sol";
contract MyContractV2 is MyContractV1 {
// ์๋ก์ด ์ํ ๋ณ์๋ ๋งจ ๋ค์ ์ถ๊ฐ!
uint256 public multiplier;
// ์๋ก์ด ํจ์ ์ถ๊ฐ
function setMultiplier(uint256 _multiplier) public {
multiplier = _multiplier;
}
// ๊ธฐ์กด ํจ์ ์ค๋ฒ๋ผ์ด๋
function getValue() public view override returns (uint256) {
return value * multiplier;
}
// V2์์ ์ถ๊ฐ๋ ์ด๊ธฐํ ํจ์
function initializeV2(uint256 _multiplier) public reinitializer(2) {
multiplier = _multiplier;
}
}
// scripts/upgrade.js
const { ethers, upgrades } = require("hardhat");
async function main() {
const PROXY_ADDRESS = "0x..."; // ๊ธฐ์กด ํ๋ก์ ์ฃผ์
// ์๋ก์ด ๊ตฌํ ์ปจํธ๋ํธ ๊ฐ์ ธ์ค๊ธฐ
const MyContractV2 = await ethers.getContractFactory("MyContractV2");
// ์
๊ทธ๋ ์ด๋ ์คํ
const upgraded = await upgrades.upgradeProxy(PROXY_ADDRESS, MyContractV2);
console.log("Contract upgraded successfully!");
console.log("Proxy address:", upgraded.address);
console.log("New implementation:", await upgrades.erc1967.getImplementationAddress(upgraded.address));
// V2 ์ด๊ธฐํ ํจ์ ํธ์ถ
await upgraded.initializeV2(10);
}
main();
โข ํ๋ก์ ์ฃผ์๋ ๊ทธ๋๋ก ์ ์ง๋๋์? โ
โข ๊ธฐ์กด ๋ฐ์ดํฐ(value, name)๊ฐ ๋ณด์กด๋์ด ์๋์? โ
โข ์๋ก์ด ํจ์(setMultiplier)๊ฐ ์๋ํ๋์? โ
โข ๊ตฌํ ์ปจํธ๋ํธ ์ฃผ์๊ฐ ๋ณ๊ฒฝ๋์๋์? โ
โ ๏ธ Storage Layout: ๊ฐ์ฅ ์กฐ์ฌํด์ผ ํ ๋ถ๋ถ
Proxy ํจํด์์ ๊ฐ์ฅ ๋ง์ด ์ค์ํ๊ณ , ๊ฐ์ฅ ์น๋ช ์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ์ด๋ํ ์ ์๋ ๋ถ๋ถ์ด ๋ฐ๋ก Storage Layout์ด์์. ์ด ๋ถ๋ถ์ ์ ๋๋ก ์ดํดํ์ง ๋ชปํ๋ฉด ์ ๊ทธ๋ ์ด๋ ํ ๋ฐ์ดํฐ๊ฐ ๊ผฌ์ด๊ฑฐ๋ ์์ ํ ๋ง๊ฐ์ง ์ ์์ด์! ๐ฑ
๐งฉ Storage Slot์ ์ดํด
EVM(Ethereum Virtual Machine)์์ ์ปจํธ๋ํธ์ ์ํ ๋ณ์๋ storage slot์ด๋ผ๋ 32๋ฐ์ดํธ ๊ณต๊ฐ์ ์์ฐจ์ ์ผ๋ก ์ ์ฅ๋ผ์. ์ฒซ ๋ฒ์งธ ๋ณ์๋ slot 0, ๋ ๋ฒ์งธ๋ slot 1, ์ด๋ฐ ์์ผ๋ก์.
Proxy ํจํด์์๋ ํ๋ก์ ์ปจํธ๋ํธ์ storage๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์, ๊ตฌํ ์ปจํธ๋ํธ๋ฅผ ์
๊ทธ๋ ์ด๋ํ ๋ storage slot์ ์์์ ํ์
์ด ์ผ์นํด์ผ ํด์!
โ ์๋ชป๋ ์์ 1: ๋ณ์ ์์ ๋ณ๊ฒฝ
// V1
contract V1 {
uint256 public a;
uint256 public b;
}
// V2 - ์๋ชป๋จ!
contract V2 {
uint256 public b; // ์์ ๋ฐ๋
uint256 public a; // ์์ ๋ฐ๋
}
โ ์๋ชป๋ ์์ 2: ๋ณ์ ํ์
๋ณ๊ฒฝ// V1
contract V1 {
uint256 public value;
}
// V2 - ์๋ชป๋จ!
contract V2 {
address public value; // ํ์
๋ณ๊ฒฝ
}
โ ์๋ชป๋ ์์ 3: ์ค๊ฐ์ ๋ณ์ ์ฝ์
// V1
contract V1 {
uint256 public a;
uint256 public c;
}
// V2 - ์๋ชป๋จ!
contract V2 {
uint256 public a;
uint256 public b; // ์ค๊ฐ์ ์ฝ์
uint256 public c;
}
โ ์ฌ๋ฐ๋ฅธ ์์: ๋์ ๋ณ์ ์ถ๊ฐ
// V1
contract V1 {
uint256 public a;
uint256 public b;
}
// V2 - ์ฌ๋ฐ๋ฆ!
contract V2 {
uint256 public a;
uint256 public b;
uint256 public c; // ๋์ ์ถ๊ฐ
address public newAddress; // ๋์ ์ถ๊ฐ
}
๐ Storage Gap ํจํด
๋ฏธ๋์ ์ ๊ทธ๋ ์ด๋๋ฅผ ๋๋นํด์ storage gap์ ๋ฏธ๋ฆฌ ํ๋ณดํด๋๋ ๊ฒ์ด ์ข์ ๊ดํ์ด์์. OpenZeppelin์์๋ ๊ถ์ฅํ๋ ๋ฐฉ๋ฒ์ด์ฃ ! ๐ฏ
contract MyContractV1 {
uint256 public value;
string public name;
// ๋ฏธ๋์ ์
๊ทธ๋ ์ด๋๋ฅผ ์ํ ์์ฝ ๊ณต๊ฐ
// 50๊ฐ์ slot์ ์์ฝ (50 * 32 bytes = 1600 bytes)
uint256[48] private __gap;
}
contract MyContractV2 {
uint256 public value;
string public name;
// ์๋ก์ด ๋ณ์ 2๊ฐ ์ถ๊ฐ
uint256 public multiplier;
address public admin;
// gap์ 48๊ฐ๋ก ์ค์ (50 - 2 = 48)
uint256[46] private __gap;
}
์ด๋ ๊ฒ ํ๋ฉด ๋์ค์ ๋ณ์๋ฅผ ์ถ๊ฐํ ๋ gap์์ ๋นผ์ ์ฌ์ฉํ๋ฉด ๋๋๊น, storage layout์ด ์์ ํ๊ฒ ์ ์ง๋ผ์! ๐
๐ ๋ณด์ ๊ณ ๋ ค์ฌํญ
Proxy ํจํด์ ๊ฐ๋ ฅํ ๊ธฐ๋ฅ์ด์ง๋ง, ๊ทธ๋งํผ ๋ณด์์ ์ ๊ฒฝ ์จ์ผ ํ ๋ถ๋ถ๋ ๋ง์์. ์ ๊ทธ๋ ์ด๋ ๊ถํ์ ๊ฐ์ง ์ฌ๋์ด ์ ์์ ์ผ๋ก ํ๋ํ๋ฉด ํฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๊ฑฐ๋ ์. ๐ก๏ธ
๐ฏ 1. ์ ๊ทธ๋ ์ด๋ ๊ถํ ๊ด๋ฆฌ
์ ๊ทธ๋ ์ด๋๋ฅผ ์ฆ์ ์คํํ์ง ์๊ณ ์ผ์ ์๊ฐ(์: 48์๊ฐ) ํ์ ์คํ๋๋๋ก ํด์. ์ด ๊ธฐ๊ฐ ๋์ ์ปค๋ฎค๋ํฐ๊ฐ ๋ณ๊ฒฝ์ฌํญ์ ๊ฒํ ํ ์ ์์ด์.
โข Multi-sig Wallet
ํ ์ฌ๋์ด ์๋ ์ฌ๋ฌ ๋ช ์ ์น์ธ์ด ์์ด์ผ ์ ๊ทธ๋ ์ด๋ํ ์ ์๋๋ก ํด์. ์๋ฅผ ๋ค์ด 5๋ช ์ค 3๋ช ์ ์๋ช ์ด ํ์ํ๋๋ก ์ค์ ํ ์ ์์ฃ .
โข DAO ๊ฑฐ๋ฒ๋์ค
ํ ํฐ ํ๋๋ค์ ํฌํ๋ก ์ ๊ทธ๋ ์ด๋ ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐฉ์์ด์์. ๊ฐ์ฅ ํ์ค์ํ๋ ๋ฐฉ๋ฒ์ด์ง๋ง ๊ตฌํ์ด ๋ณต์กํด์.
// Timelock์ ์ฌ์ฉํ ์
๊ทธ๋ ์ด๋ ์์
import "@openzeppelin/contracts/governance/TimelockController.sol";
contract UpgradeableWithTimelock {
TimelockController public timelock;
constructor(address[] memory proposers, address[] memory executors) {
// 48์๊ฐ ์ง์ฐ
timelock = new TimelockController(
2 days,
proposers,
executors,
address(0)
);
}
function scheduleUpgrade(address newImplementation) public {
// ์
๊ทธ๋ ์ด๋ ์์ฝ
bytes memory data = abi.encodeWithSignature(
"upgradeTo(address)",
newImplementation
);
timelock.schedule(
address(this),
0,
data,
bytes32(0),
bytes32(0),
2 days
);
}
}
๐ 2. ์ด๊ธฐํ ํจ์ ๋ณดํธ
initialize ํจ์๋ ํ ๋ฒ๋ง ํธ์ถ๋์ด์ผ ํด์. ๋ง์ฝ ์ฌ๋ฌ ๋ฒ ํธ์ถ๋ ์ ์๋ค๋ฉด ๊ณต๊ฒฉ์๊ฐ ์ปจํธ๋ํธ๋ฅผ ์ฌ์ด๊ธฐํํด์ ์์ ๊ถ์ ํ์ทจํ ์ ์์ด์! ๐จ
- โ initializer modifier ์ฌ์ฉํ๋์?
- โ ๋ชจ๋ ์์๋ฐ์ ์ปจํธ๋ํธ์ ์ด๊ธฐํ ํจ์๋ฅผ ํธ์ถํ๋์?
- โ ์ด๊ธฐํ ํจ์๊ฐ ์ธ๋ถ์์ ํธ์ถ ๊ฐ๋ฅํ๊ฐ์? (public/external)
- โ ๋ฐฐํฌ ์งํ ์ฆ์ ์ด๊ธฐํํ๋์?
๐ญ 3. Delegatecall์ ์ํ์ฑ
delegatecall์ ๊ฐ๋ ฅํ์ง๋ง ์ํํ ๊ธฐ๋ฅ์ด์์. ์๋ชป ์ฌ์ฉํ๋ฉด ์์์น ๋ชปํ ๊ฒฐ๊ณผ๊ฐ ๋ฐ์ํ ์ ์์ด์.
ํนํ selfdestruct๋ฅผ ํฌํจํ ์ปจํธ๋ํธ๋ก delegatecallํ๋ฉด ํ๋ก์ ์์ฒด๊ฐ ํ๊ดด๋ ์ ์์ด์! ๐ฑ
โข delegatecall์ ๊ตฌํ ์ปจํธ๋ํธ ๋ด์์ ์ฌ์ฉํ์ง ์๊ธฐ
โข ์์ฑ์์์ ์ํ ๋ณ๊ฒฝํ์ง ์๊ธฐ
โข ๋ถ๋ณ(immutable) ๋ณ์ ์ฌ์ฉ ์ฃผ์
โข OpenZeppelin์ Upgradeable ๋ฒ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ
๐งช ํ ์คํธ ์ ๋ต
์ ๊ทธ๋ ์ด๋ ๊ฐ๋ฅํ ์ปจํธ๋ํธ๋ ์ผ๋ฐ ์ปจํธ๋ํธ๋ณด๋ค ํจ์ฌ ๋ ์ฒ ์ ํ ํ ์คํธ๊ฐ ํ์ํด์. ํ๋ฒ ๋ฐฐํฌ๋ ํ์๋ ๋๋๋ฆด ์ ์์ผ๋๊น์! ๐ฏ
๐ ํ ์คํธ ์ฒดํฌ๋ฆฌ์คํธ
โข ํ๋ก์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋ฐฐํฌ๋๋๊ฐ?
โข ์ด๊ธฐํ ํจ์๊ฐ ์ ์ ์๋ํ๋๊ฐ?
โข ์ด๊ธฐ ์ํ ๊ฐ์ด ์ฌ๋ฐ๋ฅธ๊ฐ?
2. ๊ธฐ๋ฅ ํ ์คํธ
โข ๋ชจ๋ ํจ์๊ฐ ํ๋ก์๋ฅผ ํตํด ์ ์ ์๋ํ๋๊ฐ?
โข ์ํ ๋ณ๊ฒฝ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์ ์ฅ๋๋๊ฐ?
โข ์ด๋ฒคํธ๊ฐ ์ ๋๋ก ๋ฐ์ํ๋๊ฐ?
3. ์ ๊ทธ๋ ์ด๋ ํ ์คํธ
โข ์ ๊ทธ๋ ์ด๋๊ฐ ์ฑ๊ณต์ ์ผ๋ก ์คํ๋๋๊ฐ?
โข ๊ธฐ์กด ๋ฐ์ดํฐ๊ฐ ๋ณด์กด๋๋๊ฐ?
โข ์๋ก์ด ํจ์๊ฐ ์๋ํ๋๊ฐ?
โข ์์ ๋ ํจ์๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ๋๊ฐ?
4. ๊ถํ ํ ์คํธ
โข ๊ถํ ์๋ ์ฌ์ฉ์๊ฐ ์ ๊ทธ๋ ์ด๋ํ ์ ์๋๊ฐ?
โข ์ด๊ธฐํ ํจ์๋ฅผ ๋ ๋ฒ ํธ์ถํ ์ ์๋๊ฐ?
โข Admin ์ ์ฉ ํจ์๊ฐ ๋ณดํธ๋๋๊ฐ?
5. Storage Layout ํ ์คํธ
โข ์ ๊ทธ๋ ์ด๋ ํ storage slot์ด ์ฌ๋ฐ๋ฅธ๊ฐ?
โข ๋ฐ์ดํฐ ํ์ ์ด ์ผ์นํ๋๊ฐ?
โข ์๋ก์ด ๋ณ์๊ฐ ์ฌ๋ฐ๋ฅธ ์์น์ ์๋๊ฐ?
// Hardhat ํ
์คํธ ์์
const { expect } = require("chai");
const { ethers, upgrades } = require("hardhat");
describe("Upgradeable Contract Test", function() {
let proxy, owner, user;
beforeEach(async function() {
[owner, user] = await ethers.getSigners();
const V1 = await ethers.getContractFactory("MyContractV1");
proxy = await upgrades.deployProxy(V1, ["Test"], {
initializer: 'initialize'
});
await proxy.deployed();
});
it("Should initialize correctly", async function() {
expect(await proxy.name()).to.equal("Test");
expect(await proxy.value()).to.equal(0);
});
it("Should set value correctly", async function() {
await proxy.setValue(100);
expect(await proxy.getValue()).to.equal(100);
});
it("Should upgrade successfully", async function() {
// V2๋ก ์
๊ทธ๋ ์ด๋
const V2 = await ethers.getContractFactory("MyContractV2");
const upgraded = await upgrades.upgradeProxy(proxy.address, V2);
// ๊ธฐ์กด ๋ฐ์ดํฐ ๋ณด์กด ํ์ธ
expect(await upgraded.name()).to.equal("Test");
// ์๋ก์ด ๊ธฐ๋ฅ ํ
์คํธ
await upgraded.initializeV2(10);
await upgraded.setValue(5);
expect(await upgraded.getValue()).to.equal(50); // 5 * 10
});
it("Should preserve data across upgrade", async function() {
// V1์์ ๋ฐ์ดํฐ ์ค์
await proxy.setValue(999);
// V2๋ก ์
๊ทธ๋ ์ด๋
const V2 = await ethers.getContractFactory("MyContractV2");
const upgraded = await upgrades.upgradeProxy(proxy.address, V2);
// ๋ฐ์ดํฐ ๋ณด์กด ํ์ธ
await upgraded.initializeV2(1);
expect(await upgraded.getValue()).to.equal(999);
});
});
๐ฌ Storage Layout ๊ฒ์ฆ
OpenZeppelin์ Upgrades ํ๋ฌ๊ทธ์ธ์ ์๋์ผ๋ก storage layout์ ๊ฒ์ฆํด์ค์. ํ์ง๋ง ์๋์ผ๋ก๋ ํ์ธํ๋ ์ต๊ด์ ๋ค์ด๋ ๊ฒ ์ข์์! ๐
// Storage layout ๊ฒ์ฆ ๋ช
๋ น์ด
npx hardhat verify-storage-layout
// ํน์ ์ปจํธ๋ํธ์ storage layout ํ์ธ
npx hardhat storage-layout MyContractV1
npx hardhat storage-layout MyContractV2
๐ ์ค์ ํ์ฉ ์ฌ๋ก
์ด๋ก ๋ง ์์์๋ ๋ถ์กฑํ์ฃ ! ์ค์ ๋ก Proxy ํจํด์ด ์ด๋ป๊ฒ ํ์ฉ๋๋์ง ๋ช ๊ฐ์ง ์ฌ๋ก๋ฅผ ์ดํด๋ณผ๊ฒ์. ๐ช
๐ฐ 1. DeFi ํ๋กํ ์ฝ
Aave, Compound, Uniswap ๊ฐ์ ๋ํ DeFi ํ๋กํ ์ฝ๋ค์ ๋ชจ๋ ์
๊ทธ๋ ์ด๋ ๊ฐ๋ฅํ ์ปจํธ๋ํธ๋ฅผ ์ฌ์ฉํด์.
์๋ฅผ ๋ค์ด Aave V2์์ V3๋ก ์
๊ทธ๋ ์ด๋ํ ๋, ์ฌ์ฉ์๋ค์ ์๋ฌด๊ฒ๋ ํ ํ์ ์์ด ์๋์ผ๋ก ์๋ก์ด ๊ธฐ๋ฅ์ ์ฌ์ฉํ ์ ์์์ด์. ๋ง์ฝ Proxy ํจํด์ ์ฌ์ฉํ์ง ์์๋ค๋ฉด ๋ชจ๋ ์ฌ์ฉ์๊ฐ ์๊ธ์ ์ด๋ํด์ผ ํ์ ๊ฑฐ์์! ๐
๐ฎ 2. NFT ๋ง์ผํ๋ ์ด์ค
NFT ๋ง์ผํ๋ ์ด์ค๋ ๋น ๋ฅด๊ฒ ๋ณํํ๋ ์์ฅ ์๊ตฌ์ฌํญ์ ๋์ํด์ผ ํด์. ์๋ก์ด ๋ก์ดํฐ ์์คํ
, ๊ฒฝ๋งค ๋ฐฉ์, ๊ฒฐ์ ์ต์
๋ฑ์ ๊ณ์ ์ถ๊ฐํด์ผ ํ์ฃ .
OpenSea์ Seaport ํ๋กํ ์ฝ๋ ์
๊ทธ๋ ์ด๋ ๊ฐ๋ฅํ ๊ตฌ์กฐ๋ก ์ค๊ณ๋์ด ์์ด์. ์ด๋ฅผ ํตํด ์๋ก์ด NFT ํ์ค์ด๋ ๊ธฐ๋ฅ์ ๋น ๋ฅด๊ฒ ์ง์ํ ์ ์๋ต๋๋ค! ๐ผ๏ธ
๐ฆ 3. ํ ํฐ ์ปจํธ๋ํธ
์ผ๋ถ ํ ํฐ ํ๋ก์ ํธ๋ ์
๊ทธ๋ ์ด๋ ๊ฐ๋ฅํ ํ ํฐ ์ปจํธ๋ํธ๋ฅผ ์ฌ์ฉํด์. ํ์ง๋ง ์ด๊ฑด ๋
ผ๋์ ์ฌ์ง๊ฐ ์์ด์.
์ฅ์ : ๋ฒ๊ทธ ์์ , ๊ธฐ๋ฅ ์ถ๊ฐ, ๊ท์ ๋์์ด ๊ฐ๋ฅํด์.
๋จ์ : ์ค์ํ ์ฐ๋ ค, ์ ๋ขฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ด์.
๊ทธ๋์ ๋ง์ ํ๋ก์ ํธ๋ค์ด ์ด๊ธฐ์๋ ์
๊ทธ๋ ์ด๋ ๊ฐ๋ฅํ๊ฒ ๋ง๋ค๊ณ , ์ถฉ๋ถํ ์์ ํ๋๋ฉด ์
๊ทธ๋ ์ด๋ ๊ถํ์ ํฌ๊ธฐ(renounce)ํ๋ ์ ๋ต์ ์ฌ์ฉํด์. ๐ฏ
๐ 4. ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ
์ฌ๋ฅ๋ท๊ณผ ๊ฐ์ ์ฌ๋ฅ ๊ณต์ ํ๋ซํผ์์ ๋ธ๋ก์ฒด์ธ์ ํ์ฉํ๋ค๋ฉด, Proxy ํจํด์ ํ์์ ์ด์์!
์๋ฅผ ๋ค์ด:
โข ์ฌ์ฉ์ ํํ ์์คํ
๊ฐ์
โข ์๋ก์ด ๊ฒฐ์ ๋ฐฉ์ ์ถ๊ฐ
โข ์์๋ฃ ๊ตฌ์กฐ ๋ณ๊ฒฝ
โข ๋ถ์ ํด๊ฒฐ ๋ฉ์ปค๋์ฆ ์
๋ฐ์ดํธ
์ด๋ฐ ๋ณ๊ฒฝ์ฌํญ๋ค์ Proxy ํจํด์ ํตํด ์ํํ๊ฒ ์ ์ฉํ ์ ์์ด์. ์ฌ์ฉ์๋ค์ ๊ธฐ์กด ๊ณ์ ๊ณผ ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋๋ก ์ ์งํ๋ฉด์ ์๋ก์ด ๊ธฐ๋ฅ์ ๋ฐ๋ก ์ฌ์ฉํ ์ ์์ฃ ! ๐
โก ๊ฐ์ค ์ต์ ํ ํ
Proxy ํจํด์ ํธ๋ฆฌํ์ง๋ง ์ถ๊ฐ์ ์ธ ๊ฐ์ค ๋น์ฉ์ด ๋ฐ์ํด์. ํนํ delegatecall์ ์ผ๋ฐ call๋ณด๋ค ๋น์ฉ์ด ๋๊ฑฐ๋ ์. ๊ฐ์ค๋ฅผ ์ ์ฝํ๋ ๋ช ๊ฐ์ง ํ์ ์๋ ค๋๋ฆด๊ฒ์! ๐ฐ
Transparent Proxy๋ณด๋ค UUPS๊ฐ ์ผ๋ฐ ์ฌ์ฉ์์ ํจ์ ํธ์ถ ์ ๊ฐ์ค๋ฅผ ์ ์ฝํ ์ ์์ด์. Admin ์ฒดํฌ๊ฐ ์๊ธฐ ๋๋ฌธ์ด์ฃ .
2. Minimal Proxy (EIP-1167)
๋์ผํ ๋ก์ง์ ๊ฐ์ง ์ฌ๋ฌ ์ธ์คํด์ค๊ฐ ํ์ํ๋ค๋ฉด Minimal Proxy(Clone)๋ฅผ ์ฌ์ฉํ์ธ์. ๋ฐฐํฌ ๋น์ฉ์ด 10๋ฐฐ ์ด์ ์ ๋ ดํด์!
3. Storage ์ต์ ํ
โข ์์ ํ์ ๋ค์ ํจ๊ป ๋ฌถ์ด์ ํ๋์ slot์ ์ ์ฅ
โข ์์ฃผ ์ฌ์ฉํ๋ ๋ณ์๋ฅผ ์์ชฝ slot์ ๋ฐฐ์น
โข ๋ถํ์ํ storage ์ฝ๊ธฐ/์ฐ๊ธฐ ์ต์ํ
4. ํจ์ ์ต์ ํ
โข View/Pure ํจ์๋ ๊ฐ์ค๋ฅผ ์๋นํ์ง ์์์
โข ๋ฐ๋ณต์ ์ธ storage ์ ๊ทผ์ memory ๋ณ์๋ก ์บ์ฑ
โข ๋ถํ์ํ ์ด๋ฒคํธ ๋ฐ์ ์ค์ด๊ธฐ
// ๊ฐ์ค ์ต์ ํ ์์
contract OptimizedContract {
// โ ๋นํจ์จ์ : ๊ฐ๊ฐ ํ๋์ slot ์ฌ์ฉ
uint8 public a;
uint8 public b;
uint8 public c;
// โ
ํจ์จ์ : ํ๋์ slot์ ํจ๊ป ์ ์ฅ
struct PackedData {
uint8 a;
uint8 b;
uint8 c;
}
PackedData public data;
// โ ๋นํจ์จ์ : storage๋ฅผ ์ฌ๋ฌ ๋ฒ ์ฝ์
function sumBad() public view returns (uint256) {
return data.a + data.b + data.c;
}
// โ
ํจ์จ์ : memory์ ์บ์ฑ
function sumGood() public view returns (uint256) {
PackedData memory cached = data;
return cached.a + cached.b + cached.c;
}
}
๐จ ํํ ์ค์์ ํด๊ฒฐ ๋ฐฉ๋ฒ
Proxy ํจํด์ ์ฒ์ ์ฌ์ฉํ ๋ ๋ง์ ๊ฐ๋ฐ์๋ค์ด ๋น์ทํ ์ค์๋ฅผ ํด์. ์ ๊ฐ ์ง์ ๊ฒช์๊ฑฐ๋ ๋ณธ ์ค์๋ค์ ๊ณต์ ํ ๊ฒ์! ๐
โ ์ค์ 1: Constructor ์ฌ์ฉ
contract MyContract {
uint256 public value;
constructor(uint256 _value) {
value = _value; // ํ๋ก์์๋ ์ ์ฉ ์ ๋จ!
}
}
ํด๊ฒฐ:contract MyContract is Initializable {
uint256 public value;
function initialize(uint256 _value) public initializer {
value = _value; // ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ!
}
}
โ ์ค์ 2: ์ด๊ธฐํ ํจ์ ๋ฏธํธ์ถ
ํด๊ฒฐ:
๋ฐฐํฌ ์คํฌ๋ฆฝํธ์์ ์๋์ผ๋ก ์ด๊ธฐํํ๊ฑฐ๋, deployProxy ํจ์๋ฅผ ์ฌ์ฉํ์ธ์.
โ ์ค์ 3: Storage Layout ๋ณ๊ฒฝ
// V1
contract V1 {
uint256 public a;
string public b;
}
// V2 - ์๋ชป๋จ!
contract V2 {
string public b; // ์์ ๋ฐ๋
uint256 public a; // ๋ฐ์ดํฐ ์์!
}
๊ฒฐ๊ณผ:์ ๊ทธ๋ ์ด๋ ํ ๋ฐ์ดํฐ๊ฐ ์์ ํ ๊ผฌ์ฌ๋ฒ๋ ค์. uint256 ๊ฐ์ด string์ผ๋ก ํด์๋๊ณ , string์ด uint256์ผ๋ก ํด์๋๋ ๋์ฐํ ์ํฉ์ด ๋ฐ์ํด์! ๐ฑ
ํด๊ฒฐ:
์ ๋ ๋ณ์ ์์๋ฅผ ๋ฐ๊พธ์ง ๋ง๊ณ , ํญ์ ๋์ ์ถ๊ฐํ์ธ์!
โ ์ค์ 4: Selfdestruct ์ฌ์ฉ
ํด๊ฒฐ:
์ ๊ทธ๋ ์ด๋ ๊ฐ๋ฅํ ์ปจํธ๋ํธ์์๋ ์ ๋ selfdestruct๋ฅผ ์ฌ์ฉํ์ง ๋ง์ธ์!
โ ์ค์ 5: ๋ถ์ถฉ๋ถํ ํ ์คํธ
ํด๊ฒฐ:
โข ๋ก์ปฌ ํ ์คํธ โ ํ ์คํธ๋ท ๋ฐฐํฌ โ ๊ฐ์ฌ(Audit) โ ๋ฉ์ธ๋ท ๋ฐฐํฌ
โข ํ ์คํธ๋ท์์ ์ถฉ๋ถํ ์๊ฐ ๋์ ์ด์
โข ์ปค๋ฎค๋ํฐ ํผ๋๋ฐฑ ์์ง
โข ์ ๋ฌธ ๋ณด์ ๊ฐ์ฌ ๋ฐ๊ธฐ
๐ ๊ณ ๊ธ ์ฃผ์ : Diamond Pattern
Proxy ํจํด์ ํ๊ณ๋ฅผ ๊ทน๋ณตํ๊ธฐ ์ํด ๋ฑ์ฅํ ๋ ๊ณ ๊ธ ํจํด์ด ์์ด์. ๋ฐ๋ก Diamond Pattern (EIP-2535)์ด์์! ๐
๐ท Diamond Pattern์ด๋?
Diamond Pattern์ ํ๋์ ํ๋ก์๊ฐ ์ฌ๋ฌ ๊ฐ์ ๊ตฌํ ์ปจํธ๋ํธ(Facet)๋ฅผ ๊ฐ์ง ์ ์๋ ๊ตฌ์กฐ์์. ๋ง์น ๋ค์ด์๋ชฌ๋์ ์ฌ๋ฌ ๋ฉด์ฒ๋ผ์!
์ฃผ์ ํน์ง:
โข ์ปจํธ๋ํธ ํฌ๊ธฐ ์ ํ(24KB) ๊ทน๋ณต
โข ๋ชจ๋์ ์
๊ทธ๋ ์ด๋ ๊ฐ๋ฅ
โข ํจ์๋ณ๋ก ๋ค๋ฅธ ๊ตฌํ ์ปจํธ๋ํธ ์ฌ์ฉ
โข ๋ณต์กํ ์์คํ
์ ์ ํฉ
โข Facet 1: ์ฌ์ฉ์ ๊ด๋ฆฌ
โข Facet 2: ์ฌ๋ฅ ๊ฑฐ๋
โข Facet 3: ํํ ์์คํ
โข Facet 4: ๊ฒฐ์ ์ฒ๋ฆฌ
โข Facet 5: ๋ถ์ ํด๊ฒฐ
๊ฐ ๊ธฐ๋ฅ์ ๋ ๋ฆฝ์ ์ผ๋ก ์ ๊ทธ๋ ์ด๋ํ ์ ์์ด์ ๋งค์ฐ ์ ์ฐํด์! ๐ฏ
ํ์ง๋ง Diamond Pattern์ ๊ตฌํ์ด ๋ณต์กํ๊ณ ๊ฐ์ค ๋น์ฉ๋ ๋์์. ์ ๋ง ํ์ํ ๊ฒฝ์ฐ๊ฐ ์๋๋ผ๋ฉด ์ผ๋ฐ Proxy ํจํด์ผ๋ก๋ ์ถฉ๋ถํด์! ๐
๐ ํ์ต ๋ฆฌ์์ค ๋ฐ ๋๊ตฌ
Proxy ํจํด์ ๋ ๊น์ด ๊ณต๋ถํ๊ณ ์ถ๋ค๋ฉด ์ด๋ฐ ๋ฆฌ์์ค๋ค์ ์ถ์ฒํด์! ๐
โข EIP-1967: Standard Proxy Storage Slots
โข EIP-1822: Universal Upgradeable Proxy Standard
โข EIP-2535: Diamond Standard
๐ ๏ธ ๊ฐ๋ฐ ๋๊ตฌ:
โข Hardhat Upgrades Plugin
โข OpenZeppelin Defender (์๋ํ๋ ์ ๊ทธ๋ ์ด๋ ๊ด๋ฆฌ)
โข Tenderly (๋๋ฒ๊น ๋ฐ ๋ชจ๋ํฐ๋ง)
โข Slither (๋ณด์ ๋ถ์ ๋๊ตฌ)
๐บ ํ์ต ์๋ฃ:
โข OpenZeppelin์ YouTube ์ฑ๋
โข Ethereum.org์ Upgradeable Contracts ๊ฐ์ด๋
โข Smart Contract Programmer์ Proxy ํจํด ์๋ฆฌ์ฆ
โข Patrick Collins์ Solidity ๊ฐ์
๐งฐ ์ ์ฉํ ์ฝ๋ ์ค๋ํซ
// ํ๋ก์ ์ฃผ์์์ ๊ตฌํ ์ฃผ์ ๊ฐ์ ธ์ค๊ธฐ
const implementationAddress = await upgrades.erc1967.getImplementationAddress(proxyAddress);
// ํ๋ก์ ์ฃผ์์์ Admin ์ฃผ์ ๊ฐ์ ธ์ค๊ธฐ
const adminAddress = await upgrades.erc1967.getAdminAddress(proxyAddress);
// ์
๊ทธ๋ ์ด๋ ๊ฒ์ฆ (์ค์ ์
๊ทธ๋ ์ด๋ ์์ด ํ
์คํธ)
await upgrades.validateUpgrade(proxyAddress, NewImplementation);
// ๊ฐ์ ์
๊ทธ๋ ์ด๋ (๊ฒ์ฆ ๋ฌด์ - ์ํ!)
await upgrades.forceImport(proxyAddress, Implementation);
// ํ๋ก์ ์์ ๊ถ ์ด์
await upgrades.admin.transferProxyAdminOwnership(newOwner);
๐ฏ ๊ฒฐ๋ก : ์ธ์ Proxy ํจํด์ ์ฌ์ฉํด์ผ ํ ๊น?
Proxy ํจํด์ ๊ฐ๋ ฅํ์ง๋ง ๋ชจ๋ ์ํฉ์ ์ ํฉํ ๊ฒ์ ์๋์์. ์ ์คํ๊ฒ ๊ฒฐ์ ํด์ผ ํด์! ๐ค
โข ๋ณต์กํ ๋น์ฆ๋์ค ๋ก์ง์ด ์๋ ๊ฒฝ์ฐ
โข ๊ท์ ๋ ์๊ตฌ์ฌํญ์ด ์์ฃผ ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ
โข ๋ฒ๊ทธ ์์ ์ด๋ ๋ณด์ ํจ์น๊ฐ ํ์ํ ์ ์๋ ๊ฒฝ์ฐ
โข ๋๊ท๋ชจ ์๊ธ์ด๋ ์ค์ํ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ๊ฒฝ์ฐ
โข DeFi, NFT ๋ง์ผํ๋ ์ด์ค, DAO ๋ฑ
โข ์์ ํ ํ์ค์ํ๊ฐ ์ค์ํ ๊ฒฝ์ฐ
โข ๋ถ๋ณ์ฑ์ด ํต์ฌ ๊ฐ์น์ธ ๊ฒฝ์ฐ
โข ์ถ๊ฐ ๊ฐ์ค ๋น์ฉ์ด ๋ถ๋ด๋๋ ๊ฒฝ์ฐ
โข ๊ฐ๋ฐ ๋ฆฌ์์ค๊ฐ ๋ถ์กฑํ ๊ฒฝ์ฐ
โข ์ถฉ๋ถํ ํ ์คํธ์ ๊ฐ์ฌ๋ฅผ ํ ์ ์๋ ๊ฒฝ์ฐ
๐ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
Proxy ํจํด์ ๋ธ๋ก์ฒด์ธ์ ๋ถ๋ณ์ฑ๊ณผ ํ์ค ์ธ๊ณ์ ์ ์ฐ์ฑ ์ฌ์ด์์ ๊ท ํ์ ์ฐพ๋ ํ๋ฅญํ ํด๊ฒฐ์ฑ
์ด์์. ํ์ง๋ง "ํฐ ํ์๋ ํฐ ์ฑ
์์ด ๋ฐ๋ฅธ๋ค"๋ ๋ง์ฒ๋ผ, ์
๊ทธ๋ ์ด๋ ๊ถํ์ ๊ฐ์ง๋ค๋ ๊ฒ์ ๊ทธ๋งํผ ์ ์คํด์ผ ํ๋ค๋ ์๋ฏธ์ด๊ธฐ๋ ํด์. ๐ฆธ
์ฌ๋ฅ๋ท์์ ๋ธ๋ก์ฒด์ธ ๊ฐ๋ฐ ๊ด๋ จ ์ฌ๋ฅ์ ๊ณต์ ํ๊ฑฐ๋ ๋ฐฐ์ฐ๊ณ ์ถ๋ค๋ฉด, ์ด๋ฐ ๊ณ ๊ธ ํจํด๋ค์ ์ดํดํ๋ ๊ฒ์ด ํฐ ๋์์ด ๋ ๊ฑฐ์์. ์ค๋งํธ ์ปจํธ๋ํธ ๊ฐ๋ฐ์ ๋จ์ํ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋์ด์, ๋ณด์, ๊ฒฝ์ ํ, ๊ฑฐ๋ฒ๋์ค๊น์ง ๊ณ ๋ คํด์ผ ํ๋ ์ข
ํฉ ์์ ์ด๊ฑฐ๋ ์! ๐จ
์ด ๊ธ์ด ์ฌ๋ฌ๋ถ์ ๋ธ๋ก์ฒด์ธ ๊ฐ๋ฐ ์ฌ์ ์ ๋์์ด ๋์๊ธฐ๋ฅผ ๋ฐ๋ผ์. ๊ถ๊ธํ ์ ์ด ์๋ค๋ฉด ์ฌ๋ฅ๋ท์ ์ง์์ธ์ ์ฒ์์ ๋ค๋ฅธ ์ ๋ฌธ๊ฐ๋ค๊ณผ ์ํตํด๋ณด์ธ์! ํจ๊ป ๋ฐฐ์ฐ๊ณ ์ฑ์ฅํ๋ ๊ฒ์ด ๊ฐ์ฅ ๋น ๋ฅธ ๊ธธ์ด๋๊น์. ๐
Happy coding, and may your contracts be forever upgradeable! ๐โจ
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.