Skip to content

스마트 컨트랙트

스마트 컨트랙트(Smart Contract)는 블록체인 상에서 자동으로 실행되는 프로그램으로, 계약 조건이 충족될 때 자동으로 실행되는 디지털 계약이다. 중개자 없이 신뢰할 수 있는 거래를 가능하게 하며, 투명성과 불변성을 보장한다.

역사적 배경

Nick Szabo의 개념 정립 (1994-1996)

  • 스마트 컨트랙트라는 용어는 1994년 미국의 컴퓨터 과학자 Nick Szabo가 처음 제안했다.
  • 1996년 Szabo는 여러 논문을 발표하며 스마트 컨트랙트를 “계약 조건을 실행하는 전산화된 거래 프로토콜”로 정의했다.
  • 그의 비전은 일반적인 계약 조건을 충족하고, 악의적이거나 우발적인 예외를 최소화하며, 신뢰할 수 있는 중개자의 필요성을 줄이는 것이었다.
  • 자판기를 예시로 들어 설명했다: 동전을 넣으면 기계가 상품을 제공하는 방식처럼, 계약 당사자 간에 신뢰가 거의 필요 없는 메커니즘이다.

BitGold와 Bitcoin의 연결

  • Szabo는 1998년 BitGold라는 분산형 디지털 화폐 개념을 제안했으며, 이는 Bitcoin의 직접적인 전신으로 여겨진다.
  • 그러나 당시에는 스마트 컨트랙트를 실행할 적절한 기술적 기반이 부족했다.

Ethereum의 등장 (2014-2015)

  • 2014년 Vitalik Buterin이 발표한 Ethereum 백서는 Bitcoin 프로토콜을 Nick Szabo가 정의한 스마트 컨트랙트 개념의 약한 버전으로 설명했다.
  • Ethereum은 튜링 완전한 Solidity 언어를 기반으로 한 더 강력한 스마트 컨트랙트 플랫폼을 제안했다.
  • 2015년 Ethereum이 출시되면서 Szabo가 20년 전에 제시한 아이디어가 실제로 구현되었다.

작동 원리

  • 스마트 컨트랙트는 블록체인에 배포된 후 특정 주소를 가지며, 트랜잭션을 통해 호출된다.

  • 계약 코드는 블록체인 네트워크의 모든 노드에서 동일하게 실행된다.

  • 실행 결과는 블록체인에 영구적으로 기록되며, 모든 참여자가 검증할 수 있다.

  • 한번 배포된 컨트랙트는 수정할 수 없으며(immutable), 프록시 패턴 등의 기법을 사용해야만 업그레이드가 가능하다.

  • 상태 관리

    • 각 스마트 컨트랙트는 자체 상태(state)를 가지며, 이는 블록체인의 상태 트리에 저장된다.
    • 상태 변수(state variable)는 컨트랙트의 영구 저장소에 저장되며, 트랜잭션을 통해서만 변경할 수 있다.
    • 로컬 변수는 함수 실행 중에만 메모리에 존재하며, 함수가 종료되면 사라진다.
  • 트랜잭션 처리 흐름

    1. 사용자가 스마트 컨트랙트 함수를 호출하는 트랜잭션을 생성한다.
    2. 트랜잭션은 네트워크의 검증 노드에 전파된다.
    3. 마이너 또는 검증자가 트랜잭션을 블록에 포함시킨다.
    4. 네트워크의 모든 노드가 컨트랙트 코드를 실행하여 새로운 상태를 계산한다.
    5. 합의를 통해 새로운 상태가 블록체인에 확정된다.

실행 환경

Ethereum Virtual Machine (EVM)

  • EVM은 Ethereum 블록체인에서 스마트 컨트랙트를 실행하는 가상 머신이다.
  • 스택 기반 아키텍처를 사용하며, 256비트 워드 크기를 가진다.
  • Big-endian 방식을 사용하며, 각 스택은 최대 1024개의 항목을 보유할 수 있다.
  • 튜링 완전(Turing-complete)하지만, Gas 메커니즘을 통해 무한 루프를 방지한다.

Opcodes

  • 컴파일된 스마트 컨트랙트 바이트코드는 EVM opcodes로 실행된다.
  • 기본 스택 연산(XOR, AND, ADD, SUB 등)을 수행하는 opcodes가 있다.
  • 블록체인 특화 opcodes도 존재한다:
    • ADDRESS: 현재 실행 중인 컨트랙트의 주소를 반환
    • BALANCE: 특정 주소의 잔액을 반환
    • BLOCKHASH: 특정 블록의 해시를 반환
    • CALLER: 호출자의 주소를 반환
    • CALLVALUE: 전송된 이더의 양을 반환
  • 각 opcode는 특정량의 Gas를 소비하며, Ethereum 옐로우 페이퍼에 정의되어 있다.

Gas 메커니즘

  • Gas는 EVM에서 계산 작업을 측정하는 단위이다.
  • 각 opcode 실행은 미리 정해진 양의 Gas를 소비한다.
  • Gas는 다음과 같은 목적을 가진다:
    • 무한 루프 방지
    • 효율적인 코드 작성 장려
    • 네트워크를 스팸으로부터 보호
  • 트랜잭션이 Gas를 모두 소진하면 실행이 중단되고 롤백되지만, 소비된 Gas는 반환되지 않는다.
  • Gas Price는 사용자가 설정하며, 높을수록 빠르게 처리될 가능성이 크다.
