완성된 코드

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

오프체인 IP(예: 책, 캐릭터, 그림 등)가 있다고 가정해 봅시다. Story에서 해당 IP를 등록하려면 먼저 NFT를 발행해야 합니다. 이 NFT는 IP에 대한 소유권입니다. 그런 다음 해당 NFT를 Story에 등록하여 IP 자산으로 만듭니다. 아래 튜토리얼에서 이 과정을 안내해 드리겠습니다.

전제 조건

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

  1. 다음을 완료하세요: 자체 프로젝트 설정하기

시작하기 전에

두 가지 시나리오가 있습니다:

  1. 이미 사용자 정의 ERC-721 NFT 계약이 있고 이를 통해 발행할 수 있습니다
  2. 발행을 위한 SPG (Periphery) NFT 계약을 생성하고 싶습니다

시나리오 #1: 이미 사용자 정의 ERC-721 NFT 계약이 있고 이를 통해 발행할 수 있습니다

이미 NFT를 발행했거나 사용자 정의 ERC-721 계약을 사용하여 IP를 등록하려는 경우 이 섹션을 참조하세요.

아래에서 볼 수 있듯이 등록 과정은 비교적 간단합니다. 우리는SimpleNFT을 예시로 사용하지만, 여러분은 자신의 ERC-721 계약으로 대체할 수 있습니다.

해야 할 일은 단순히registerIP Asset Registry with:

  • chainid- 간단히block.chainid
  • tokenContract- NFT 컬렉션의 주소
  • tokenId- NFT의 ID

테스트 파일을test/0_IPARegistrar.t.sol에 생성하여 작동을 확인하고 결과를 검증해 보겠습니다:

계약 주소

Story 계약의 주소를 여러분을 위해 미리 입력해 두었습니다. 하지만 여기에서도 해당 주소를 찾을 수 있습니다:배포된 스마트 계약

테스트에 사용하는SimpleNFT계약을 여기에서 볼 수 있습니다here.

테스트에 사용하는SimpleNFT계약을 여기에서 볼 수 있습니다here.

test/0_IPARegistrar.t.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

import { Test } from "forge-std/Test.sol";
import { IIPAssetRegistry } from "@storyprotocol/core/interfaces/registries/IIPAssetRegistry.sol";

// your own ERC-721 NFT contract
import { SimpleNFT } from "../src/mocks/SimpleNFT.sol";

// Run this test:
// forge test --fork-url https://aeneid.storyrpc.io/ --match-path test/0_IPARegistrar.t.sol
contract IPARegistrarTest is Test {
    address internal alice = address(0xa11ce);

    // For addresses, see https://docs.story.foundation/developers/deployed-smart-contracts
    // Protocol Core - IPAssetRegistry
    IIPAssetRegistry internal IP_ASSET_REGISTRY = IIPAssetRegistry(0x77319B4031e6eF1250907aa00018B8B1c67a244b);

    SimpleNFT public SIMPLE_NFT;

    function setUp() public {
        // Create a new Simple NFT collection
        SIMPLE_NFT = new SimpleNFT("Simple IP NFT", "SIM");
    }

    /// @notice Mint an NFT and then register it as an IP Asset.
    function test_register() public {
        uint256 expectedTokenId = SIMPLE_NFT.nextTokenId();
        address expectedIpId = IP_ASSET_REGISTRY.ipId(block.chainid, address(SIMPLE_NFT), expectedTokenId);

        uint256 tokenId = SIMPLE_NFT.mint(alice);
        address ipId = IP_ASSET_REGISTRY.register(block.chainid, address(SIMPLE_NFT), tokenId);

        assertEq(tokenId, expectedTokenId);
        assertEq(ipId, expectedIpId);
        assertEq(SIMPLE_NFT.ownerOf(tokenId), alice);
    }
}

시나리오 #2: SPG NFT 계약을 생성하여 발행을 대신하고 싶은 경우

자체 사용자 정의 NFT 계약이 없다면 이 섹션을 참조하세요.

이를 위해 우리는SPG를 사용할 것입니다. 이는 여러 트랜잭션을 하나로 결합할 수 있게 해주는 유틸리티 계약입니다. 이 경우, SPG의mintAndRegisterIp함수를 사용하여 NFT 발행과 IP 자산으로의 등록을 동시에 수행합니다.

를 사용하기 위해서는mintAndRegisterIp먼저 새로운SPGNFT컬렉션을 생성해야 합니다. 이는 단순히createCollectionStoryProtocolGateway계약에서 호출하면 됩니다. 또는 어떤 이유로 자체SPGNFT를 만들고 싶다면ISPGNFT계약 인터페이스를 구현할 수 있습니다. 아래 예시를 따라 새로운 SPGNFT를 초기화하는 데 사용할 수 있는 예시 매개변수를 확인하세요.

자체 SPGNFT를 가지고 나면 해야 할 일은 단순히mintAndRegisterIp with:

  • spgNftContract- SPGNFT 계약의 주소
  • recipient- NFT를 받고 따라서 새로 등록된 IP의 소유자가 될 주소.Note: remember that registering IP on Story is permissionless, so you can register an IP for someone else (by paying for the transaction) yet they can still be the owner of that IP Asset.
  • ipMetadata- NFT와 IP에 연관된 메타데이터.this섹션을 참조하여 NFT 및 IP 메타데이터 설정에 대해 더 잘 이해할 수 있습니다.
  1. 를 실행하여touch test/0_IPARegistrar.t.sol에 테스트 파일을 생성하세요test/0_IPARegistrar.t.sol. 그런 다음 다음 코드를 붙여넣으세요:

