Example integration
미리 작성된 스마트 컨트랙트와 API, 바로 쓸 수 있는 코드 스니펫으로 Midnight Network 개발을 빠르게 시작하세요.
Try the project
로컬에서 전체 설정을 테스트하려면 아래 단계를 따르세요:
Repository: https://github.com/MeshJS/midnight-setup
Clone the repository
HTTPS 또는 SSH로 저장소를 복제하세요.
- using https:
git clone https://github.com/MeshJS/midnight-setup.git
- using ssh:
git clone git@github.com:MeshJS/midnight-setup.git
Navigate to the folder
복제한 디렉터리로 이동하세요.
cd midnight-setup
Install dependencies
워크스페이스 의존성을 설치하세요.
yarn install
Set environment variable
UI 앱에 사용할 네트워크 ID를 설정하세요.
cd packages/ui && echo 'VITE_NETWORK_ID="TestNet"' > .env
Build all packages
모노레포 전체를 빌드하세요.
cd ../../ && yarn build:all
Download fetch parameters
로컬 실행에 필요한 ZK 파라미터를 다운로드하세요.
cd packages/cli && ./fetch-zk-params.sh
Start testnet with Docker
Docker Compose로 로컬 테스트넷을 시작하세요.
docker-compose -f testnet.yml up -d
Run the frontend
UI 앱 개발 서버를 시작하세요.
cd ../ui && yarn start
http://localhost:8080에서 애플리케이션에 접속할 수 있습니다.
Provider setup
컨트랙트 API를 사용하기 전에 프로바이더를 설정하세요.
import { FetchZkConfigProvider } from "@midnight-ntwrk/midnight-js-fetch-zk-config-provider";
import { httpClientProofProvider } from "@midnight-ntwrk/midnight-js-http-client-proof-provider";
import { indexerPublicDataProvider } from "@midnight-ntwrk/midnight-js-indexer-public-data-provider";
import { levelPrivateStateProvider } from "@midnight-ntwrk/midnight-js-level-private-state-provider";
import type { MidnightSetupContractProviders } from "@meshsdk/midnight-setup";
export async function setupProviders(): Promise<MidnightSetupContractProviders> {
const wallet = window.midnight?.mnLace;
if (!wallet) {
throw new Error("Please install Lace Beta Wallet for Midnight Network");
}
const walletAPI = await wallet.enable();
const walletState = await walletAPI.state();
const uris = await wallet.serviceUriConfig();
return {
privateStateProvider: levelPrivateStateProvider({
privateStateStoreName: "my-dapp-state",
}),
zkConfigProvider: new FetchZkConfigProvider(
window.location.origin,
fetch.bind(window),
),
proofProvider: httpClientProofProvider(uris.proverServerUri),
publicDataProvider: indexerPublicDataProvider(
uris.indexerUri,
uris.indexerWsUri,
),
walletProvider: {
coinPublicKey: walletState.coinPublicKey,
encryptionPublicKey: walletState.encryptionPublicKey,
balanceTx: (tx, newCoins) => {
return walletAPI.balanceAndProveTransaction(tx, newCoins);
},
},
midnightProvider: {
submitTx: (tx) => {
return walletAPI.submitTransaction(tx);
},
},
};
}
Core operations
SDK의 핵심 컨트랙트 워크플로 예제입니다.
Deploy a contract
새 컨트랙트를 배포하고 주소를 확인합니다.
import { MidnightSetupAPI } from "@meshsdk/midnight-setup";
import { setupProviders } from "./providers";
async function deployContract() {
const providers = await setupProviders();
const contractInstance = new MyContract({});
const api = await MidnightSetupAPI.deployContract(providers, contractInstance);
console.log("Contract deployed at:", api.deployedContractAddress);
return api;
}
Join existing contract
주소로 이미 배포된 컨트랙트에 연결합니다.
async function joinContract(contractAddress: string) {
const providers = await setupProviders();
const contractInstance = new MyContract({});
const api = await MidnightSetupAPI.joinContract(providers, contractInstance, contractAddress);
return api;
}
Read contract state
컨트랙트 상태와 원장 상태를 조회합니다.
// Get contract state
const contractState = await api.getContractState();
console.log("Contract data:", contractState.data);
// Get ledger state
const ledgerState = await api.getLedgerState();
console.log("Message:", ledgerState.ledgerState?.message);
React integration
아래 훅과 컴포넌트 패턴으로 SDK를 React 앱에 연결하세요.
Custom hook
배포와 참여 로직을 재사용 가능한 React 훅으로 감쌉니다.
import { useState, useCallback } from 'react';
import { MidnightSetupAPI } from '@meshsdk/midnight-setup';
import { setupProviders } from './providers';
export const useMidnightContract = () => {
const [api, setApi] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const deployContract = useCallback(async (contractInstance) => {
setIsLoading(true);
setError(null);
try {
const providers = await setupProviders();
const newApi = await MidnightSetupAPI.deployContract(providers, contractInstance);
setApi(newApi);
return newApi;
} catch (err) {
setError(err.message);
throw err;
} finally {
setIsLoading(false);
}
}, []);
const joinContract = useCallback(async (contractInstance, address) => {
setIsLoading(true);
setError(null);
try {
const providers = await setupProviders();
const newApi = await MidnightSetupAPI.joinContract(providers, contractInstance, address);
setApi(newApi);
return newApi;
} catch (err) {
setError(err.message);
throw err;
} finally {
setIsLoading(false);
}
}, []);
return {
api,
deployContract,
joinContract,
isLoading,
error
};
};
React component
위 훅을 사용한 간단한 컨트랙트 관리 UI 예제입니다.
import React, { useState } from 'react';
import { useMidnightContract } from './hooks/useMidnightContract';
function ContractManager() {
const {
api,
deployContract,
joinContract,
isLoading,
error
} = useMidnightContract();
const [contractAddress, setContractAddress] = useState('');
const handleDeploy = async () => {
try {
const contractInstance = new MyContract({});
const newApi = await deployContract(contractInstance);
console.log('Deployed:', newApi.deployedContractAddress);
} catch (err) {
console.error('Deploy failed:', err);
}
};
const handleJoin = async () => {
try {
const contractInstance = new MyContract({});
await joinContract(contractInstance, contractAddress);
console.log('Joined contract:', contractAddress);
} catch (err) {
console.error('Join failed:', err);
}
};
return (
<div className="contract-manager">
<h2>Contract Manager</h2>
{error && (
<div className="error">Error: {error}</div>
)}
<div className="actions">
<button onClick={handleDeploy} disabled={isLoading}>
{isLoading ? 'Deploying...' : 'Deploy Contract'}
</button>
<div className="join-section">
<input
type="text"
placeholder="Contract Address"
value={contractAddress}
onChange={(e) => setContractAddress(e.target.value)}
/>
<button onClick={handleJoin} disabled={isLoading}>
Join Contract
</button>
</div>
</div>
</div>
);
}
Error handling
아래 패턴으로 SDK 오류를 처리하고 UI를 보호하세요.
Common error patterns
알려진 SDK 오류를 사용자 친화적 메시지로 변환합니다.
const handleMidnightError = (error: Error) => {
if (error.message.includes('Please install Lace Beta Wallet')) {
return 'Please install Lace Beta Wallet for Midnight Network';
}
if (error.message.includes('Insufficient funds')) {
return 'Insufficient funds for transaction';
}
if (error.message.includes('Contract not found')) {
return 'Contract address not found or invalid';
}
return 'An unexpected error occurred';
};
Error boundary
렌더링 오류를 잡아서 폴백 UI를 표시합니다.
import React from 'react';
export class MidnightErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.error('Midnight Error:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
<div className="error-fallback">
<h2>Something went wrong with Midnight Network</h2>
<button onClick={() => window.location.reload()}>
Reload Page
</button>
</div>
);
}
return this.props.children;
}
}