// Gas 소비 예시
function expensiveOperation() public {
// 반복문은 많은 Gas를 소비한다
for(uint i = 0; i < 1000; i++) {
// 상태 변경은 특히 비용이 크다 (20,000 Gas)
data[i] = i;
}
}
function efficientOperation() public {
// 한 번의 상태 변경으로 Gas를 절약한다
dataHash = keccak256(abi.encode(data));
}

EVM 호환성과 확장

  • 2025년 현재, EVM 호환성은 새로운 블록체인과 레이어2 솔루션의 표준이 되었다.
  • Binance Smart Chain, Polygon, Avalanche 등 다양한 체인이 EVM과 호환된다.
  • EVM-equivalent 영지식 롤업(ZK-rollups)과 Gas 효율성 개선이 계속 발전하고 있다.
  • Pectra 네트워크 업그레이드(2025년 5월 7일 예정)는 EVM의 기본 버전을 Cancun에서 Prague로 변경한다.

프로그래밍 언어

Solidity

Ethereum 블록체인에서 스마트 컨트랙트를 작성하기 위해 특별히 설계된 고수준의 객체 지향 프로그래밍 언어이다.

  • 역사와 현황

    • 2014년 Ethereum 팀의 Gavin Wood 박사를 포함한 개발자들이 만들었다.
    • 2025년 현재 Web3 생태계에서 가장 널리 사용되는 언어이다.
    • 최신 버전은 Solidity 0.8.30으로, 2025년 5월 Pectra 네트워크 업그레이드를 지원한다.
    • Solidity Summit 2025는 2025년 11월 18일 아르헨티나 부에노스아이레스에서 개최될 예정이다.
  • 주요 특징

    • 정적 타입(statically typed) 언어로, 컴파일 시점에 타입이 검증된다.
    • 상속, 라이브러리, 복잡한 사용자 정의 타입을 지원한다.
    • JavaScript와 유사한 문법을 가져 웹 개발자들이 접근하기 쉽다.
    • EVM을 대상으로 컴파일되어 바이트코드로 변환된다.
  • 버전 0.8.0 이후의 주요 개선사항

    • 자동 오버플로우/언더플로우 검사 기능 내장
    • 이전 버전에서는 SafeMath 라이브러리를 사용해야 했지만, 이제는 기본적으로 제공된다.
// Solidity 스마트 컨트랙트 예시
pragma solidity ^0.8.30;
contract SimpleStorage {
// 상태 변수
uint256 private storedData;
address public owner;
// 이벤트
event DataChanged(uint256 newValue, address changedBy);
// 생성자
constructor() {
owner = msg.sender;
}
// 수정자
modifier onlyOwner() {
require(msg.sender == owner, "Not the owner");
_;
}
// 함수
function set(uint256 x) public onlyOwner {
storedData = x;
emit DataChanged(x, msg.sender);
}
function get() public view returns (uint256) {
return storedData;
}
}
  • 사용 플랫폼
    • Ethereum을 비롯해 Binance Smart Chain, Polygon, Avalanche 등 EVM 호환 블록체인에서 사용된다.

Vyper

Python과 유사한 문법을 가진 Ethereum 스마트 컨트랙트 언어이다.

  • 설계 철학

    • 보안성과 감사 가능성(auditability)을 최우선으로 한다.
    • Solidity보다 기능이 제한적이지만, 코드를 더 읽기 쉽고 이해하기 쉽게 만든다.
    • ”명시적인 것이 암시적인 것보다 낫다”는 Python의 철학을 따른다.
  • 주요 특징

    • 상속을 지원하지 않아 복잡성을 줄인다.
    • 인라인 어셈블리가 없어 보안 취약점을 줄인다.
    • 수정자(modifier) 대신 데코레이터를 사용한다.
    • 명확한 타입 시스템을 가진다.
# Vyper 스마트 컨트랙트 예시
# @version ^0.3.0
storedData: public(uint256)
owner: public(address)
event DataChanged:
newValue: uint256
changedBy: indexed(address)
@external
def __init__():
self.owner = msg.sender
@external
def set(x: uint256):
assert msg.sender == self.owner, "Not the owner"
self.storedData = x
log DataChanged(x, msg.sender)
@external
@view
def get() -> uint256:
return self.storedData

Rust (Solana)

Solana 블록체인에서 스마트 컨트랙트(프로그램)를 작성하는 데 사용되는 시스템 프로그래밍 언어이다.

  • 특징

    • 성능과 안전성을 위해 설계된 다중 패러다임 범용 프로그래밍 언어이다.
    • 특히 안전한 동시성(safe concurrency)을 보장한다.
    • C++과 문법적으로 유사하지만, borrow checker를 사용해 메모리 안전성을 보장한다.
    • Solana에서 초당 65,000건 이상의 트랜잭션을 처리할 수 있는 고성능 스마트 컨트랙트를 작성할 수 있다.
  • 개발 프레임워크

    • Anchor: Solana 스마트 컨트랙트 개발을 단순화하는 프레임워크
    • 상세하고 업데이트된 문서와 활발한 Discord 커뮤니티 지원
  • 트랜잭션 비용

    • 평균 트랜잭션 수수료가 $0.001~$0.02로 매우 저렴하다.