계약 주소

Story 계약의 주소를 여러분을 위해 미리 입력해 두었습니다. 하지만 여기에서도 해당 주소를 찾을 수 있습니다:배포된 스마트 계약

test/0_IPARegistrar.t.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.26;

import { Test } from "forge-std/Test.sol";
import { IIPAssetRegistry } from "@storyprotocol/core/interfaces/registries/IIPAssetRegistry.sol";
import { ISPGNFT } from "@storyprotocol/periphery/interfaces/ISPGNFT.sol";
import { IRegistrationWorkflows } from "@storyprotocol/periphery/interfaces/workflows/IRegistrationWorkflows.sol";
import { WorkflowStructs } from "@storyprotocol/periphery/lib/WorkflowStructs.sol";

// Run this test:
// forge test --fork-url https://aeneid.storyrpc.io/ --match-path test/0_IPARegistrar.t.sol
contract IPARegistrarTest is Test {
    address internal alice = address(0xa11ce);

    // For addresses, see https://docs.story.foundation/developers/deployed-smart-contracts
    // Protocol Core - IPAssetRegistry
    IIPAssetRegistry internal IP_ASSET_REGISTRY = IIPAssetRegistry(0x77319B4031e6eF1250907aa00018B8B1c67a244b);
    // Protocol Periphery - RegistrationWorkflows
    IRegistrationWorkflows internal REGISTRATION_WORKFLOWS =
        IRegistrationWorkflows(0xbe39E1C756e921BD25DF86e7AAa31106d1eb0424);

    ISPGNFT public SPG_NFT;

    function setUp() public {
        // Create a new NFT collection via SPG
        SPG_NFT = ISPGNFT(
            REGISTRATION_WORKFLOWS.createCollection(
                ISPGNFT.InitParams({
                    name: "Test Collection",
                    symbol: "TEST",
                    baseURI: "",
                    contractURI: "",
                    maxSupply: 100,
                    mintFee: 0,
                    mintFeeToken: address(0),
                    mintFeeRecipient: address(this),
                    owner: address(this),
                    mintOpen: true,
                    isPublicMinting: false
                })
            )
        );
    }

    /// @notice Mint an NFT and register it in the same call via the Story Protocol Gateway.
    /// @dev Requires the collection address that is passed into the `mintAndRegisterIp` function
    /// to be created via SPG (createCollection), as done above. Or, a contract that
    /// implements the `ISPGNFT` interface.
    function test_mintAndRegisterIp() public {
        uint256 expectedTokenId = SPG_NFT.totalSupply() + 1;
        address expectedIpId = IP_ASSET_REGISTRY.ipId(block.chainid, address(SPG_NFT), expectedTokenId);

        // Note: The caller of this function must be the owner of the SPG NFT Collection.
        // In this case, the owner of the SPG NFT Collection is the contract itself
        // because it deployed it in the `setup` function.
        // We can make `alice` the recipient of the NFT though, which makes her the
        // owner of not only the NFT, but therefore the IP Asset.
        (address ipId, uint256 tokenId) = REGISTRATION_WORKFLOWS.mintAndRegisterIp(
            address(SPG_NFT),
            alice,
            WorkflowStructs.IPMetadata({
                ipMetadataURI: "https://ipfs.io/ipfs/QmZHfQdFA2cb3ASdmeGS5K6rZjz65osUddYMURDx21bT73",
                ipMetadataHash: keccak256(
                    abi.encodePacked(
                        "{'title':'My IP Asset','description':'This is a test IP asset','createdAt':'','creators':[]}"
                    )
                ),
                nftMetadataURI: "https://ipfs.io/ipfs/QmRL5PcK66J1mbtTZSw1nwVqrGxt98onStx6LgeHTDbEey",
                nftMetadataHash: keccak256(
                    abi.encodePacked(
                        "{'name':'Test NFT','description':'This is a test NFT','image':'https://picsum.photos/200'}"
                    )
                )
            }),
            true
        );

        assertEq(ipId, expectedIpId);
        assertEq(tokenId, expectedTokenId);
        assertEq(SPG_NFT.ownerOf(tokenId), alice);
    }
}

테스트 실행 및 결과 확인

  1. 를 실행하세요forge build. 모든 것이 성공적이라면 명령이 성공적으로 컴파일될 것입니다.

  2. 이제 다음 명령을 실행하여 테스트를 실행하세요:

forge test --fork-url https://aeneid.storyrpc.io/ --match-path test/0_IPARegistrar.t.sol

IP에 라이선스 조건 추가

축하합니다, IP를 등록하셨습니다!

완성된 코드

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

이제 IP가 등록되었으니라이선스 조건을 생성하고 첨부할 수 있습니다. 이를 통해 다른 사람들이 라이선스를 발행하고 조건에 따라 제한된 방식으로 여러분의 IP를 사용할 수 있게 됩니다.

다음 페이지에서 이에 대해 살펴보겠습니다.