모든 컨트랙트/민팅/트랜스퍼 관련 보호 API는 x-api-key + X-CORPORATE-ID 헤더를 동시에 요구합니다. 예시:
x-api-key: ${GLOBAL_SECRET_KEY}
X-CORPORATE-ID: ${CORPORATE_ID}
/contracts/deploy컨트랙트를 즉시 배포하지 않고 Bull 큐에 작업으로 적재합니다. 응답은 MongoDB에 적재된 DeployedContract 문서입니다.
| Name | Required | Value |
|---|---|---|
| x-api-key | Yes | 서버에 설정된 글로벌 API 키 |
| X-CORPORATE-ID | Yes | corporateAccounts 컬렉션에 등록된 기업 ID |
| Content-Type | Yes | application/json |
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
chainId |
string | ✅ | 배포 대상 체인 ID (ALLOWED_CHAIN_IDS 환경 변수에서 정의, 기본값 43114) |
name |
string | ✅ | 컨트랙트 이름 (최대 50자) |
symbol |
string | ✅ | 심볼 (최대 8자) |
currentOwnerAddress |
string | ❌ | 배포 직후 소유자 주소. 미입력 시 서버가 기업 시크릿키 지갑 주소를 자동 설정합니다. |
ercStandard |
string | ✅ | '721' 또는 '1155' |
contractType |
string | ✅ | 'standard'(전송 가능) 또는 'certificate'(전송 불가·메타데이터 불변) |
royaltyReceiver |
string | ❌ | 로열티 수취 주소 (기본값: currentOwnerAddress) — certificate 타입은 미사용 |
royaltyFeeBps |
number | ❌ | basis point 단위 로열티 비율 (미입력 시 0%) — certificate 타입은 미사용 |
metadataBaseUri |
string(url) | ❌ | 배포 직후 컨트랙트에 세팅할 메타데이터 Base URI. 미입력 시 .env의 METADATA_BASE_URI를 사용하거나 비워둡니다. (certificate 타입은 무시) |
trustedForwarder |
string | ❌ | EIP-2771 Trusted Forwarder 주소. 미지정 시 .env의 기본값을 사용합니다. |
transferOwnerAddress |
string | ❌ | 배포 후 최종 오너로 즉시 이전할 주소. 입력 시 배포 → (서버가 오너일 때만) Base URI 설정 → transferOwnership를 자동 큐잉하여 이 주소로 이전합니다. |
curl -X POST https://api.example.com/contracts/deploy \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43114",
"name": "Miji Ticket",
"symbol": "MTKT",
// currentOwnerAddress 생략 가능. 미입력 시 기업 시크릿키 주소로 자동 설정됨
"ercStandard": "721",
"contractType": "standard",
"royaltyReceiver": "0x5678def0...def0",
"royaltyFeeBps": 750,
"metadataBaseUri": "https://api.example.com/metadata",
"trustedForwarder": "0x9876...5432",
"transferOwnerAddress": "0xExternalFinalOwner..." // 최종 오너
}'
curl -X POST https://api.example.com/contracts/deploy \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43114",
"name": "Miji Certificate",
"symbol": "MCERT",
// currentOwnerAddress 생략 가능. 미입력 시 기업 시크릿키 주소로 자동 설정됨
"ercStandard": "1155",
"contractType": "certificate",
"trustedForwarder": "0x9876...5432"
}'
certificate 타입은 전송/approve가 전부 차단됩니다. 민팅/소각만 가능하며, 메타데이터는 민팅 시 tokenUri + metadataHash로 불변 저장됩니다(민팅 API 참고).
Base URI 설정과 오너 이전 플로우
- Base URI 설정은 컨트랙트 오너인 서명자일 때만 실행됩니다. 배포 시
currentOwnerAddress를 서비스/기업 지갑으로 두고, 최종 오너를transferOwnerAddress에 지정하면 “배포 → Base URI 설정 → 소유권 이전”이 자동으로 이어집니다.currentOwnerAddress를 외부 지갑으로 배포하면 Base URI 설정은 건너뛰며(onlyOwner 미충족), 이후 오너가 직접 설정해야 합니다.transferOwnerAddress를 넣으면 배포 성공 후transferOwnership작업이 큐에 등록되고 웹훅(ownership.transferred/ownership.failed)으로 결과가 통지됩니다.
{
"_id": "6750121f7b3d9f1a6c4c4051",
"chainId": "43114",
"name": "Miji Ticket",
"symbol": "MTKT",
"ercStandard": "721",
"status": "DEPLOYING",
"currentOwnerAddress": "0x1234abcd...abcd",
"royaltyReceiver": "0x5678def0...def0",
"royaltyFeeBps": 750,
"createdAt": "2025-11-18T06:11:43.511Z",
"updatedAt": "2025-11-18T06:11:43.511Z"
}
이후 Processor가 성공적으로 배포하면 status가 ACTIVE, 주소/트랜잭션 해시가 채워집니다. 실패 시 FAILED와 errorMessage가 저장됩니다.
선택적으로 metadataBaseUri를 전달하면 배포 직후 컨트랙트에 다음과 같이 Base URI가 설정됩니다.
<metadataBaseUri>/<contractAddress>/ (컨트랙트 주소 소문자)<metadataBaseUri>/<contractAddress>/{id} ({id} 플레이스홀더는 OpenSea 규격)따라서 기본값을 https://api.example.com/metadata로 두면 민팅된 토큰의 tokenURI는
https://api.example.com/metadata/<contractAddress>/<tokenId> 형태가 되어, 본 서버의 GET /metadata/:contractAddress/:tokenId와 바로 호환됩니다.
/contracts/forwarderEIP-2771 MinimalForwarder 컨트랙트를 배포합니다. 대납(Gasless) 트랜잭션을 중계하는 인프라용 컨트랙트입니다.
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
chainId |
string | ✅ | 배포 대상 체인 ID |
alias |
string | ❌ | Forwarder 별칭 (관리용) |
curl -X POST https://api.example.com/contracts/forwarder \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43113",
"alias": "Fuji Forwarder 1"
}'
/contracts/read컨트랙트의 View(읽기 전용) 함수를 호출하여 현재 상태를 조회합니다. 가스비가 소모되지 않습니다.
기본적으로 ERC-721, ERC-1155, ERC-20 및 Forwarder의 표준 함수 ABI가 내장되어 있어 별도 abi 파라미터 없이 호출 가능합니다.
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
chainId |
string | ✅ | 조회할 체인 ID |
contractAddress |
string | ✅ | 컨트랙트 주소 |
method |
string | ✅ | 호출할 함수 이름 (예: ownerOf, balanceOf) |
args |
array | ❌ | 함수 인자 배열 |
abi |
array | ❌ | 커스텀 ABI (미지정 시 표준 ABI 사용) |
ownerOf)curl -X POST https://api.example.com/contracts/read \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43113",
"contractAddress": "0x1234...",
"method": "ownerOf",
"args": ["1"]
}'
Response: "0xabcd..." (토큰 1번의 소유자 주소)
ERC-721은
ownerOf(tokenId)로 단일 소유자 주소를 반환합니다.
balanceOf)curl -X POST https://api.example.com/contracts/read \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43113",
"contractAddress": "0x1234...",
"method": "balanceOf",
"args": ["0xOwnerAddress", "1"]
}'
Response: "5" (지갑이 보유한 해당 tokenId 수량, 문자열)
ERC-1155에서는
balanceOf(address, tokenId)로 조회해야 합니다. 721과 달리 주소/토큰ID 두 개 모두 필요합니다.
owner)curl -X POST https://api.example.com/contracts/read \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43113",
"contractAddress": "0x1234...",
"method": "owner"
}'
Response: "0xABCD..." (컨트랙트의 Ownable 오너 주소)
주의:
owner()는 컨트랙트 소유자(관리자 지갑)를 반환하고,ownerOf(tokenId)는 특정 토큰의 소유자를 반환합니다. 혼동하지 마세요.
getMetadataHash)curl -X POST https://api.example.com/contracts/read \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43113",
"contractAddress": "0x1234...",
"method": "getMetadataHash",
"args": ["1"]
}'
Response: "0x...metadataHash" (bytes32 문자열)
인증서(
contractType=certificate) 전용 메타데이터 불변성 검증에 사용합니다.
supportsInterface)curl -X POST https://api.example.com/contracts/read \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43113",
"contractAddress": "0x1234...",
"method": "supportsInterface",
"args": ["0x80ac58cd"]
}'
Response: true 또는 false
0x80ac58cd(ERC-721), 0xd9b67a26(ERC-1155), 0x2a55205a(ERC-2981) 등 표준 인터페이스 지원 여부를 확인할 수 있습니다.
누구나 온체인 호출로 검증할 수 있으며, 별도 서비스 종속이 필요 없습니다.
1) 온체인 해시 조회
getMetadataHash(tokenId) 호출(예: POST /contracts/read 또는 직접 RPC call) → bytes32 해시 확보.2) 오프체인 메타데이터 수집
tokenURI(721) 또는 uri(1155) 호출 → 메타데이터 URL 획득 → JSON 다운로드.3) 표준화(canonicalize) 후 SHA-256 해시 계산
4) 해시 비교
참고
/contracts/read API를 사용하면 ABI 없이도 표준 view 함수를 호출할 수 있습니다.tokenURI)curl -X POST https://api.example.com/contracts/read \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43113",
"contractAddress": "0x1234...",
"method": "tokenURI",
"args": ["1"]
}'
Response: "https://api.example.com/metadata/<contractAddress>/1"
ERC-721은
tokenURI(tokenId)를 호출합니다. 배포 시metadataBaseUri를 넣지 않았다면 호출 시 컨트랙트가 revert할 수 있습니다.
uri)curl -X POST https://api.example.com/contracts/read \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43113",
"contractAddress": "0x1234...",
"method": "uri",
"args": ["1"]
}'
Response: "https://api.example.com/metadata/<contractAddress>/{id}"
{id}는 OpenSea 규격대로 토큰 ID(16진수, 0x 접두어 없는 zero-pad)로 치환됩니다.
ERC-1155는
tokenURI메서드가 없으므로 반드시uri(tokenId)로 조회하세요. 배포 시metadataBaseUri가 비어 있으면 호출이 실패합니다.
isTrustedForwarder)대납(Gasless) 트랜잭션을 위해 특정 Forwarder 컨트랙트를 신뢰하는지 확인합니다.
curl -X POST https://api.example.com/contracts/read \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43113",
"contractAddress": "0xNFTContract...",
"method": "isTrustedForwarder",
"args": ["0xForwarderAddress..."]
}'
Response: true 또는 false (boolean)
/contracts/transfer-ownership컨트랙트 소유자를 온체인에서 변경합니다. 호출하면 작업이 큐에 적재되고, 처리 결과는 웹훅(ownership.transferred / ownership.failed)으로 전달됩니다. 호출 지갑은 해당 컨트랙트의 현재 오너(기업 시크릿키)여야 합니다.
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
chainId |
string | ✅ | 체인 ID |
contractAddress |
string | ✅ | 대상 컨트랙트 주소 |
newOwnerAddress |
string | ✅ | 변경할 새 오너 주소 |
curl -X POST https://api.example.com/contracts/transfer-ownership \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43114",
"contractAddress": "0x1234...",
"newOwnerAddress": "0xabcd..."
}'
{
"status": "QUEUED",
"jobId": "12345",
"contractId": "6750121f7b3d9f1a6c4c4051",
"contractAddress": "0x1234...",
"newOwner": "0xabcd..."
}
처리 완료 시 기업별 웹훅이 설정되어 있으면
ownership.transferred(성공) /ownership.failed(실패) 이벤트가 전달됩니다. 배포 시trustedForwarder를 올바르게 넣어두면, 추후 메타트랜잭션 기반 대납 민팅/운영을 재배포 없이 확장할 수 있습니다.
tokenUri (필수, 빈 값 불가)metadataHash (필수, SHA-256 bytes32, 0x.., 0x00..00 금지)amount > 0 필수getMetadataHash(tokenId)로 온체인 해시를 조회하여 오프체인 메타데이터와 비교 검증하세요.curl -X POST https://api.example.com/minting/orders \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43114",
"contractAddress": "0xCERT721...",
"receiverAddress": "0xReceiver...",
"tokenId": "1",
"metadataId": "6740f7a329d9f9323f8a9c91",
"tokenUri": "https://cdn.example.com/meta/1.json",
"metadataHash": "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}'
curl -X POST https://api.example.com/minting/orders \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}" \
-H "Content-Type: application/json" \
-d '{
"chainId": "43114",
"contractAddress": "0xCERT1155...",
"receiverAddress": "0xReceiver...",
"tokenId": "1001",
"amount": 1,
"metadataId": "6740f7a329d9f9323f8a9c91",
"tokenUri": "https://cdn.example.com/meta/1001.json",
"metadataHash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
}'
/contracts/:idPOST /contracts/deploy 호출 시 받은 _id를 사용해 현재 상태를 조회합니다.
| Name | Required | Value |
|---|---|---|
| x-api-key | Yes | 글로벌 API 키 |
| X-CORPORATE-ID | Yes | corporateAccounts 식별자 |
curl -X GET https://api.example.com/contracts/691c1552f28bd9c4cb602c0d \
-H "x-api-key: ${GLOBAL_SECRET_KEY}" \
-H "X-CORPORATE-ID: ${CORPORATE_ID}"
DeployedContract 문서를 그대로 반환합니다. 상태/주소/트랜잭션 해시/오류 메시지를 확인할 수 있습니다.