How to Tip an IP

Learn how to tip an IP Asset using the SDK and Smart Contracts.

Using the SDK

👍

See the Completed Code

To see a completed, working example of setting up a simple derivative chain and then tipping the child IP Asset, please see the commercial tutorial.

In this tutorial, you will learn how to send money ("tip") an IP Asset using the TypeScript SDK.

The Explanation

In this scenario, let's say there is a parent IP Asset that represents Mickey Mouse. Someone else draws a hat on that Mickey Mouse and registers it as a derivative (or "child") IP Asset. The License Terms specify that the child must share 50% of all commercial revenue (commercialRevShare = 50) with the parent. Someone else (a 3rd party user) comes along and wants to send the derivative 2 SUSD for being really cool.

For the purposes of this example, we will assume the child is already registered as a derivative IP Asset. If you want help learning this, check out Register a Derivative.

  • Parent IP ID: 0x42595dA29B541770D9F9f298a014bF912655E183
  • Child IP ID: 0xeaa4Eed346373805B377F5a4fe1daeFeFB3D182a

0. Before you Start

There are a few steps you have to complete before you can start the tutorial.

  1. Add your Story Network Testnet wallet's private key to .env file:
WALLET_PRIVATE_KEY=<YOUR_WALLET_PRIVATE_KEY>
  1. Add your preferred RPC URL to your .env file. You can just use the public default one we provide:
RPC_PROVIDER_URL=https://odyssey.storyrpc.io
  1. Install the dependencies:
npm install @story-protocol/core-sdk viem

1. Set up your Story Config

import { StoryClient, StoryConfig } from '@story-protocol/core-sdk'
import { http } from 'viem'
import { privateKeyToAccount, Address, Account } from 'viem/accounts'

const privateKey: Address = `0x${process.env.WALLET_PRIVATE_KEY}`
const account: Account = privateKeyToAccount(privateKey)

const config: StoryConfig = {  
  account: account,  
  transport: http(process.env.RPC_PROVIDER_URL),  
  chainId: 'odyssey',  
}  
const client = StoryClient.newClient(config)

2. Tipping the Derivative IP Asset

Now we will use the payRoyaltyOnBehalf function to pay the derivative asset. In this case:

  1. receiverIpId is the ipId of the derivative asset
  2. payerIpId is zeroAddress because the payer is a 3rd party (someone that thinks Mickey Mouse with a hat on him is cool), and not necessarily another IP Asset
  3. token is the address of SUSD, which is currently the only whitelisted revenue token
  4. amount is 2, since the person tipping wants to send 2 SUSD
import { PayRoyaltyOnBehalfResponse } from '@story-protocol/core-sdk'

const response: PayRoyaltyOnBehalfResponse = await client.royalty.payRoyaltyOnBehalf({
  receiverIpId: '0xeaa4Eed346373805B377F5a4fe1daeFeFB3D182a',
  payerIpId: zeroAddress,
  token: '0x91f6F05B08c16769d3c85867548615d270C42fC7',
  amount: 2,
  txOptions: { waitForTransaction: true },
})
console.log(`Paid royalty at transaction hash ${response.txHash}`)

3. Parent Claiming Due Revenue

At this point we have already finished the tutorial: we learned how to tip an IP Asset. But what if the parent wants to claim their due revenue? In this example, the parent should be able to claim 1 SUSD since the child earned 2 SUSD and the commercialRevShare = 50 in the license terms.

We will use the transferToVaultAndSnapshotAndClaimByTokenBatch to claim the due revenue tokens.

  1. ancestorIpId is the ipId of the parent ("ancestor") asset
  2. claimer is the address that holds the royalty tokens associated with the parent's IP Royalty Vault. By default, they are in the IP Account, which is just the ipId of the parent asset
  3. childIpId is obviously the ipId of the child asset
  4. royaltyPolicy is the address of the royalty policy. As explained in 💸 Royalty Module, this is either RoyaltyPolicyLAP or RoyaltyPolicyLRP, depending on the license terms. In this case, let's assume the license terms specify a RoyaltyPolicyLAP. Simply go to Deployed Smart Contracts and find the correct address.
  5. currencyToken is the address of SUSD, which is currently the only whitelisted revenue token
  6. amount is 1, since the parent should have 1 SUSD available to claim
import { TransferToVaultAndSnapshotAndClaimByTokenBatchResponse } from '@story-protocol/core-sdk'

const response: TransferToVaultAndSnapshotAndClaimByTokenBatchResponse = await client.royalty.transferToVaultAndSnapshotAndClaimByTokenBatch({
  ancestorIpId: '0x42595dA29B541770D9F9f298a014bF912655E183',
  claimer: '0x42595dA29B541770D9F9f298a014bF912655E183',
  royaltyClaimDetails: [{ 
    childIpId: '0xeaa4Eed346373805B377F5a4fe1daeFeFB3D182a', 
    royaltyPolicy: '0x793Df8d32c12B0bE9985FFF6afB8893d347B6686', 
    currencyToken: '0x91f6F05B08c16769d3c85867548615d270C42fC7', 
    amount: 1 
  }],
  txOptions: { waitForTransaction: true },
})
console.log(`Claimed revenue: ${response.amountsClaimed} at snapshotId ${response.snapshotId}`)

4. Done!

👍

See the Completed Code

To see a completed, working example of setting up a simple derivative chain and then tipping the child IP Asset, please see the commercial tutorial.

Using a Smart Contract

🚧

Not Completed

A full written tutorial is coming soon. For now, you can see a code example at the bottom of this file in our boilerplate.