For the complete documentation index, see llms.txt
Create your first Midnight contract
이 quick start는 환경이 Compact 컨트랙트를 컴파일하고 테스트할 수 있는지 점검하고, Compact이 어떤 모습인지 보여줍니다. 메시지를 저장하는 컨트랙트를 작성해 컴파일하고, example-hello-world 리포지토리의 테스트를 로컬 네트워크에서 실행합니다. 테스트 토큰이나 공개 네트워크는 필요하지 않습니다.
Prerequisites
- Compact toolchain 0.31.1 버전. Install the toolchain을 따라 설치한 뒤
compact compile --version으로 확인하세요. 각 네트워크가 지원하는 버전은 support matrix에 정리돼 있습니다. - Node.js 22 또는 24. 프로젝트 의존성은 Node.js 23에서는 설치되지 않습니다.
- Yarn.
corepack enable을 한 번 실행하면 프로젝트가 고정해 둔 Yarn 버전을 사용합니다. - 실행 중인 Docker Desktop, 또는 Compose v2를 지원하는 다른 Docker 엔진.
- Git.
Set up the project
리포지토리를 클론하고 의존성을 설치하세요:
git clone https://github.com/midnightntwrk/example-hello-world.git
cd example-hello-world
yarn install
이후의 모든 명령은 example-hello-world 디렉터리에서 실행하세요.
Write the contract
다음 내용으로 contracts/hello-world.compact를 생성하세요:
pragma language_version 0.23;
export ledger message: Opaque<"string">;
export circuit storeMessage(newMessage: Opaque<"string">): [] {
message = disclose(newMessage);
}
pragma language_version 0.23;은 Compact 언어 버전을 선언합니다. 컴파일러가 해당 버전을 지원하지 않으면 파일을 거부합니다.export ledger message는 공개 온체인 상태를 선언합니다. 문자열을 담는message라는 필드입니다.export circuit storeMessage는 circuit을 선언합니다. circuit은 트랜잭션이 호출하는 함수에 해당하는 Compact의 구성 요소입니다.newMessage는 비공개입니다. circuit 인자는 기본적으로 비공개이기 때문입니다.disclose()는 그 값을 ledger에 저장해 공개하겠다는 의도를 컴파일러에 알립니다. 이 함수가 없으면potential witness-value disclosure must be declared but is not오류와 함께 컴파일이 실패합니다.
Compile the contract
컴파일 스크립트를 실행하세요:
yarn compile
스크립트는 compact compile contracts/hello-world.compact contracts/managed/hello-world를 실행합니다. 컴파일러는 컨트랙트를 영지식 circuit으로 변환하고, proving key와 verifier key를 생성하며, DApp 코드가 가져다 쓰는 JavaScript와 TypeScript를 만듭니다. 출력에는 circuit 하나가 표시됩니다:
Compiling 1 circuits:
circuit "storeMessage" (k=6, rows=26)
Overall progress [====================] 1/1
스크립트나 코딩 에이전트에서 명령을 실행하면 첫 줄만 보입니다. 정작 확인해야 할 것은 아래의 파일들입니다.
출력은 contracts/managed/hello-world에 생성됩니다:
contracts/managed/hello-world/
├── compiler/ contract-info.json, a description of the contract for other tools
├── contract/ index.js and index.d.ts, the contract implementation
├── keys/ storeMessage.prover and storeMessage.verifier
└── zkir/ storeMessage.zkir and storeMessage.bzkir, the circuit in ZKIR
Test the contract on a local network
리포지토리의 테스트는 컴파일한 컨트랙트를 배포하고, Hello World!로 storeMessage를 호출한 뒤, ledger에서 메시지를 다시 읽어 옵니다. 테스트는 Docker에서 돌아가는 로컬 네트워크를 상대로 실행되며, 네트워크가 시작될 때 자금이 충전되는 지갑을 사용합니다.
-
로컬 네트워크를 시작하세요:
yarn env:upMidnight node, indexer, proof server가 시작되고 셋 모두 정상 상태가 되면 반환됩니다.
-
지갑의 DUST를 사용할 수 있을 때까지 기다리세요:
yarn wait:dust갓 띄운 네트워크는 지갑이 수수료를 낼 수 있기까지 몇 초가 필요합니다. 스크립트는
DUST ready를 출력하고 종료됩니다. -
테스트를 실행하세요:
yarn test:local실행이 끝나면 테스트 두 개가 모두 통과합니다:
[11:53:49.163] INFO (63955): Wallet sync complete after 23 emissions[11:53:49.174] INFO (63955): Providers initialized on 'local'. Ready to test![11:53:49.177] INFO (63955): Creating private state...[11:54:09.014] INFO (63955): Setting the contract address...[11:54:09.014] INFO (63955): Contract deployed at: 2e5b69411fcabd3e803fd2971fdae2ffe4482e7f3d0174d50b8a4f0f3abb29fb✓ src/test/hw.test.ts (2 tests) 37897ms✓ Deploys the contract 19846ms✓ Stores Hello World! 17347msTest Files 1 passed (1)Tests 2 passed (2)컨트랙트 주소와 소요 시간은 환경마다 다릅니다. 두 테스트가 모두 통과하면 환경이 준비된 것입니다.
-
로컬 네트워크를 중지하세요:
yarn env:down
Troubleshooting
| Symptom | Fix |
|---|---|
language version X.Y.Z mismatch (X.Y.Z는 컴파일러의 언어 버전, 예: 0.22.0) | 컴파일러가 컨트랙트의 언어 버전을 지원하지 않습니다. compact update 0.31.1로 toolchain 0.31.1을 설치하세요. |
Cannot find module './managed/hello-world/contract/index.js' | 컨트랙트가 컴파일되지 않았습니다. 테스트 전에 yarn compile을 실행하세요. |
Cannot connect to the Docker daemon | Docker가 실행되고 있지 않습니다. Docker Desktop을 시작하고 엔진이 올라올 때까지 기다린 뒤 yarn env:up을 다시 실행하세요. |
첫 시작에서 yarn env:up이 container ...-indexer-1 exited (1)로 실패 | node가 첫 블록을 생성하기 전에 indexer가 먼저 시작됐습니다. yarn env:up을 다시 실행하세요. |
테스트 도중 Wallet.InsufficientFunds | 지갑의 DUST가 사용 가능해지기 전에 테스트가 실행됐습니다. yarn wait:dust를 실행한 뒤 yarn test:local을 다시 실행하세요. |
RPC-CORE: subscribeRuntimeVersion(): RuntimeVersion:: disconnected ... 1000:: Normal Closure | 오류가 아닙니다. 지갑 설정 중 연결이 정상적으로 닫히는 것이며, 실행은 계속됩니다. |
Next steps
- Make your contract private: 이 컨트랙트는 메시지를 공개된 채로 저장합니다. witness와 commitment로 컨트랙트의 입력을 ledger 밖에 두세요.
- Bulletin board tutorial: private state를 쓰는 컨트랙트부터 CLI까지, 완전한 DApp을 만들어 봅니다.
- Deploying and operating a contract: 컨트랙트를 배포하고 호출하는 TypeScript를 작성합니다.
- Networks and environments: 로컬 네트워크에서 Preprod로 넘어갑니다.
- Compact language reference: 언어 전체 레퍼런스.
- Examples: 읽고 실행할 수 있는 완전한 DApp 모음.