CDR 볼트는 DATA Foundation의 라이선스 토큰 뒤에 게이팅되어 라이선스 보유자만이
볼트 콘텐츠를 복호화할 수 있도록 할 수 있습니다. 현재 Aeneid 릴리스에서는
이것이 수동 통합입니다: CDR 조건 데이터를 직접 인코딩하고 DATA Foundation
라이선스 토큰을 별도로 발행합니다.
사전 요구 사항
Aeneid 컨트랙트
| 컨트랙트 | 주소 |
|---|
| OwnerWriteCondition | 0x4C9bFC96d7092b590D497A191826C3dA2277c34B |
| LicenseReadCondition | 0xC0640AD4CF2CaA9914C8e5C44234359a9102f7a3 |
| LicenseToken | 0xFe3838BFb30B34170F00030B52eA4893d8aAC6bC |
DATA Foundation 라이선스 읽기 패턴이 작동하는 방식
모든 CDR 볼트에는 writeConditionAddr 및 readConditionAddr가 있습니다. Aeneid에서
DATA Foundation 라이선스 게이트 볼트의 경우:
writeConditionAddr는 일반적으로 OwnerWriteCondition을 가리키며,
writeConditionData = abi.encode(ownerAddress)입니다
readConditionAddr는 LicenseReadCondition을 가리키며,
readConditionData = abi.encode(licenseTokenAddress, ipId)입니다
- 읽기 시점의
accessAuxData는
abi.encode(uint256[] licenseTokenIds)입니다
CDR SDK는 IP Asset을 등록하거나 라이선스 토큰을 발행해주지 않습니다. 먼저
DATA Foundation 도구로 IP를 생성하고 그 ipId를 얻은 다음 볼트를 구성하세요.
자산을 아직 등록하지 않았다면 IP Asset 등록에서
시작하세요. 발행 전에 라이선스 조건을 첨부하거나 검사해야 한다면,
Attach Terms를 참조하세요.
라이선스 게이트 볼트 업로드
import { encodeAbiParameters } from "viem";
const globalPubKey = await client.observer.getGlobalPubKey();
const dataKey = new TextEncoder().encode("confidential IP content");
const writeCondData = encodeAbiParameters(
[{ type: "address" }],
[uploaderAddress],
);
const readCondData = encodeAbiParameters(
[{ type: "address" }, { type: "address" }],
[
"0xFe3838BFb30B34170F00030B52eA4893d8aAC6bC",
ipId,
],
);
await client.uploader.uploadCDR({
dataKey,
globalPubKey,
updatable: false,
writeConditionAddr: "0x4C9bFC96d7092b590D497A191826C3dA2277c34B",
writeConditionData: writeCondData,
readConditionAddr: "0xC0640AD4CF2CaA9914C8e5C44234359a9102f7a3",
readConditionData: readCondData,
accessAuxData: "0x",
});
암호화된 콘텐츠가 오프체인에 있는 경우 동일한 조건 설정이 uploadFile()과 함께
작동합니다.
읽기 전 라이선스 토큰 발행
사용자가 DATA Foundation 라이선스 게이트 볼트를 읽기 전에 여전히 라이선스
토큰을 발행해야 합니다. DATA Foundation 코어 SDK의 wipClient는 WIP 래핑 및
승인 단계를 처리하므로 독자가 세 번의 짧은 호출로 IP를 래핑하고,
RoyaltyModule을 승인하고, 발행할 수 있습니다.
WIP는 Wrapped IP로, 네이티브 IP 토큰의 ERC-20 래핑 형태입니다.
DATA Foundation의 로열티 / 라이선스 흐름은 WIP를 사용하므로 독자는 먼저 IP를
래핑한 다음 RoyaltyModule이 이를 사용하도록 승인합니다.
import { parseEther, http } from "viem";
import { StoryClient } from "@story-protocol/core-sdk";
const ROYALTY_MODULE = "0xD2f60c40fEbccf6311f8B47c4f2Ec6b040400086";
const storyClient = StoryClient.newClient({
transport: http("https://aeneid.datarpc.io"),
account: readerAccount,
chainId: "aeneid",
});
// 1. Wrap 1 IP → 1 WIP so the mint fee can be paid in WIP.
await storyClient.wipClient.deposit({
amount: parseEther("1"),
});
// 2. Approve the RoyaltyModule to spend WIP for the mint.
await storyClient.wipClient.approve({
spender: ROYALTY_MODULE,
amount: parseEther("1"),
});
// 3. Mint the DATA Foundation license token.
const mintResult = await storyClient.license.mintLicenseTokens({
licensorIpId: ipId,
licenseTermsId: BigInt(2054),
amount: 1,
});
const licenseTokenId = mintResult.licenseTokenIds![0];
licenseTermsId: 2054는 예시일 뿐입니다. 실제로 IP Asset에 첨부된 라이선스
조건 ID로 교체하세요. 자산을 등록하거나 조건을 첨부할 때 해당 ID를 받게
됩니다.
위의 래핑, 승인 및 발행 호출은 모두 온체인 트랜잭션입니다. 이후의
accessCDR() 호출은 한 번의 온체인 읽기 요청을 추가합니다.
라이선스 토큰으로 읽기
읽기 시점에 호출자의 라이선스 토큰 ID를 accessAuxData를 통해 전달합니다.
import { encodeAbiParameters } from "viem";
const accessAuxData = encodeAbiParameters(
[{ type: "uint256[]" }],
[[BigInt(licenseTokenId)]],
);
// Sends 1 read transaction, then collects partials and combines locally
const { dataKey } = await client.consumer.accessCDR({
uuid,
accessAuxData,
timeoutMs: 120_000,
});
const content = new TextDecoder().decode(dataKey);
console.log(`Decrypted IP content: ${content}`);
호출자가 볼트의 IP Asset에 대한 유효한 라이선스 토큰을 보유하지 않은 경우,
읽기 요청은 온체인에서 되돌려지며 검증자들은 부분 복호화를 생성하지 않습니다.
사용자 정의 조건 컨트랙트
라이선스 게이팅은 하나의 패턴일 뿐입니다. 다음 인터페이스 중 하나 또는 둘 다를
구현하여 모든 접근 제어 로직에 대해 자체 조건 컨트랙트를 배포할 수 있습니다:
interface ICDRWriteCondition {
function checkWriteCondition(
uint32 uuid,
bytes calldata accessAuxData,
bytes calldata conditionData,
address caller
) external view returns (bool);
}
interface ICDRReadCondition {
function checkReadCondition(
uint32 uuid,
bytes calldata accessAuxData,
bytes calldata conditionData,
address caller
) external view returns (bool);
}
CDR 컨트랙트는 write() 또는 read() 작업을 허용하기 전에 이러한 함수를 호출합니다.
허용하려면 true를 반환하고, 거부하려면 false를 반환하세요. 그런 다음 볼트를 할당할 때
조건 컨트랙트 주소를 readConditionAddr 또는 writeConditionAddr로 전달하세요.