๋ฉ”์ธ ์ฝ˜ํ…์ธ ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ
Hooks๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐœ๋ฐœ์ž๋Š” License Tokens ๋ฐœํ–‰ ๋˜๋Š” ํŒŒ์ƒ๋ฌผ ๋“ฑ๋ก ์‹œ ์‚ฌ์šฉ์ž ์ •์˜ ๊ตฌํ˜„, ์ œํ•œ ๋ฐ ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Hooks์—๋Š” ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์ด ์žˆ์Šต๋‹ˆ๋‹ค:
  1. Licensing Hooks: ๋ผ์ด์„ ์Šค ํ† ํฐ์„ ๋ฐœํ–‰ํ•˜๊ธฐ ์ „์— ์‚ฌ์šฉ์ž ์ •์˜ ๋กœ์ง์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค(๋ฐ ํŒŒ์ƒ๋ฌผ ๋“ฑ๋ก). ์˜ˆ๋ฅผ ๋“ค์–ด, ๋™์  ๊ฐ€๊ฒฉ ์š”์ฒญ, ๋ฐœํ–‰ ๊ฐ€๋Šฅํ•œ ๋ผ์ด์„ ์Šค ํ† ํฐ ์ˆ˜ ์ œํ•œ, ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. Licensing Hooks๋Š” ์–ธ์ œ๋“ ์ง€ licensing config์—์„œ ์ถ”๊ฐ€/์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. Commercializer Checker Hooks: Licensing Hooks์™€ ์œ ์‚ฌํ•˜์ง€๋งŒ, ์ง์ ‘์ ์œผ๋กœ ๋ผ์ด์„ ์Šค ์กฐ๊ฑด์˜ ์ผ๋ถ€์ด๋ฉฐ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ ๋ฐœํ–‰ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜๋„ ์—†์Šต๋‹ˆ๋‹ค.

Licensing Hooks

์ด๋“ค์€ IModule์„ ํ™•์žฅํ•˜๋Š” ILicensingHook ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์ปจํŠธ๋ž™ํŠธ์ž…๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์ ์€, Licensing Hook๊ฐ€ License Token์ด ๋ฐœํ–‰๋˜๊ธฐ ์ „์— ํ˜ธ์ถœ๋˜์–ด ์‚ฌ์šฉ์ž ์ •์˜ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๊ณ  ํ•ด๋‹น License Token์˜ ์ตœ์ข… totalMintingFee๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” beforeMintLicenseTokens ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค.
ILicensingHook ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ๋Š” ์—ฌ๊ธฐ์—์„œ ํ™•์ธํ•˜์„ธ์š”.
ILicensingHook.sol
/// @notice This function is called when the LicensingModule mints license tokens.
/// @dev The hook can be used to implement various checks and determine the minting price.
/// The hook should revert if the minting is not allowed.
/// @param caller The address of the caller who calling the mintLicenseTokens() function.
/// @param licensorIpId The ID of licensor IP from which issue the license tokens.
/// @param licenseTemplate The address of the license template.
/// @param licenseTermsId The ID of the license terms within the license template,
/// which is used to mint license tokens.
/// @param amount The amount of license tokens to mint.
/// @param receiver The address of the receiver who receive the license tokens.
/// @param hookData The data to be used by the licensing hook.
/// @return totalMintingFee The total minting fee to be paid when minting amount of license tokens.
function beforeMintLicenseTokens(
  address caller,
  address licensorIpId,
  address licenseTemplate,
  uint256 licenseTermsId,
  uint256 amount,
  address receiver,
  bytes calldata hookData
) external returns (uint256 totalMintingFee);
์ด ํ•จ์ˆ˜๊ฐ€ totalMintingFee๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•˜์„ธ์š”. โ€œLicense Terms์—์„œ ๋ฐœํ–‰ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ๊ณ , LicenseConfig์—์„œ๋„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๊ณ , beforeMintLicenseTokens์—์„œ ๋™์  ๊ฐ€๊ฒฉ์„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ตœ์ข… ๋ฐœํ–‰ ์ˆ˜์ˆ˜๋ฃŒ๋Š” ์‹ค์ œ๋กœ ๋ฌด์—‡์ด ๋ ๊นŒ?โ€๋ผ๊ณ  ๊ถ๊ธˆํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ์„ ์ˆœ์œ„๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:
๋ฐœํ–‰ ์ˆ˜์ˆ˜๋ฃŒ์ค‘์š”๋„
beforeMintLicenseTokens์—์„œ ๋ฐ˜ํ™˜๋œ totalMintingFee์ตœ๊ณ  ์šฐ์„ ์ˆœ์œ„
LicenseConfig์— ์„ค์ •๋œ mintingFeeโฌ‡๏ธ
License Terms์— ์„ค์ •๋œ mintingFee์ตœ์ € ์šฐ์„ ์ˆœ์œ„
์™ธ๋ถ€ license hook์˜ ์ž ์žฌ์ ์œผ๋กœ ์•…์˜์ ์ธ ๊ตฌํ˜„์— ์ฃผ์˜ํ•˜์„ธ์š”. ์„ ํƒํ•œ hook์˜ ์ฝ”๋“œ๋Š” DATA Foundation ํŒ€์— ์˜ํ•ด ๊ฒ€ํ†  ๋˜๋Š” ๊ฐ์‚ฌ๋˜์ง€ ์•Š์•˜์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋จผ์ € ์ง์ ‘ ํ™•์ธํ•˜์„ธ์š”.