Plutus (Cardano)

Cardano 블록체인의 스마트 컨트랙트 플랫폼으로, Haskell 기반의 함수형 프로그래밍 언어이다.

  • 특징

    • Haskell을 기반으로 하여 안전한 애플리케이션을 구축할 수 있다.
    • 고차 함수(higher-order functions), 지연 평가(lazy evaluation), 불변 데이터 구조를 지원한다.
    • 복잡하고 표현력 있는 스마트 컨트랙트 작성이 가능하다.
    • 결정론적(deterministic) 트랜잭션과 보안에 중점을 둔다.
  • 장단점

    • 장점: 연구 기반 접근 방식, 예측 가능한 실행, 형식 검증(formal verification) 지원
    • 단점: Haskell은 배우기 어렵고 개발자 커뮤니티가 상대적으로 작다.
  • 성능

    • 블록당 20초의 트랜잭션 속도로 보안, 속도, 낮은 수수료의 균형을 제공한다.
    • 최종 확정(finality)까지 약 2분이 소요된다.
    • 평균 트랜잭션 수수료는 최대 $0.4 정도이다.

언어 선택 가이드

  • Solidity: 가장 성숙한 생태계와 풍부한 리소스, Ethereum과 EVM 호환 체인에 적합
  • Vyper: 보안이 중요하고 감사가 필요한 프로젝트, Python 개발자에게 적합
  • Rust: 고성능이 필요한 프로젝트, Solana 생태계
  • Plutus: 형식 검증과 수학적 정확성이 중요한 프로젝트, Cardano 생태계

개발 도구 및 프레임워크

Hardhat

JavaScript/TypeScript 기반의 Ethereum 개발 환경이다.

  • 주요 기능

    • 컴파일, 테스팅, 디버깅, 배포, 자동화를 하나의 환경에서 제공한다.
    • TypeScript를 기본적으로 지원한다.
    • 플러그인 시스템을 통해 기능을 확장할 수 있다.
    • Hardhat Network라는 로컬 Ethereum 네트워크를 제공한다.
  • 특징

    • 풍부한 플러그인 생태계
    • 상세한 스택 트레이스와 에러 메시지
    • Solidity 디버거 내장
    • Gas 리포팅 도구
// hardhat.config.js 예시
module.exports = {
solidity: "0.8.30",
networks: {
hardhat: {
chainId: 1337
},
sepolia: {
url: process.env.SEPOLIA_URL,
accounts: [process.env.PRIVATE_KEY]
}
}
};

Foundry

Rust로 작성된 Ethereum 개발 툴킷이다.

  • 구성 요소

    • forge: 컴파일, 테스트, 배포를 담당하는 핵심 도구
    • anvil: 로컬 Ethereum 노드
    • cast: RPC 호출과 블록체인 상호작용을 위한 CLI
    • chisel: Solidity REPL
  • 장점

    • 벤치마크 결과 경쟁 도구보다 최대 5배 빠른 컴파일 속도
    • Solidity로 테스트를 작성하여 JavaScript 프레임워크의 오버헤드를 피할 수 있다.
    • Property-based fuzzing과 invariant 테스팅 지원
    • Rust의 효율성과 캐싱 덕분에 뛰어난 성능
// Foundry 테스트 예시 (Solidity)
pragma solidity ^0.8.30;
import "forge-std/Test.sol";
import "../src/SimpleStorage.sol";
contract SimpleStorageTest is Test {
SimpleStorage public store;
function setUp() public {
store = new SimpleStorage();
}
function testSet() public {
store.set(42);
assertEq(store.get(), 42);
}
function testFuzz_Set(uint256 x) public {
store.set(x);
assertEq(store.get(), x);
}
}
  • 2025년 트렌드
    • 많은 개발자들이 Hardhat에서 Foundry로 전환하는 추세이다.
    • Foundry의 개방적인 접근 방식과 성능이 주요 이유이다.

Truffle

Ethereum과 EVM 호환 체인을 위한 개발 프레임워크이다.

  • 현황

    • 최근 개발이 중단되었다(discontinued).
    • 역사적으로 중요한 도구였으며, 많은 레거시 프로젝트가 여전히 사용 중이다.
    • 컨트랙트 라이프사이클 전체를 지원했다: 작성, 컴파일, 테스팅, 디버깅, 배포
  • 개발자 마이그레이션

    • 초기에는 Truffle에서 Hardhat으로 전환하는 추세였다.
    • Hardhat이 더 유연하고 덜 독단적이었기 때문이다.
    • 현재는 Hardhat에서 Foundry로의 전환이 활발하다.

