완성된 코드
완성된 코드를 끝까지 따라가 보세요.
이 섹션에서는 IP Asset으로부터 라이선스 토큰(License Token)을 민팅하는 방법을 설명합니다. IP Asset에 라이선스 약관(License Terms)이 첨부되어 있어야만 해당 IP Asset에서 라이선스 토큰을 민팅할 수 있습니다. 라이선스 토큰은 ERC-721로 민팅됩니다.
라이선스 토큰을 민팅하는 이유는 두 가지입니다:
- 라이선스를 보유하고, 라이선스에 명시된 조건으로 기반 IP Asset을 사용할 수 있게 하기 위함 (예: “적절한 출처 표시를 하고 수익의 5%를 공유하는 한 상업적 사용 가능”)
- 라이선스 토큰을 사용해 다른 IP Asset을 그 IP의 파생물로 연결하기 위함. 다만 이후에 보게 되겠지만, 일부 SDK 함수들은 파생물을 등록하기 위해 라이선스 토큰을 먼저 명시적으로 민팅할 필요 없이 내부적으로 알아서 처리해 줍니다.
사전 준비
튜토리얼을 시작하기 전에 몇 가지 단계를 완료해야 합니다.
- 자체 프로젝트 설정하기를 완료하세요.
- 라이선스 약관이 첨부된 IP Asset이 있어야 합니다. 방법은 여기에서 확인할 수 있습니다.
라이선스 민팅
IP Asset (ipId = 0x01)에 라이선스 약관 (licenseTermdId = 10)이 첨부되어 있다고 가정합시다. 이 약관이 적용된 라이선스 토큰 2개를 특정 지갑 주소 (0x02)로 민팅하려고 합니다.
유료 라이선스일부 IP Asset에는 라이선스 약관이 첨부되어 있을 수 있으며, 라이선스를 민팅하는 사용자에게 mintingFee를 요구할 수 있다는 점을 유의하세요.
test/3_LicenseToken.t.sol에 테스트 파일을 만들어 동작 및 결과를 확인해 봅시다:
컨트랙트 주소DATA Foundation 컨트랙트 주소를 미리 채워 두었습니다. 주소는 배포된 스마트 컨트랙트에서도 확인할 수 있습니다.
test/3_LicenseToken.t.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;
import { Test } from "forge-std/Test.sol";
// for testing purposes only
import { MockIPGraph } from "@storyprotocol/test/mocks/MockIPGraph.sol";
import { IIPAssetRegistry } from "@storyprotocol/core/interfaces/registries/IIPAssetRegistry.sol";
import { IPILicenseTemplate } from "@storyprotocol/core/interfaces/modules/licensing/IPILicenseTemplate.sol";
import { ILicensingModule } from "@storyprotocol/core/interfaces/modules/licensing/ILicensingModule.sol";
import { ILicenseToken } from "@storyprotocol/core/interfaces/ILicenseToken.sol";
import { RoyaltyPolicyLAP } from "@storyprotocol/core/modules/royalty/policies/LAP/RoyaltyPolicyLAP.sol";
import { PILFlavors } from "@storyprotocol/core/lib/PILFlavors.sol";
import { PILTerms } from "@storyprotocol/core/interfaces/modules/licensing/IPILicenseTemplate.sol";
import { SimpleNFT } from "../src/mocks/SimpleNFT.sol";
// Run this test:
// forge test --fork-url https://aeneid.datarpc.io/ --match-path test/3_LicenseToken.t.sol
contract LicenseTokenTest is Test {
address internal alice = address(0xa11ce);
address internal bob = address(0xb0b);
// For addresses, see https://docs.datafdn.org/developers/deployed-smart-contracts
// Protocol Core - IPAssetRegistry
IIPAssetRegistry internal IP_ASSET_REGISTRY = IIPAssetRegistry(0x77319B4031e6eF1250907aa00018B8B1c67a244b);
// Protocol Core - LicensingModule
ILicensingModule internal LICENSING_MODULE = ILicensingModule(0x04fbd8a2e56dd85CFD5500A4A4DfA955B9f1dE6f);
// Protocol Core - PILicenseTemplate
IPILicenseTemplate internal PIL_TEMPLATE = IPILicenseTemplate(0x2E896b0b2Fdb7457499B56AAaA4AE55BCB4Cd316);
// Protocol Core - RoyaltyPolicyLAP
address internal ROYALTY_POLICY_LAP = 0xBe54FB168b3c982b7AaE60dB6CF75Bd8447b390E;
// Protocol Core - LicenseToken
ILicenseToken internal LICENSE_TOKEN = ILicenseToken(0xFe3838BFb30B34170F00030B52eA4893d8aAC6bC);
// Revenue Token - MERC20
address internal MERC20 = 0xF2104833d386a2734a4eB3B8ad6FC6812F29E38E;
SimpleNFT public SIMPLE_NFT;
uint256 public tokenId;
address public ipId;
uint256 public licenseTermsId;
function setUp() public {
// this is only for testing purposes
// due to our IPGraph precompile not being
// deployed on the fork
vm.etch(address(0x0101), address(new MockIPGraph()).code);
SIMPLE_NFT = new SimpleNFT("Simple IP NFT", "SIM");
tokenId = SIMPLE_NFT.mint(alice);
ipId = IP_ASSET_REGISTRY.register(block.chainid, address(SIMPLE_NFT), tokenId);
licenseTermsId = PIL_TEMPLATE.registerLicenseTerms(
PILFlavors.commercialRemix({
mintingFee: 0,
commercialRevShare: 10 * 10 ** 6, // 10%
royaltyPolicy: ROYALTY_POLICY_LAP,
currencyToken: MERC20
})
);
vm.prank(alice);
LICENSING_MODULE.attachLicenseTerms(ipId, address(PIL_TEMPLATE), licenseTermsId);
}
/// @notice Mints license tokens for an IP Asset.
/// Anyone can mint a license token.
function test_mintLicenseToken() public {
uint256 startLicenseTokenId = LICENSING_MODULE.mintLicenseTokens({
licensorIpId: ipId,
licenseTemplate: address(PIL_TEMPLATE),
licenseTermsId: licenseTermsId,
amount: 2,
receiver: bob,
royaltyContext: "", // for PIL, royaltyContext is empty string
maxMintingFee: 0,
maxRevenueShare: 0
});
assertEq(LICENSE_TOKEN.ownerOf(startLicenseTokenId), bob);
assertEq(LICENSE_TOKEN.ownerOf(startLicenseTokenId + 1), bob);
}
}
코드 테스트하기!
forge build를 실행하세요. 모든 것이 정상이라면 명령이 성공적으로 컴파일되어야 합니다.
이제 다음 명령을 실행하여 테스트를 진행하세요:
forge test --fork-url https://aeneid.datarpc.io/ --match-path test/3_LicenseToken.t.sol
파생물 등록하기
완성된 코드
완성된 코드를 끝까지 따라가 보세요.
이제 라이선스 토큰을 민팅했으니, 보유하거나 IP Asset을 파생물로 연결하는 데 사용할 수 있습니다. 다음 페이지에서 다루겠습니다.