์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ Hooks

๋‹ค์Œ์€ ์šฐ๋ฆฌ ํ”„๋กœํ† ์ฝœ์— ๋ฐฐํฌ๋˜์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” hooks์ž…๋‹ˆ๋‹ค.
์ด hooks์˜ ๋ฐฐํฌ๋œ ์ฃผ์†Œ๋Š” ์—ฌ๊ธฐ์—์„œ ํ™•์ธํ•˜์„ธ์š”.
Hook์„ค๋ช…์ปจํŠธ๋ž™ํŠธ ์ฝ”๋“œ
LockLicenseHook๋ผ์ด์„ ์Šค ํ† ํฐ ๋ฐœํ–‰ ๋˜๋Š” ์ƒˆ๋กœ์šด ํŒŒ์ƒ๋ฌผ ๋“ฑ๋ก์„ ์ค‘๋‹จํ•ฉ๋‹ˆ๋‹ค.์—ฌ๊ธฐ ๋ณด๊ธฐ โ†—๏ธ
TotalLicenseTokenLimitHook๋ฐœํ–‰ ๊ฐ€๋Šฅํ•œ ๋ผ์ด์„ ์Šค ํ† ํฐ์˜ ์ˆ˜์— ์ œํ•œ์„ ์„ค์ •ํ•˜๋ฉฐ, ์–ธ์ œ๋“ ์ง€ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.์—ฌ๊ธฐ ๋ณด๊ธฐ โ†—๏ธ

Hooks ๊ตฌํ˜„ํ•˜๊ธฐ

SDK ์ฝ”๋“œ ์˜ˆ์ œ

licensing hook๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋Š” ์‹ค์ œ ์ž‘๋™ํ•˜๋Š” TypeScript SDK ์ฝ”๋“œ ์˜ˆ์ œ. ๋” ๊ตฌ์ฒด์ ์œผ๋กœ, ๋ฐœํ–‰ ๊ฐ€๋Šฅํ•œ ๋ผ์ด์„ ์Šค ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ๋ฐฉ๋ฒ•.

Solidity ์ฝ”๋“œ ์˜ˆ์ œ

licensing hook๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋Š” ์‹ค์ œ ์ž‘๋™ํ•˜๋Š” Solidity ์ฝ”๋“œ ์˜ˆ์ œ. ๋” ๊ตฌ์ฒด์ ์œผ๋กœ, ๋ฐœํ–‰ ๊ฐ€๋Šฅํ•œ ๋ผ์ด์„ ์Šค ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ๋ฐฉ๋ฒ•.
Licensing Hooks๋Š” ๊ถ๊ทน์ ์œผ๋กœ ILicensingHook ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์Šค๋งˆํŠธ ์ปจํŠธ๋ž™ํŠธ์ž…๋‹ˆ๋‹ค. ์ธํ„ฐํŽ˜์ด์Šค๋Š” ์—ฌ๊ธฐ์—์„œ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฏธ ๋ฐฐํฌ๋œ ๋ช‡ ๊ฐ€์ง€ Licensing Hooks๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค(์œ„ ์ฐจํŠธ ์ฐธ์กฐ). ์‹ค์ œ๋กœ Licensing Hook๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Licensing Config์— ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. Licensing Config๋Š” IP Asset์— ์กฐ๊ฑด์„ ์ฒจ๋ถ€ํ•  ๋•Œ License Terms์— ์„ค์ •ํ•˜๋Š” ์ผ๋ จ์˜ ๊ตฌ์„ฑ์ž…๋‹ˆ๋‹ค.
1

Licensing Config ์ƒ์„ฑ

๋จผ์ € Licensing Config๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค:
import { LicensingConfig } from '@story-protocol/core-sdk';

const licensingConfig: LicensingConfig = {
    isSet: true,
    mintingFee: 0n,
    // address of TotalLicenseTokenLimitHook
    // from https://docs.datafdn.org/developers/deployed-smart-contracts
    licensingHook: '0xaBAD364Bfa41230272b08f171E0Ca939bD600478',
    hookData: zeroAddress,
    commercialRevShare: 0,
    disabled: false,
    expectMinimumGroupRewardShare: 0,
    expectGroupRewardPool: zeroAddress,
}
2