기타 개발 도구

  • Remix IDE: 브라우저 기반 Solidity IDE, 초보자와 빠른 프로토타이핑에 적합
  • Tenderly: 실시간 모니터링, 디버깅, 시뮬레이션 플랫폼
  • OpenZeppelin: 검증된 스마트 컨트랙트 라이브러리와 보안 도구
  • Ethers.js / Web3.js: JavaScript 라이브러리로 스마트 컨트랙트와 상호작용
  • The Graph: 블록체인 데이터 인덱싱 및 쿼리 프로토콜

토큰 표준

ERC-20: 대체 가능 토큰 (Fungible Tokens)

Ethereum 블록체인에서 대체 가능한 토큰을 생성하기 위한 표준 인터페이스이다.

  • 역사

    • 2015년에 처음 제안되었으며, 2017년에 Ethereum 생태계에 공식적으로 통합되었다.
  • 주요 특징

    • 모든 토큰이 동일한 가치를 가지며 상호 교환 가능하다.
    • 투표 토큰, 스테이킹 토큰, 가상 화폐 등에 사용된다.
  • 필수 함수

    • totalSupply(): 총 토큰 공급량
    • balanceOf(address): 특정 주소의 잔액
    • transfer(address, amount): 토큰 전송
    • approve(address, amount): 지출 승인
    • transferFrom(address, address, amount): 승인된 토큰 전송
    • allowance(address, address): 승인된 지출 한도 조회
// ERC-20 인터페이스
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
  • 사용 사례
    • DeFi 프로토콜의 거버넌스 토큰 (UNI, AAVE, COMP 등)
    • 스테이블코인 (USDT, USDC, DAI 등)
    • 유틸리티 토큰

ERC-721: 대체 불가능 토큰 (Non-Fungible Tokens)

각 토큰이 고유하며 대체 불가능한 토큰을 위한 표준이다.

  • 역사

    • 2017년에 도입되었으며, NFT 현상을 촉발시킨 혁명적인 토큰 표준이다.
    • Ethereum 생태계에서 NFT 생성의 기반이 되었다.
  • 주요 특징

    • 각 토큰은 고유한 토큰 ID를 가진다.
    • 예술 작품, 수집품, 게임 아이템, 부동산 등을 나타낸다.
  • 필수 함수

    • balanceOf(address): 소유한 NFT 개수
    • ownerOf(tokenId): 특정 NFT의 소유자
    • safeTransferFrom(from, to, tokenId): 안전한 전송
    • transferFrom(from, to, tokenId): 전송
    • approve(to, tokenId): 전송 승인
    • setApprovalForAll(operator, approved): 운영자 승인
    • getApproved(tokenId): 승인된 주소 조회
    • isApprovedForAll(owner, operator): 운영자 승인 상태
// ERC-721 기본 구현 예시
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
contract MyNFT is ERC721 {
uint256 private _tokenIdCounter;
constructor() ERC721("MyNFT", "MNFT") {}
function mint(address to) public {
_tokenIdCounter++;
_safeMint(to, _tokenIdCounter);
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
// 메타데이터 URI 반환
return string(abi.encodePacked("https://api.example.com/metadata/", tokenId));
}
}
  • 사용 사례
    • 디지털 예술품 (CryptoPunks, Bored Ape Yacht Club)
    • 게임 아이템 (Axie Infinity)
    • 가상 부동산 (Decentraland)
    • 디지털 수집품

ERC-1155: 멀티 토큰 표준

단일 컨트랙트에서 대체 가능, 반대체 가능, 대체 불가능 토큰을 모두 표현할 수 있는 표준이다.

  • 주요 특징

    • ERC-20과 ERC-721의 기능을 결합한 업그레이드된 표준이다.
    • 하나의 스마트 컨트랙트로 여러 토큰을 동시에 표현할 수 있다.
    • 배치 전송(batch transfer)을 지원하여 Gas 비용을 최대 90%까지 절감할 수 있다.
  • 장점

    • 네트워크 혼잡 감소
    • 효율적인 토큰 관리
    • 게임과 같이 다양한 종류의 아이템을 다루는 애플리케이션에 적합
// ERC-1155 배치 전송 예시
interface IERC1155 {
function balanceOf(address account, uint256 id) external view returns (uint256);
function balanceOfBatch(address[] accounts, uint256[] ids) external view returns (uint256[] memory);
function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) external;
// 배치 전송 - Gas 효율적
function safeBatchTransferFrom(
address from,
address to,
uint256[] ids,
uint256[] amounts,
bytes data
) external;
function setApprovalForAll(address operator, bool approved) external;
function isApprovedForAll(address account, address operator) external view returns (bool);
}
  • 사용 사례
    • 게임 (다양한 아이템과 화폐를 하나의 컨트랙트로 관리)
    • 반대체 가능 토큰 (제한된 수량의 동일한 아이템)
    • 복합 토큰 시스템

토큰 표준 비교

기준ERC-20ERC-721ERC-1155
토큰 유형대체 가능대체 불가능혼합형
도입 시기2017년2017년이후
배치 전송불가불가가능
Gas 효율성보통낮음높음
주요 용도화폐, 토큰NFT, 수집품게임, 복합 시스템

주요 사용 사례

DeFi (탈중앙화 금융)

