스마트 컨트랙트 개발 및 보안 감사


  # 스마트 컨트랙트 개발 및 보안 감사

스마트 컨트랙트(Smart Contract)는 블록체인 가상 머신(EVM 등) 위에서 사전에 프로그래밍된 조건에 따라 자동으로 실행되는 불변(Immutable)의 프로그램입니다.

[TOC]

---

## 1. Solidity 핵심 문법과 EVM 메모리 구조

### 1.1 데이터 저장 위치 (Data Location)와 가스 비용
EVM의 가스 소모량은 데이터가 저장되는 위치에 따라 극단적으로 달라집니다.

* **Storage (스토리지)**: 블록체인 상태(State)에 영구 기록되는 공간. `SSTORE` 연산 시 최대 20,000 gas 소모 (가장 비쌈).
* **Memory (메모리)**: 함수 실행 중에만 존재하는 임시 휘발성 메모리.
* **Calldata (캘데이터)**: 외부 트랜잭션 호출 인자(Arguments)가 담기는 불변의 읽기 전용 영역 (가장 저렴).

---

## 2. 주요 토큰 표준 (ERC Standards)

<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>표준</th>
<th>용도</th>
<th>핵심 인터페이스</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>ERC-20</strong></td>
<td>대체 가능한 토큰 (Fungible Token)</td>
<td><code>totalSupply()</code>, <code>balanceOf()</code>, <code>transfer()</code>, <code>approve()</code>, <code>transferFrom()</code></td>
</tr>
<tr>
<td><strong>ERC-721</strong></td>
<td>대체 불가능한 토큰 (NFT)</td>
<td><code>ownerOf(tokenId)</code>, <code>safeTransferFrom()</code>, <code>tokenURI()</code></td>
</tr>
<tr>
<td><strong>ERC-1155</strong></td>
<td>멀티 토큰 표준 (FT + NFT 하이브리드)</td>
<td>단일 트랜잭션으로 여러 종류의 토큰을 일괄 전송(Batch Transfer)하여 가스비 대폭 절감</td>
</tr>
<tr>
<td><strong>ERC-4337</strong></td>
<td>계정 추상화 (Account Abstraction)</td>
<td>스마트 컨트랙트 지갑(시드구문 없는 소셜 로그인, 가스비 대납 Bundler)</td>
</tr>
</tbody>
</table>
</div>

---

## 3. 스마트 컨트랙트 필수 보안 패턴과 취약점 (SWC)

스마트 컨트랙트는 한 번 배포되면 수정할 수 없으므로 철저한 보안 방어 패턴을 준수해야 합니다.

### 3.1 재진입 공격 (Reentrancy Attack)
2016년 360만 ETH가 탈취된 The DAO 해킹 사건의 주범입니다. 컨트랙트가 외부 주소로 이더를 전송할 때, 상대방의 `fallback()` 또는 `receive()` 함수가 실행 완료되기 전에 원본 함수의 출금 로직을 재호출하여 잔고를 0으로 만드는 공격입니다.

#### 취약한 코드 예시:
```solidity
// 위험: 잔고 차감 전에 송금 실행
function withdraw() public {
    uint256 amount = balances[msg.sender];
    require(amount > 0);
    
    (bool success, ) = msg.sender.call{value: amount}(""); // 외부 호출
    require(success);
    
    balances[msg.sender] = 0; // 사후 차감 (취약점!)
}
```

#### 안전한 방어 패턴: Checks-Effects-Interactions & ReentrancyGuard
```solidity
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

function withdraw() public nonReentrant {
    // 1. Checks (조건 검증)
    uint256 amount = balances[msg.sender];
    require(amount > 0, "No funds");
    
    // 2. Effects (내부 상태 변경을 먼저 실행)
    balances[msg.sender] = 0;
    
    // 3. Interactions (외부 상호작용은 마지막에 실행)
    (bool success, ) = msg.sender.call{value: amount}("");
    require(success, "Transfer failed");
}
```

### 3.2 정수 오버플로우/언더플로우 (Overflow/Underflow)
Solidity 0.8.0 이상에서는 기본 연산자에 산술 오버플로우 검사가 내장되어 있어 오버플로우 발생 시 자동으로 `revert`됩니다.

### 3.3 가스 최적화 테크닉
* **변수 패킹 (Struct Packing)**: EVM은 32바이트(256비트) 단위로 스토리지를 읽습니다. `uint128 a; uint128 b;`를 인접 선언하면 단 1개의 32바이트 슬롯에 묶여 저장되므로 가스를 절반으로 아낄 수 있습니다.
* **Custom Error 사용**: `require(cond, "Long error string")` 대신 `if (!cond) revert CustomError()`를 사용하면 바이트코드 크기와 배포/실행 가스를 대폭 절감합니다.