개요

OpenZeppelin의 contracts-upgradeable은 업그레이드 가능한 스마트 컨트랙트를 안전하게 구현하기 위한 베이스 라이브러리 프록시 Proxy 패턴으로 사용자 호출 주소와 로직 컨트랙트를 분리하고 delegatecall로 로직을 실행 Transparent Proxy와 UUPS 두 방식을 공식 지원

이 글은 Hardhat 환경에서 @openzeppelin/hardhat-upgrades 플러그인과 함께 UUPS를 중심으로 배포와 업그레이드 흐름을 정리하고, Transparent와의 차이점을 요약

핵심 개념

  • Proxy 컨트랙트와 Implementation 컨트랙트를 분리하여 배포
  • 사용자는 Proxy 주소로 상호작용, Proxy는 delegatecall로 Implementation의 로직 실행
  • 업그레이드는 Proxy가 가리키는 Implementation 주소를 교체하는 방식
  • EIP-1967 표준 슬롯을 사용해 Implementation 주소 보관

방식 요약

  • Transparent Proxy 방식
    • Proxy와 ProxyAdmin이 분리되어 권한 관리
    • 관리자 주소로 호출 시 업그레이드 관리 인터페이스 노출, 일반 사용자는 로직만 사용
  • UUPS 방식
    • 로직 컨트랙트가 업그레이드 함수를 직접 구현, Proxy는 그 함수를 delegatecall로 실행
    • 구조 단순, 불필요한 관리 레이어 감소

프로젝트 초기 세팅

  • Node.js 프로젝트 생성 후 기본 설정 진행
  • 필수 패키지 설치
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox
npm install --save-dev @openzeppelin/hardhat-upgrades @openzeppelin/contracts-upgradeable
npx hardhat
  • hardhat.config에 네트워크 설정 추가 권장

업그레이드 가능한 컨트랙트 작성

UUPS 기준 최소 골격 예시. 생성자 대신 initializer 사용, 접근 제어로 업그레이드 권한 제한 권장

V1

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";

contract MyContractV1 is Initializable, UUPSUpgradeable, OwnableUpgradeable {
    uint256 public value;

    function initialize() public initializer {
        __Ownable_init();
        value = 0;
    }

    function setValue(uint256 _value) external {
        value = _value;
    }

    function _authorizeUpgrade(address newImplementation) internal override onlyOwner {}
}

포인트

  • Initializable 상속으로 생성자 대체, 재초기화 방지
  • UUPSUpgradeable 상속으로 UUPS 업그레이드 진입점 제공
  • _authorizeUpgrade에 onlyOwner 부여로 업그레이드 권한 제한

V2 증분 변경 예시

contract MyContractV2 is MyContractV1 {
    function increment() external {
        value += 1;
    }
    // 상태 변수 추가 시 기존 순서 유지 후 맨 아래에 추가
}

주의

  • Storage Layout 보존 필수. 기존 변수 타입·순서 변경 금지, 삭제 금지, 새 변수는 맨 아래 추가
  • 구현 컨트랙트에 constructor 사용 금지. 초기화는 initializer로 일원화

배포와 업그레이드 흐름

처음 배포 UUPS

const MyV1 = await ethers.getContractFactory("MyContractV1")
const proxy = await upgrades.deployProxy(MyV1, [], { kind: "uups", initializer: "initialize" })
await proxy.deployed()

업그레이드 V2

const MyV2 = await ethers.getContractFactory("MyContractV2")
const upgraded = await upgrades.upgradeProxy(proxy.address, MyV2)
await upgraded.deployed()

구현 주소 확인 EIP-1967

const impl = await upgrades.erc1967.getImplementationAddress(proxy.address)

특징

  • 사용자 호출 주소는 Proxy 주소로 고정 유지
  • 업그레이드 시 새 Implementation 배포 후 Proxy의 구현 포인터만 교체

Transparent Proxy와의 비교

배포 구분은 kind 옵션으로 결정

await upgrades.deployProxy(MyV1, [], { kind: "transparent" })

차이점 요약

  • Transparent는 ProxyAdmin으로 업그레이드 권한 분리, 관리 계정과 일반 사용자의 인터페이스 충돌 방지
  • UUPS는 로직 컨트랙트가 업그레이드 엔트리포인트를 제공해 구성 간결, 배포·운영 비용 절감 가능
  • 두 방식 모두 EIP-1967 슬롯 사용, Hardhat 업그레이드 플러그인으로 배포·업그레이드 절차 유사

업그레이드 시 체크리스트

  1. Storage Layout 안전성
  • 변수 삭제·재배치 금지
  • 새 변수는 항상 맨 아래 추가
  • 업그레이드 전후 슬럿 변화 정적 분석 권장
  1. 업그레이드 권한 모델
  • UUPS: _authorizeUpgrade로 접근 제어 구성
  • Transparent: ProxyAdmin 보유자 또는 멀티시그로 관리
  • 멀티시그·타임락·거버넌스 연계로 안전성 강화
  1. ABI·인터페이스 호환성
  • 기존 인터페이스 변경 최소화
  • 이벤트 시그니처, 외부 호출 경로 변화 시 연동 주체 공지 및 마이그레이션 플랜 준비
  1. 초기화와 재초기화 관리
  • constructor 사용 금지, initializer 단일 진입점 유지
  • 필요 시 reinitializer 버전 관리로 점진 초기화 설계
  1. 테스트와 검증
  • 스토리지 레이아웃 회귀 테스트, 업그레이드 시나리오 테스트 포함
  • 로컬·테스트넷에서 배포→업그레이드→롤백 흐름 리허설
  • 코드 리뷰 및 외부 감사 고려
  1. 운영 관점 베스트 프랙티스
  • 구현 주소와 Proxy 주소, 관리자 키 체계적 보관
  • 변경 이력 온체인·오프체인 기록, 이벤트 기반 모니터링 구성
  • 사고 대응을 위한 업그레이드 차단 스위치 또는 긴급 멈춤 흐름 검토

간단 예시 워크플로

  • V1 배포 후 기능 검증
  • V2 빌드 및 저장소 레이아웃 확인
  • 테스트넷에서 upgradeProxy 리허설, 구현 주소 확인
  • 메인넷에서 멀티시그 승인 후 upgradeProxy 실행
  • 구현 주소 변경 이벤트와 릴리스 노트 공지

마무리

OpenZeppelin contracts-upgradeable은 Proxy + Implementation 패턴을 표준 슬롯과 베이스 컨트랙트로 일관되게 제공 UUPS와 Transparent 중 운영 요구에 맞춰 선택, Hardhat 업그레이드 플러그인으로 배포와 업그레이드 절차 단순화 Proxy 주소를 유지하면서 내부 로직을 교체해 실서비스 중 기능 추가와 버그 수정이 가능한 운영 체계 수립 가능 핵심은 스토리지 레이아웃 보존, 권한 모델 안전화, 업그레이드 전 검증과 회귀 방지 체계 구축임

참고자료