스마트 컨트랙트를 통해 전통적인 금융 서비스를 블록체인에서 제공한다.

  • 2025년 시장 현황

    • 주간 평균 거래량이 약 186억 달러에 달한다.
    • 970만 개 이상의 고유 지갑이 DeFi와 상호작용하고 있다.
    • 2025년 5월 기준, 대출 플랫폼 Aave가 전체 TVL(Total Value Locked)의 약 45%를 차지하며, 약 254억 달러를 보유하고 있다.
  • 탈중앙화 거래소 (DEX)

    • 중개자 없이 피어 투 피어 암호화폐 거래를 가능하게 한다.
    • 자동 실행 스마트 컨트랙트를 통해 거래를 촉진한다.
    • 예시: Uniswap, SushiSwap, PancakeSwap
// 간단한 자동화된 마켓 메이커 (AMM) 개념
contract SimpleAMM {
uint256 public reserveA;
uint256 public reserveB;
// Constant Product Formula: x y = k
function swap(uint256 amountAIn) public returns (uint256 amountBOut) {
uint256 k = reserveA reserveB;
reserveA += amountAIn;
uint256 newReserveB = k / reserveA;
amountBOut = reserveB - newReserveB;
reserveB = newReserveB;
return amountBOut;
}
}
  • 대출 및 차입

    • 대출자는 즉시 암호화폐를 차입할 수 있다.
    • 차입자는 충분한 담보를 스마트 컨트랙트에 예치해야 한다.
    • 예시: Aave, Compound, MakerDAO
  • 수익 집계기 (Yield Aggregators)

    • 자동으로 최고 수익률을 제공하는 DeFi 프로토콜을 찾아 자금을 배분한다.
    • 예시: Yearn Finance
  • 합성 자산 (Synthetic Assets)

    • 실물 자산의 가격을 추적하는 토큰을 생성한다.
    • 예시: Synthetix
  • 기타 DeFi 애플리케이션

    • 자산 토큰화 플랫폼
    • 보험 DApp
    • 예측 시장
    • 스테이블코인 프로토콜

NFT (Non-Fungible Tokens)

디지털 또는 실물 자산의 소유권을 나타내는 고유한 토큰이다.

  • 디지털 예술품

    • 예술가들이 디지털 작품을 판매하고 로열티를 받을 수 있다.
    • 예시: CryptoPunks, Bored Ape Yacht Club, Art Blocks
  • 게임 아이템

    • 게임 내 아이템을 실제로 소유하고 거래할 수 있다.
    • 플레이-투-언(Play-to-Earn) 모델
    • 예시: Axie Infinity, Gods Unchained
  • 메타버스 부동산

    • 가상 세계에서 토지와 건물을 소유할 수 있다.
    • 예시: Decentraland, The Sandbox
  • 멤버십과 접근 권한

    • NFT를 커뮤니티 멤버십이나 특별 이벤트 티켓으로 사용한다.
// NFT 로열티 구현 예시 (ERC-2981)
import "@openzeppelin/contracts/token/common/ERC2981.sol";
contract ArtNFT is ERC721, ERC2981 {
constructor() ERC721("ArtNFT", "ART") {
// 10% 로열티 설정
_setDefaultRoyalty(msg.sender, 1000); // 1000 = 10%
}
function mint(address to, uint256 tokenId) public {
_safeMint(to, tokenId);
}
}

DAO (탈중앙화 자율 조직)

스마트 컨트랙트로 운영되는 분산형 조직이다.

  • 거버넌스
    • 토큰 보유자가 제안하고 투표할 수 있다.
    • 투표 결과가 자동으로 실행된다.
// 간단한 DAO 투표 메커니즘
contract SimpleDAO {
struct Proposal {
string description;
uint256 voteCount;
bool executed;
mapping(address => bool) voters;
}
mapping(uint256 => Proposal) public proposals;
uint256 public proposalCount;
function propose(string memory description) public returns (uint256) {
uint256 proposalId = proposalCount++;
Proposal storage p = proposals[proposalId];
p.description = description;
return proposalId;
}
function vote(uint256 proposalId) public {
Proposal storage p = proposals[proposalId];
require(!p.voters[msg.sender], "Already voted");
p.voters[msg.sender] = true;
p.voteCount++;
}
function execute(uint256 proposalId) public {
Proposal storage p = proposals[proposalId];
require(p.voteCount > 100, "Not enough votes");
require(!p.executed, "Already executed");
p.executed = true;
// 제안 실행 로직
}
}
  • 예시
    • MakerDAO: DeFi 프로토콜 거버넌스
    • Uniswap DAO: DEX 프로토콜 관리
    • Aragon: DAO 생성 플랫폼

공급망 관리

제품의 원산지부터 최종 소비자까지 추적한다.

  • 투명성과 위조 방지
  • 실시간 추적 및 인증
  • 자동화된 품질 검증

신원 관리

자기 주권 신원(Self-Sovereign Identity)을 가능하게 한다.

  • 사용자가 자신의 데이터를 제어한다.
  • 탈중앙화된 신원 검증
  • 예시: uPort, Civic

부동산

부동산 거래를 디지털화하고 자동화한다.

  • 소유권 이전의 자동화
  • 중개인 없는 거래
  • 토큰화된 부동산 투자

업그레이드 패턴

