> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stablenet.network/llms.txt
> Use this file to discover all available pages before exploring further.

# Foundry로 컨트랙트 배포하기

> Foundry 프로젝트를 구성하고, WKRC 결제 컨트랙트를 작성해 StableNet Testnet에 배포합니다.

> Foundry의 `forge`와 `cast`를 사용해 Solidity 컨트랙트를 StableNet Testnet에 배포합니다.

## 배우는 내용

이 튜토리얼을 완료하면 다음을 할 수 있습니다:

* StableNet Testnet을 위한 Foundry 프로젝트 구성
* `forge script`로 WKRC 결제 컨트랙트 배포
* `cast send`로 컨트랙트 함수를 호출하고 Explorer에서 결과 확인

## 사전 준비

* Foundry 설치 — `forge --version`으로 확인. 미설치 시:

  ```shell theme={null}
  curl -L https://foundry.paradigm.xyz | bash
  foundryup
  ```

* [Faucet](https://faucet.stablenet.network)에서 테스트넷 WKRC 받기

## 프로젝트 생성

```shell theme={null}
forge init stablenet-demo
cd stablenet-demo
```

## foundry.toml 설정

`foundry.toml`에 StableNet Testnet 엔드포인트를 추가합니다:

```toml theme={null}
[profile.default]
src = "src"
out = "out"
libs = ["lib"]

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

## WKRCPayment.sol 작성

기본 파일을 삭제하고 `src/WKRCPayment.sol`을 생성합니다:

```shell theme={null}
rm src/Counter.sol
```

```solidity theme={null}
// 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 결제를 수락합니다.
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);
    }

    function allowanceOf(address owner) external view returns (uint256) {
        return WKRC.allowance(owner, address(this));
    }
}
```

컴파일해서 오류가 없는지 확인합니다:

```shell theme={null}
forge build
```

```text theme={null}
[⠒] Compiling...
Compiler run successful!
```

## 배포 스크립트 작성

`script/DeployWKRCPayment.s.sol`을 생성합니다:

```solidity theme={null}
// 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();
    }
}
```

## Testnet에 배포

<Warning>
  개인 키를 버전 관리 시스템에 커밋하지 마세요. `.env` 파일에 저장하고 `.gitignore`에 추가하세요.
</Warning>

```shell theme={null}
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
```

```text theme={null}
Script ran successfully.

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

Chain 8283

✅ Hash: 0xDEF...
Contract Address: 0xABC...
Block: NNNN
```

**Contract Address**를 저장하세요 — 다음 단계에서 필요합니다.

<Note>
  StableNet은 GovValidator 컨트랙트가 설정한 최소 priority fee를 적용합니다. 모든 `forge script`와 `cast send` 호출에 `--priority-gas-price 27600000000000`을 전달하세요.
</Note>

## WKRC 승인 후 결제

`pay()`를 호출하기 전에 배포한 컨트랙트가 지갑의 WKRC를 사용할 수 있도록 승인해야 합니다:

```shell theme={null}
export CONTRACT=0xABC...
export RECIPIENT=0xRecipientAddress
export AMOUNT=1000000000000000000
export WKRC=0x0000000000000000000000000000000000001000

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

# pay()를 호출해 수신자에게 전송
cast send $CONTRACT \
  "pay(address,uint256)" $RECIPIENT $AMOUNT \
  --rpc-url https://api.test.stablenet.network \
  --private-key $PRIVATE_KEY \
  --priority-gas-price 27600000000000
```

승인 한도가 소비됐는지 확인합니다:

```shell theme={null}
cast call $CONTRACT \
  "allowanceOf(address)(uint256)" $RECIPIENT \
  --rpc-url https://api.test.stablenet.network
```

```text theme={null}
0
```

## Explorer에서 확인

[explorer.stablenet.network](https://explorer.stablenet.network)를 열고 컨트랙트 주소를 검색합니다. 배포 트랜잭션, WKRC 컨트랙트에서의 `approve` 호출, 로그에 `Payment` 이벤트가 포함된 `pay` 호출을 확인할 수 있습니다.

## 다음 단계

<CardGroup cols={2}>
  <Card title="Hardhat으로 배포하기" href="/ko/v0.3/build/tutorials/deploy-with-hardhat">Hardhat과 ethers.js로 같은 컨트랙트를 배포합니다.</Card>
  <Card title="이벤트 구독하기" href="/ko/v0.3/build/tutorials/listen-to-events">WebSocket으로 온체인 이벤트를 구독합니다.</Card>
  <Card title="RPC API 레퍼런스" href="/ko/v0.3/reference/rpc-api">지원되는 JSON-RPC 메서드 전체 목록.</Card>
  <Card title="수수료 위임" href="/ko/v0.3/build/tutorials/fee-delegation">별도 계정이 사용자 대신 가스를 납부하게 합니다.</Card>
</CardGroup>
