완성된 코드

완성된 코드를 끝까지 따라가세요.

이 섹션에서는 License TokenIP Asset에서 발행하는 방법을 보여줍니다. IP Asset에 License Terms가 첨부된 경우에만 License Token을 발행할 수 있습니다. License Token은 ERC-721로 발행됩니다.

License Token을 발행하는 두 가지 이유가 있습니다:

  1. 라이선스를 보유하고 라이선스에 설명된 대로 기본 IP Asset을 사용할 수 있도록 하기 위해 (예: “적절한 귀속을 제공하고 수익의 5%를 공유하는 한 상업적으로 사용할 수 있음”)
  2. 라이선스 토큰을 사용하여 다른 IP Asset을 그것의 파생작으로 연결하기 위해. 하지만 나중에 보시겠지만, 일부 SDK 함수는 파생작을 등록하기 위해 명시적으로 라이선스 토큰을 먼저 발행할 필요가 없으며, 실제로 뒤에서 이를 처리합니다.

전제 조건

튜토리얼을 시작하기 전에 완료해야 할 몇 가지 단계가 있습니다.

  1. 완료하세요 자체 프로젝트 설정
  2. IP Asset에 License Terms가 첨부되어 있어야 합니다. 방법은 여기

라이선스 발행

IP Asset (ipId = 0x01)에 License Terms (licenseTermdId = 10)가 첨부되어 있다고 가정해 봅시다. 우리는 이 조건으로 2개의 License Token을 특정 지갑 주소 (0x02)로 발행하고 싶습니다.

유료 라이선스

일부 IP Asset에는 라이선스를 발행하는 사용자가 mintingFee를 지불해야 하는 라이선스 조건이 첨부되어 있을 수 있음을 유의하세요.

작동을 확인하고 결과를 검증하기 위해 test/3_LicenseToken.t.sol 아래에 테스트 파일을 만들어 봅시다:

계약 주소

Story 컨트랙트의 주소를 여러분을 위해 미리 채워 넣었습니다. 하지만 여기에서도 해당 주소들을 찾을 수 있습니다:배포된 스마트 컨트랙트

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.storyrpc.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.story.foundation/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.storyrpc.io/ --match-path test/3_LicenseToken.t.sol

파생작 등록하기

완성된 코드

완성된 코드를 끝까지 따라가보세요.

이제 라이선스 토큰을 발행했으니, 이를 보유하거나 IP 자산을 파생작으로 연결하는 데 사용할 수 있습니다. 다음 페이지에서 이에 대해 살펴보겠습니다.