메인 콘텐츠로 건너뛰기
이 가이드에서는 Foundry 프로젝트를 생성하고, WKRC 결제 컨트랙트를 작성하고, StableNet 테스트넷에 배포한 다음 Explorer에서 검증합니다. 소요 시간: 약 15분 도구: Foundry (forge, cast) 네트워크: StableNet 테스트넷 (Chain ID 8283)

사전 준비

시작 전에 아래 항목을 확인하세요:
  • Foundry 설치forge --version으로 확인하세요. 없다면 설치합니다:
    curl -L https://foundry.paradigm.xyz | bash
    foundryup
    
  • 잔액이 있는 테스트넷 지갑. Faucet에서 무료 KRC를 받으세요:

    Faucet

    테스트넷 KRC 요청 — 회원가입 불필요.

    Explorer

    배포 전 잔액을 확인하세요.
StableNet은 27,600 Gwei 최소 Priority Fee를 강제합니다. 이 가이드의 배포 커맨드에는 해당 값이 포함되어 있습니다. 이 임계값 미만의 트랜잭션은 거절됩니다.

네트워크 정보

항목
Chain ID8283
RPC URLhttps://api.test.stablenet.network
Explorerexplorer.stablenet.network
Faucetfaucet.stablenet.network
WKRC 컨트랙트0x0000000000000000000000000000000000001000
최소 Gas Tip27,600 Gwei
WKRC는 StableNet의 네이티브 코인으로, NativeCoinAdapter 시스템 컨트랙트를 통해 표준 ERC-20 인터페이스로 노출됩니다. 가스비에 사용되는 잔액과 WKRC.balanceOf()로 조회되는 잔액이 동일합니다.

단계별 가이드

1

프로젝트 생성

새 Foundry 프로젝트를 만들고 forge-std를 설치합니다:
forge init stablenet-demo
cd stablenet-demo
프로젝트 구조:
stablenet-demo/
├── src/          # 컨트랙트 소스 파일
├── script/       # 배포 스크립트
├── test/         # 테스트 파일
└── foundry.toml  # Foundry 설정
2

foundry.toml 설정

foundry.toml을 열고 StableNet 테스트넷 RPC 엔드포인트를 추가합니다:
[profile.default]
src = "src"
out = "out"
libs = ["lib"]

[rpc_endpoints]
stablenet_testnet = "https://api.test.stablenet.network"
3

WKRCPayment.sol 작성

기본 제공되는 src/Counter.sol을 삭제하고 src/WKRCPayment.sol을 만듭니다:
rm src/Counter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

interface IERC20 {
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
}

/// @title WKRCPayment
/// @notice 승인된 발신자로부터 WKRC 결제를 수락합니다.
///         발신자는 먼저 이 컨트랙트를 approve해야 합니다 (4단계 참고).
contract WKRCPayment {
    /// @dev NativeCoinAdapter (WKRC) — StableNet의 고정 시스템 컨트랙트 주소.
    IERC20 public constant WKRC =
        IERC20(0x0000000000000000000000000000000000001000);

    event Payment(address indexed from, address indexed to, uint256 amount);

    /// @notice msg.sender로부터 `amount`만큼 WKRC를 가져와 `to`에게 전송합니다.
    ///         사전에 WKRC.approve(address(this), amount)가 필요합니다.
    function pay(address to, uint256 amount) external {
        require(WKRC.transferFrom(msg.sender, to, amount), "WKRC transfer failed");
        emit Payment(msg.sender, to, amount);
    }

    /// @notice `owner`가 이 컨트랙트에 승인한 WKRC 한도를 조회합니다.
    function allowanceOf(address owner) external view returns (uint256) {
        return WKRC.allowance(owner, address(this));
    }
}
컴파일로 오류가 없는지 확인합니다:
forge build
예상 출력:
[⠒] Compiling...
[⠢] Compiling 1 files with 0.8.x
[⠆] Solc 0.8.x finished in Xs
Compiler run successful!
4

배포 스크립트 작성

script/DeployWKRCPayment.s.sol을 만듭니다:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import {Script, console} from "forge-std/Script.sol";
import {WKRCPayment} from "../src/WKRCPayment.sol";

contract DeployWKRCPayment is Script {
    function run() external {
        vm.startBroadcast();
        WKRCPayment payment = new WKRCPayment();
        console.log("WKRCPayment deployed at:", address(payment));
        vm.stopBroadcast();
    }
}
5

테스트넷에 배포

프라이빗 키를 내보내고 배포 스크립트를 실행합니다:
export PRIVATE_KEY=0xYourPrivateKey