스마트 컨트랙트는 기본적으로 불변(immutable)이지만, 프록시 패턴을 사용하면 업그레이드가 가능하다.

Transparent Proxy Pattern (투명 프록시)

  • 작동 원리

    • 프록시 컨트랙트에 업그레이드 기능이 포함되어 있다.
    • 메시지 호출자(msg.sender)에 따라 실행 경로가 달라진다.
    • 관리자 주소와 일반 사용자를 구분하여 처리한다.
  • 특징

    • 프록시 컨트랙트에 upgradeTo(address) 메서드가 있어 구현 컨트랙트 주소를 업데이트한다.
    • 관리자는 업그레이드 함수에만 접근할 수 있고, 일반 사용자는 구현 컨트랙트의 함수를 호출한다.
  • 단점

    • 모든 호출마다 호출자를 확인해야 하므로 약간의 Gas 오버헤드가 발생한다.
    • 프록시에 관리 로직이 포함되어 배포 비용이 높다.
// Transparent Proxy 개념
contract TransparentProxy {
address public implementation;
address public admin;
modifier onlyAdmin() {
require(msg.sender == admin, "Not admin");
_;
}
function upgradeTo(address newImplementation) external onlyAdmin {
implementation = newImplementation;
}
fallback() external payable {
require(msg.sender != admin, "Admin cannot call implementation");
_delegate(implementation);
}
function _delegate(address impl) internal {
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()) }
}
}
}

UUPS (Universal Upgradeable Proxy Standard)

  • 작동 원리

    • 업그레이드 로직이 프록시가 아닌 구현 컨트랙트에 있다.
    • ERC-1822에서 처음 설명된 패턴이다.
    • 프록시는 매우 간단하며, 저장소 역할만 하고 호출을 위임한다.
  • 장점

    • 프록시가 더 작아 배포 비용이 저렴하다.
    • 업그레이드 로직을 최종 구현에서 제거하여 컨트랙트를 사실상 불변으로 만들 수 있다.
    • OpenZeppelin은 대부분의 사용 사례에 UUPS를 권장한다.
    • Transparent Proxy보다 Gas 효율적이다.
  • 단점

    • 구현 컨트랙트 배포 및 업그레이드 비용이 더 높다.
    • 구현 컨트랙트에 업그레이드 로직을 포함해야 한다.
// UUPS 패턴 예시
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
contract MyContractV1 is UUPSUpgradeable {
uint256 public value;
function initialize(uint256 _value) public initializer {
value = _value;
}
function _authorizeUpgrade(address newImplementation) internal override {
// 업그레이드 권한 검증
require(msg.sender == owner, "Not authorized");
}
function setValue(uint256 _value) public {
value = _value;
}
}
contract MyContractV2 is UUPSUpgradeable {
uint256 public value;
uint256 public newFeature; // 새로운 기능 추가
function _authorizeUpgrade(address newImplementation) internal override {
require(msg.sender == owner, "Not authorized");
}
function setValue(uint256 _value) public {
value = _value;
}
function setNewFeature(uint256 _newFeature) public {
newFeature = _newFeature;
}
}

Beacon Proxy Pattern

  • 작동 원리

    • 여러 프록시가 하나의 Beacon 컨트랙트를 참조한다.
    • Beacon은 현재 구현 컨트랙트의 주소를 저장한다.
    • Beacon 주소만 업데이트하면 모든 프록시가 동시에 업그레이드된다.
  • 장점

    • 동일한 로직을 사용하는 여러 컨트랙트를 한 번에 업그레이드할 수 있다.
    • 대규모 배포에 효율적이다.

Diamond Pattern (EIP-2535)

  • 작동 원리

    • 하나의 프록시가 여러 구현 컨트랙트(facet)를 참조한다.
    • 각 함수를 개별적으로 업그레이드할 수 있다.
    • 24KB 컨트랙트 크기 제한을 우회할 수 있다.
  • 장점

    • 모듈식 업그레이드
    • 무제한 컨트랙트 크기
    • Gas 효율적인 선택적 업그레이드
  • 단점

    • 구현이 복잡하다.
    • 디버깅이 어렵다.

업그레이드 패턴 선택 가이드

패턴사용 사례Gas 효율성복잡도
Transparent Proxy단순한 업그레이드 필요 시보통낮음
UUPS대부분의 경우 (권장)높음보통
Beacon여러 동일 컨트랙트 관리높음보통
Diamond대규모 복잡한 시스템매우 높음높음

2025년 현재, OpenZeppelin은 UUPS를 가장 권장하고 있으며, 경량성과 유연성 덕분에 널리 채택되고 있다.

보안

스마트 컨트랙트 보안은 매우 중요하다. 2024년에만 149건의 사고로 약 14.2억 달러의 손실이 발생했다.

OWASP Smart Contract Top 10 (2025)

OWASP Smart Contract Top 10은 스마트 컨트랙트에서 발견되는 상위 10개 취약점에 대한 표준 인식 문서이다.

  1. Access Control (접근 제어): $953M 손실 (2024)
  2. Logic Errors (로직 오류): $63M 손실
  3. Reentrancy (재진입): $35.7M 손실
  4. Integer Overflow/Underflow (정수 오버플로우/언더플로우)
  5. 기타 취약점들

