이번 글에서는 로컬 개발 환경과 Sepolia 테스트넷에서 Cairo로 작성된 ZK 증명 기반의 스마트 컨트랙트를 작성하고, sncast를 이용해 배포하고 호출해보겠습니다.
로컬 네트워크에서 개발하기 위해 Starknet Devnet을 실행합니다. Ethereum의 Anvil과 유사하게 동작합니다.
starknet-devnet --seed=0
--seed=0을 지정하면 동일한 계정 및 주소가 항상 생성됩니다.
[package]
name = "cairo_contract"
version = "0.1.0"
edition = "2024_07"
[dependencies]
starknet = "2.11.4"
[dev-dependencies]
snforge_std = "0.43.1"
assert_macros = "2.11.4"
[[target.starknet-contract]]
sierra = true
casm = true
[scripts]
test = "snforge test"
[tool.scarb]
allow-prebuilt-plugins = ["snforge_std"]
기본 설정에서 casm = true만 추가했습니다.
sierra = true
casm = true
Devnet에서 미리 배포된 계정을 사용하여 snfoundry에 불러옵니다:
sncast account import \
--name=local-test-account \
--address=0x064b48806902a367c8598f4f95c305e8c1a1acba5f082d294a43793113115691 \
--type=oz \
--url=http://127.0.0.1:5050 \
--private-key=0x0000000000000000000000000000000071d7bb07b9a64f6f78ac4c816aff4da9 \
--add-profile=devnet \
--silent
--name= 옵션에 계정 alias를 설정할 수 있습니다.
scarb build
빌드하면 target/release 폴더 아래에 .contract_class.json 및 .compiled_contract_class.json 파일이 생성됩니다.
sncast --profile=devnet --account=local-test-account declare --contract-name=VerifierContract
출력 예시:
class_hash: 0x04eefd80...
transaction_hash: 0x01871398...
sncast --profile=devnet --account=local-test-account deploy \
--class-hash=0x04eefd80... \
--salt=0
출력 예시:
contract_address: 0x0044bd8c...
sncast --profile=devnet --account=local-test-account call \
--contract-address=0x0044bd8c... \
--function verify_add_and_mul \
--arguments 5,6,11,30
결과:
response: true
response_raw: [0x1]
/// 두 수를 더해서 결과가 예상한 값과 같은지 검증하는 함수
fn verify_addition(a: u16, b: u16, expected: u16) -> bool {
let result = a + b;
result == expected
}
/// 두 수를 곱해서 결과가 예상한 값과 같은지 검증하는 함수
fn verify_multiplication(a: u16, b: u16, expected: u16) -> bool {
let result = a * b;
result == expected
}
#[starknet::contract]
mod VerifierContract {
use super::{verify_addition, verify_multiplication};
#[external(v0)]
fn verify_add_and_mul(x: u16, y: u16, expected_add: u16, expected_mul: u16) -> bool {
verify_addition(x, y, expected_add) && verify_multiplication(x, y, expected_mul)
}
}
Sepolia는 Starknet의 퍼블릭 테스트넷으로, 실제 메인넷 배포 전 테스트하기에 적합합니다. 이 섹션에서는 Sepolia 네트워크에서 계정을 생성하고, 컨트랙트를 선언/배포/호출하는 전체 과정을 설명합니다.
sncast account create \
--network=sepolia \
--name=sepolia-test-account
account create: 새로운 Starknet 계정 생성--network=sepolia: Sepolia 네트워크 대상으로 생성--name=...: 계정 이름을 snfoundry.toml에 저장할 때 사용할 alias생성 직후 해당 계정은 아직 배포되지 않은 상태이며,
DEPLOY_ACCOUNT트랜잭션 전송을 위해 사용 전 STRK로 충전 해야 합니다.
Starknet Sepolia Faucet에 접속하여 위에서 생성한 주소에 STRK 또는 ETH를 지급받습니다:
https://faucet.sepolia.starknet.io
STRK 토큰이 있어야 계정 배포(deploy) 및 트랜잭션 수수료 지불이 가능합니다.
sncast account deploy \
--network=sepolia \
--name=sepolia-test-account
account deploy: 생성한 계정을 Starknet Sepolia에 실제 배포예시 결과:
transaction: https://sepolia.starkscan.co/tx/0x...
sncast declare \
--account=sepolia-test-account \
--contract-name=VerifierContract \
--network=sepolia
declare: 스마트 컨트랙트의 클래스 코드를 네트워크에 등록하는 과정입니다.error: Transaction execution error = TransactionExecutionErrorData { transaction_index: 0, execution_error: Message("Class with hash 0x04eefd807f4b568213d65322e5031c08bfc4d496cf859ea3bcfdbff12e173bda is already declared.") }
위와 같이 class_hash가 이미 네트워크에 등록되어 있으면, 중복 선언이 감지되어 오류가 발생합니다. 이 경우에는 에러 메시지에 반환되는 기존 class_hash를 그대로 사용하여 배포(deploy) 단계를 진행하면 됩니다.
sncast deploy \
--account=sepolia-test-account \
--class-hash=0x... \
--network=sepolia
deploy: 선언한 class_hash를 바탕으로 컨트랙트 인스턴스를 배포합니다.--salt를 지정하면 배포 주소를 고정할 수도 있습니다.sncast call \
--contract-address=0x... \
--function=verify_add_and_mul \
--arguments=5,6,11,30 \
--network=sepolia
call: 상태 변경 없는 읽기 전용 함수를 실행합니다.5 + 6 == 11, 5 * 6 == 30인지 검증하는 함수입니다.출력 결과:
response: true
response_raw: [0x1]
| 단계 | 명령어 | 설명 |
|---|---|---|
| 계정 생성 | sncast account create --network=sepolia --name=... | 계정 정보를 로컬에 생성 |
| Faucet 사용 | Starknet Sepolia Faucet | 테스트용 STRK/ETH 지급 |
| 계정 배포 | sncast account deploy --network=sepolia --name=... | 계정 인스턴스를 네트워크에 배포 |
| 선언 | sncast declare --account=... --contract-name=... --network=sepolia | 스마트 컨트랙트 코드 등록 |
| 배포 | sncast deploy --account=... --class-hash=... --network=sepolia | class hash 기반으로 컨트랙트 생성 |
| 호출 | sncast call --contract-address=... --function=... --arguments=... --network=sepolia | 컨트랙트 함수 호출 (read-only) |