forge script script/DeployWKRCPayment.s.sol \
  --rpc-url https://api.test.stablenet.network \
  --private-key $PRIVATE_KEY \
  --priority-gas-price 27600000000000 \
  --broadcast
PRIVATE_KEY를 버전 관리에 커밋하지 마세요. .env 파일을 사용하고 .gitignore에 추가하세요.
블록 포함까지 최대 1-2분 걸릴 수 있습니다. cast가 타임아웃되더라도 tx는 mempool에 있으며 곧 확정됩니다.
성공 시 출력 예시:
Script ran successfully.

== Logs ==
WKRCPayment deployed at: 0xABC...

## Setting up 1 EVM.
Chain 8283

Estimated gas price: X gwei
Estimated total gas used for script: Y

✅ Hash: 0xDEF...
Contract Address: 0xABC...
Block: NNNN
Contract Address를 저장해 두세요 — 다음 단계에서 필요합니다.
6

WKRC 승인 후 결제 전송

pay()를 호출하기 전에, 배포한 컨트랙트가 WKRC를 가져갈 수 있도록 지갑에서 먼저 approve해야 합니다. cast로 두 트랜잭션을 전송합니다:
export CONTRACT=0xABC...              # 배포한 WKRCPayment 주소
export RECIPIENT=0xRecipientAddress
export AMOUNT=1000000000000000000     # 1 WKRC (소수점 18자리)
export WKRC=0x0000000000000000000000000000000000001000

# A단계: 컨트랙트가 1 WKRC를 사용할 수 있도록 approve
cast send $WKRC \
  "approve(address,uint256)" $CONTRACT $AMOUNT \
  --rpc-url https://api.test.stablenet.network \
  --private-key $PRIVATE_KEY \
  --priority-gas-price 27600000000000

# B단계: pay() 호출로 수신자에게 전송
cast send $CONTRACT \
  "pay(address,uint256)" $RECIPIENT $AMOUNT \
  --rpc-url https://api.test.stablenet.network \
  --private-key $PRIVATE_KEY \
  --priority-gas-price 27600000000000
--priority-gas-price를 27,600 Gwei 이상으로 높이지 마세요. gas estimation 단계에서 NativeCoinAdapter balance 부족 오류가 발생할 수 있습니다.
승인 한도가 소진됐는지 확인합니다:
export YOUR_ADDRESS=0x<지갑-주소>

cast call $CONTRACT \
  "allowanceOf(address)(uint256)" $YOUR_ADDRESS \
  --rpc-url https://api.test.stablenet.network
# 결과: 0
7

Explorer에서 검증

explorer.stablenet.network에서 컨트랙트 주소를 검색합니다.다음 항목을 확인할 수 있어야 합니다:
  • 배포 트랜잭션
  • WKRC 컨트랙트의 approve 트랜잭션
  • 내 컨트랙트의 pay 호출, 로그에 Payment 이벤트 포함
Payment 이벤트가 확인되면 WKRC 전송이 온체인에 기록된 것입니다.

무슨 일이 일어났나요?

  • WKRC는 StableNet의 KRW 연동 네이티브 코인입니다. 일반 ERC-20 토큰과 동일하게 approve, transferFrom, balanceOf가 표준 인터페이스로 작동합니다.
  • **WKRCPayment.pay()**는 ERC-20 transferFrom 패턴을 사용합니다. 사용자가 먼저 컨트랙트를 spender로 승인하면, 컨트랙트가 토큰을 가져갑니다. 온체인 결제 흐름의 표준 패턴입니다.
  • 27,600 Gwei Priority Fee는 네트워크의 GovValidator 거버넌스 컨트랙트가 강제합니다. 컨트랙트 배포를 포함한 모든 트랜잭션에 이 최솟값이 적용됩니다.

트러블슈팅

  • “replacement transaction underpriced”--gas-price 80000000000000 --priority-gas-price 35000000000000 조합 사용
  • “transfer amount exceeds balance” → gas price를 낮춰 재시도

다음 단계

EVM 호환성 레퍼런스

지원되는 eth_* RPC 메서드, StableNet과 Ethereum의 차이점, 수수료 위임(tx type 0x16).

네트워크 정보

전체 네트워크 파라미터 — Chain ID, 시스템 컨트랙트 주소.

API 레퍼런스

curl 및 ethers.js 예제가 포함된 JSON-RPC 메서드.

Explorer

온체인에서 컨트랙트와 트랜잭션을 조회합니다.