주요 보안 취약점

Reentrancy Attack (재진입 공격)

  • 설명

    • 외부 컨트랙트 호출이 완료되기 전에 동일한 함수가 다시 호출되는 공격이다.
    • 공격자가 자금을 빼내거나 컨트랙트 상태를 변경할 수 있다.
    • 2024년에 $35.7M의 손실을 초래했다.
  • 취약한 코드 예시

// 취약한 코드 - Reentrancy 가능
contract VulnerableBank {
mapping(address => uint256) public balances;
function withdraw(uint256 amount) public {
require(balances[msg.sender] >= amount);
// 외부 호출 전에 상태를 업데이트하지 않음 - 취약점!
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] -= amount;
}
}
// 공격자 컨트랙트
contract Attacker {
VulnerableBank bank;
receive() external payable {
// 재진입 공격
if (address(bank).balance >= 1 ether) {
bank.withdraw(1 ether);
}
}
}
  • 안전한 코드 (Checks-Effects-Interactions 패턴)
// 안전한 코드
contract SecureBank {
mapping(address => uint256) public balances;
function withdraw(uint256 amount) public {
// 1. Checks (검증)
require(balances[msg.sender] >= amount);
// 2. Effects (상태 변경)
balances[msg.sender] -= amount;
// 3. Interactions (외부 호출)
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
}
// ReentrancyGuard 사용
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SafeBank is ReentrancyGuard {
mapping(address => uint256) public balances;
function withdraw(uint256 amount) public nonReentrant {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
}
}

Integer Overflow/Underflow

  • 설명

    • 정수가 허용된 범위를 벗어나는 값으로 변경될 때 발생한다.
    • Overflow: 최대값을 초과
    • Underflow: 최소값 미만으로 떨어짐
  • 해결책

    • Solidity 0.8.0 이상에서는 자동으로 오버플로우/언더플로우를 검사한다.
    • 이전 버전에서는 SafeMath 라이브러리를 사용해야 했다.
// Solidity 0.8.0 이상 - 자동 검사
function add(uint256 a, uint256 b) public pure returns (uint256) {
return a + b; // 오버플로우 시 자동으로 revert
}
// 체크를 비활성화하려면 unchecked 사용 (Gas 절약)
function unsafeAdd(uint256 a, uint256 b) public pure returns (uint256) {
unchecked {
return a + b; // 오버플로우 검사 없음
}
}

Access Control (접근 제어)

  • 설명
    • 권한이 없는 사용자가 중요한 함수를 호출할 수 있는 취약점이다.
    • 2024년에 $953M의 손실을 초래한 가장 큰 보안 이슈이다.
// 취약한 코드
contract Vulnerable {
address public owner;
// 누구나 owner를 변경할 수 있음!
function setOwner(address newOwner) public {
owner = newOwner;
}
}
// 안전한 코드
import "@openzeppelin/contracts/access/Ownable.sol";
contract Secure is Ownable {
function sensitiveFunction() public onlyOwner {
// owner만 호출 가능
}
function transferOwnership(address newOwner) public override onlyOwner {
super.transferOwnership(newOwner);
}
}
// 역할 기반 접근 제어 (RBAC)
import "@openzeppelin/contracts/access/AccessControl.sol";
contract SecureWithRoles is AccessControl {
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
constructor() {
_grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
_grantRole(ADMIN_ROLE, msg.sender);
}
function mint(address to) public onlyRole(MINTER_ROLE) {
// MINTER_ROLE을 가진 사용자만 실행 가능
}
}

Front-Running

  • 설명

    • 공격자가 대기 중인 트랜잭션을 보고 더 높은 Gas Price로 먼저 실행시키는 공격이다.
    • DEX에서 큰 거래를 먼저 실행하여 이익을 얻는 방식이다.
  • 완화 방법

    • Commit-Reveal 스킴 사용
    • 최대 슬리피지 설정
    • Private transaction pools 사용
// Commit-Reveal 패턴
contract SecureAuction {
mapping(address => bytes32) public commitments;
mapping(address => uint256) public bids;
// 1단계: 입찰 커밋 (실제 값은 숨김)
function commitBid(bytes32 hashedBid) public {
commitments[msg.sender] = hashedBid;
}
// 2단계: 입찰 공개
function revealBid(uint256 amount, string memory secret) public {
bytes32 hash = keccak256(abi.encodePacked(amount, secret));
require(commitments[msg.sender] == hash, "Invalid reveal");
bids[msg.sender] = amount;
}
}

보안 베스트 프랙티스

개발 단계

  1. Checks-Effects-Interactions 패턴 사용

    • 항상 검증 → 상태 변경 → 외부 호출 순서를 따른다.
  2. 검증된 라이브러리 사용

    • OpenZeppelin Contracts와 같은 검증된 라이브러리를 사용한다.
    • 직접 구현보다 안전하고 Gas 효율적이다.
  3. 함수 가시성 명시

    • public, external, internal, private를 명확히 지정한다.
    • 기본값에 의존하지 않는다.
  4. 이벤트 로깅

    • 중요한 상태 변경은 반드시 이벤트로 기록한다.
    • 오프체인 모니터링과 감사에 필수적이다.
// 베스트 프랙티스 예시
contract BestPractices {
uint256 private value;
address private immutable owner;
event ValueChanged(uint256 oldValue, uint256 newValue, address changedBy);
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner, "Not authorized");
_;
}
function setValue(uint256 newValue) external onlyOwner {
uint256 oldValue = value;
value = newValue;
emit ValueChanged(oldValue, newValue, msg.sender);
}
function getValue() external view returns (uint256) {
return value;
}
}