Licensing Config ์„ค์ •

๋‹ค์Œ์œผ๋กœ, License Terms์— Licensing Config๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ์˜ˆ์‹œ์—์„œ๋Š” IP Asset์„ ๋“ฑ๋กํ•  ๋•Œ ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค:
์ด ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์€ ์•ฝ๊ฐ„์˜ ์„ค์ •์ด ํ•„์š”ํ•˜๋ฉฐ, ์ด๋ฏธ TypeScript SDK๋ฅผ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜๊ณ  ์žˆ๋Š” ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์‹ค์ œ ์ž‘๋™ํ•˜๋Š” ์ฝ”๋“œ ์˜ˆ์ œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.
์ด๋Š” ์—ฌ๊ธฐ์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๋Š” registerIpAsset ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
const response = await client.ipAsset.registerIpAsset({
    nft: {
        type: 'mint',
        spgNftContract: '0xc32A8a0FF3beDDDa58393d022aF433e78739FAbc', // public spg contract for ease-of-use
    },
    licenseTermsData: [
        {
            terms: { defaultMintingFee: 0, commercialUse: true, ... }, // dummy license terms
            // set the licensing config here
            licensingConfig: licensingConfig
        },
    ],
    ipMetadata: {
        ipMetadataURI: 'test-uri',
        ipMetadataHash: toHex('test-metadata-hash', { size: 32 }),
        nftMetadataHash: toHex('test-nft-metadata-hash', { size: 32 }),
        nftMetadataURI: 'test-nft-uri',
    }
})

console.log(`Token ID: ${response.tokenId}, IPA ID: ${response.ipId}, License Terms ID: ${response.licenseTermsIds}`);
3

์ œํ•œ์„ 1๋กœ ์„ค์ •

์ด์ œ ์กฐ๊ฑด์— Licensing Config๋ฅผ ์„ค์ •ํ–ˆ์œผ๋ฏ€๋กœ, hook์˜ setTotalLicenseTokenLimit ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐœํ–‰ ๊ฐ€๋Šฅํ•œ ์ตœ๋Œ€ ๋ผ์ด์„ ์Šค ์ˆ˜๋ฅผ 1๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
const hookResponse = await client.license.setMaxLicenseTokens({
  ipId: response.ipId,
  licenseTermsId: response.licenseTermsIds![0],
  maxLicenseTokens: 1000,
});

console.log(`Max license tokens set at transaction hash ${hookResponse.txHash}`);

์ƒˆ๋กœ์šด Licensing Hook ์ƒ์„ฑ