테스트 단계

  1. 포괄적인 단위 테스트

    • 모든 함수와 엣지 케이스를 테스트한다.
    • Foundry의 Fuzzing을 활용한다.
  2. Invariant 테스팅

    • 컨트랙트가 항상 유지해야 하는 불변 조건을 테스트한다.
// Foundry Invariant 테스트 예시
contract TokenInvariantTest is Test {
Token token;
function setUp() public {
token = new Token();
}
// 불변 조건: 총 공급량은 항상 모든 잔액의 합과 같아야 함
function invariant_totalSupplyEqualsBalances() public {
uint256 totalBalance = 0;
for (uint i = 0; i < users.length; i++) {
totalBalance += token.balanceOf(users[i]);
}
assertEq(token.totalSupply(), totalBalance);
}
}
  1. Gas 최적화 테스트
    • Gas 사용량을 모니터링하고 최적화한다.

배포 전 감사

  1. 전문 감사 받기

    • CertiK, Trail of Bits, OpenZeppelin 등의 전문 감사 업체를 활용한다.
    • 대규모 프로젝트는 여러 업체의 감사를 받는다.
  2. 자동화된 보안 도구 사용

    • Slither: 정적 분석 도구
    • Mythril: 심볼릭 실행 도구
    • Echidna: Property-based 테스팅 도구
  3. 버그 바운티 프로그램

    • Immunefi, HackerOne 등의 플랫폼에서 버그 바운티를 운영한다.

배포 후 모니터링

  1. 실시간 모니터링

    • Tenderly, Forta 등의 도구로 비정상적인 활동을 감지한다.
  2. Emergency Pause 기능

    • 문제 발견 시 컨트랙트를 일시 중지할 수 있는 기능을 포함한다.
import "@openzeppelin/contracts/security/Pausable.sol";
contract EmergencyStop is Pausable, Ownable {
function criticalFunction() public whenNotPaused {
// 일시 중지 시 실행 불가
}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
}
  1. Multisig 지갑 사용
    • 중요한 관리 기능은 다중 서명이 필요하도록 한다.
    • Gnosis Safe 등의 검증된 multisig 솔루션을 사용한다.

블록체인 플랫폼 비교

Ethereum

  • 특징

    • 가장 성숙한 스마트 컨트랙트 플랫폼
    • 가장 큰 개발자 생태계와 DApp 생태계
    • Proof of Stake 합의 메커니즘 (The Merge 이후)
  • 성능

    • 약 15-30 TPS
    • 블록 시간: 12초
    • 최종 확정: 약 15분
  • 개발

    • 언어: Solidity, Vyper
    • 도구: Hardhat, Foundry, Remix
    • 표준: ERC-20, ERC-721, ERC-1155 등
  • 장단점

    • 장점: 네트워크 효과, 방대한 리소스, 높은 보안성
    • 단점: 높은 Gas 비용, 제한된 처리량

Solana

  • 특징

    • 고성능 블록체인
    • Proof of History + Proof of Stake
    • 매우 빠른 트랜잭션 처리
  • 성능

    • 65,000+ TPS
    • 블록 시간: 400ms
    • 최종 확정: 13초 이내
  • 개발

    • 언어: Rust, C
    • 프레임워크: Anchor
    • 튜링 완전, 무허가(permissionless)
  • 비용

    • 평균 트랜잭션 수수료: $0.001-$0.02
  • 장단점

    • 장점: 매우 빠른 속도, 낮은 수수료, 우수한 개발 도구
    • 단점: 네트워크 안정성 이슈(과거), 상대적으로 작은 생태계

Cardano

  • 특징

    • 연구 중심 접근 방식
    • Ouroboros Proof of Stake
    • 형식 검증 강조
  • 성능

    • 약 250 TPS (목표치)
    • 블록 시간: 20초
    • 최종 확정: 약 2분
  • 개발

    • 언어: Plutus (Haskell 기반), Aiken
    • 결정론적 트랜잭션
    • 튜링 완전, 무허가
  • 비용

    • 평균 트랜잭션 수수료: 최대 $0.4
  • 장단점

    • 장점: 수학적으로 검증된 보안, 예측 가능한 실행
    • 단점: 느린 개발 속도, 학습 곡선이 높음, 작은 개발자 커뮤니티

플랫폼 선택 가이드

  • Ethereum: 가장 안전하고 검증된 플랫폼이 필요한 경우, 광범위한 생태계 통합
  • Solana: 고성능과 낮은 비용이 중요한 경우, 게임이나 고빈도 거래 애플리케이션
  • Cardano: 형식 검증과 수학적 정확성이 중요한 경우, 장기적 안정성 중시

참고