์ƒˆ๋กœ์šด licensing hook๋ฅผ ๋งŒ๋“ค๊ณ  DATA Foundation ํ”„๋กœํ† ์ฝœ์— ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ๋กœ ๋“ฑ๋กํ•˜๋ ค๋ฉด ์•„๋ž˜ ์ ˆ์ฐจ๋ฅผ ๋”ฐ๋ฅด์„ธ์š”.
  1. Hook ๊ฐœ๋ฐœ: ์ด ํ…œํ”Œ๋ฆฟ ์ €์žฅ์†Œ๋ฅผ ํฌํฌํ•˜์—ฌ ๊ฐœ๋ฐœ์„ ๋ถ€ํŠธ์ŠคํŠธ๋žฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ Aeneid ํ”„๋กœํ† ์ฝœ์— ๋Œ€ํ•œ ํ…Œ์ŠคํŠธ์™€ ํ•จ๊ป˜ ์˜ˆ์‹œ hook๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์ง€๋งŒ, ์‚ฌ์šฉ์€ ์„ ํƒ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค.
    LicenseCallerWhitelistHook.sol hook๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ ์˜ˆ์‹œ๋กœ license-caller-whitelist-hook์„ ์ฐธ์กฐํ•˜์„ธ์š”.
  2. Registered Modules ์ €์žฅ์†Œ ํฌํฌ: registered-modules ์ €์žฅ์†Œ๋ฅผ ์ž์‹ ์˜ GitHub ๊ณ„์ •์œผ๋กœ ํฌํฌํ•˜์„ธ์š”.
  3. Module ๋ชฉ๋ก ์—…๋ฐ์ดํŠธ: registered-modules ์ €์žฅ์†Œ์—์„œ hook-modules.json ํŒŒ์ผ์— hook์˜ ์„ธ๋ถ€ ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”. aeneid ๋ฐ mainnet ๋ชจ๋‘์— hook๋ฅผ ๋ฐฐํฌ ๋ฐ ๋ธ”๋ก ์ต์Šคํ”Œ๋กœ๋Ÿฌ์—์„œ ๊ฒ€์ฆํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ JSON ๊ตฌ์กฐ๋ฅผ ์ค€์ˆ˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”:
    {
      "name": "YourModuleName",
      "aeneid": {
        "address": "YourModuleAddress",
        "blockExplorerLink": "YourModuleBlockExplorerLink"
      },
      "mainnet": {
        "address": "YourModuleAddress",
        "blockExplorerLink": "YourModuleBlockExplorerLink"
      }
    }
    
    YourModuleName, YourModuleAddress, YourModuleBlockExplorerLink๋ฅผ ๊ฐ๊ฐ hook์˜ ์ด๋ฆ„, ์ฃผ์†Œ, ๋ธ”๋ก ์ต์Šคํ”Œ๋กœ๋Ÿฌ ํŽ˜์ด์ง€ ๋งํฌ๋กœ ๋ฐ”๊พธ์„ธ์š”. ์˜ˆ์‹œ:
    {
      "name": "LicenseCallerWhitelistHook",
      "aeneid": {
        "address": "0x37be56d9fb06d885cda3cb010096c94c28b4d658",
        "blockExplorerLink": "https://aeneid.datanetscan.io/address/0x37be56d9fb06d885cda3cb010096c94c28b4d658?tab=contract"
      },
      "mainnet": {
        "address": "0x6d9d51a444c8318e8840e75dab7ed81b5a714610",
        "blockExplorerLink": "https://www.datanetscan.io/address/0x6d9d51a444c8318e8840e75dab7ed81b5a714610?tab=contract"
      }
    }
    
  4. Pull Request (PR) ์ƒ์„ฑ: hook๋ฅผ ์ถ”๊ฐ€ํ•œ ํ›„, ์ด ์ €์žฅ์†Œ์— ๋Œ€ํ•ด pull request๋ฅผ ์ƒ์„ฑํ•˜์„ธ์š”. PR ์„ค๋ช…์— ๋‹ค์Œ ์ •๋ณด๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”(๊ฐ’์€ ๋ณธ์ธ์˜ ๊ฒƒ์œผ๋กœ ๋ฐ”๊พธ์„ธ์š”):
    ## Register my module
    
    - Module type: `hook`
    - Module name: `LicenseCallerWhitelistHook`
    - Aeneid Module address: `0x37be56d9fb06d885cda3cb010096c94c28b4d658`
    - Mainnet Module address: `0x6d9d51a444c8318e8840e75dab7ed81b5a714610`
    - My module is immutable: yes
    - My module is using an upgradeable proxy: no
    - My module has been verified on the block explorer (required): yes
    - Summary of my module: Hook for allowing a licensor to gate which addresses can mint a license. The licensor can add/remove an address at any time.
    - GitHub repository with source code and tests: https://github.com/jacob-tucker/license-caller-whitelist-hook
    
  5. ๊ฒ€์ฆ ๋Œ€๊ธฐ: PR์ด ์ œ์ถœ๋˜๋ฉด ๊ฒ€ํ† ๋ฉ๋‹ˆ๋‹ค. ๋ณด์•ˆ ๊ฐ์‚ฌ๊ฐ€ ์ˆ˜ํ–‰ ๋ฐ ์™„๋ฃŒ๋˜๊ณ  ๋ชจ๋“ˆ์ด ํ”„๋กœํ† ์ฝœ์— ํ™”์ดํŠธ๋ฆฌ์ŠคํŠธ๋กœ ๋“ฑ๋ก๋˜๋ฉด, PR์ด ๋ณ‘ํ•ฉ๋ฉ๋‹ˆ๋‹ค. ์ด ์‹œ์ ์—์„œ ๋ชจ๋“ˆ์€ ๊ณต์‹์ ์œผ๋กœ ๋“ฑ๋ก๋˜๊ณ  DATA Foundation ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ์— ์•ˆ์ „ํ•œ ๊ฒƒ์œผ๋กœ ์ธ์ •๋ฉ๋‹ˆ๋‹ค.
์—ฌ๋Ÿฌ๋ถ„์˜ ๊ธฐ์—ฌ๋ฅผ ๊ธฐ๋Œ€ํ•˜๋ฉฐ DATA Foundation ๋ชจ๋“ˆ ์ƒํƒœ๊ณ„๋ฅผ ํ™•์žฅํ•ด ๋‚˜๊ฐ€๊ธธ ๋ฐ”๋ž๋‹ˆ๋‹ค!

Commercializer Checker Hooks

๋ฌธ์„œ๊ฐ€ ๊ณง ์ œ๊ณต๋  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ๊ทธ๋™์•ˆ ์งˆ๋ฌธ์ด ์žˆ์œผ์‹œ๋ฉด Builderโ€™s Discord์—์„œ ๋ฌธ์˜ํ•ด ์ฃผ์„ธ์š”.