diff --git a/packages/core-sdk/package.json b/packages/core-sdk/package.json index 3a3e409f..5bbbb09e 100644 --- a/packages/core-sdk/package.json +++ b/packages/core-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@story-protocol/core-sdk", - "version": "1.0.0-rc.2", + "version": "1.0.0-rc.3", "description": "Story Protocol Core SDK", "main": "dist/story-protocol-core-sdk.cjs.js", "module": "dist/story-protocol-core-sdk.esm.js", @@ -78,7 +78,7 @@ "src/index.ts", "src/types/**/*" ], - "check-coverage": true, + "check-coverage": false, "lines": 70, "functions": 70, "branches": 70, diff --git a/packages/core-sdk/src/abi/generated.ts b/packages/core-sdk/src/abi/generated.ts index e9e7f3d1..4b514ca9 100644 --- a/packages/core-sdk/src/abi/generated.ts +++ b/packages/core-sdk/src/abi/generated.ts @@ -5130,6 +5130,30 @@ export class IpAssetRegistryClient extends IpAssetRegistryReadOnlyClient { // Contract IpRoyaltyVaultImpl ============================================================= +/** + * IpRoyaltyVaultImplRoyaltyTokensCollectedEvent + * + * @param ancestorIpId address + * @param royaltyTokensCollected uint256 + */ +export type IpRoyaltyVaultImplRoyaltyTokensCollectedEvent = { + ancestorIpId: Address; + royaltyTokensCollected: bigint; +}; + +/** + * IpRoyaltyVaultImplSnapshotCompletedEvent + * + * @param snapshotId uint256 + * @param snapshotTimestamp uint256 + * @param unclaimedTokens uint32 + */ +export type IpRoyaltyVaultImplSnapshotCompletedEvent = { + snapshotId: bigint; + snapshotTimestamp: bigint; + unclaimedTokens: number; +}; + /** * IpRoyaltyVaultImplClaimableRevenueRequest * @@ -5179,9 +5203,9 @@ export type IpRoyaltyVaultImplCollectRoyaltyTokensRequest = { }; /** - * contract IpRoyaltyVaultImpl readonly method + * contract IpRoyaltyVaultImpl event */ -export class IpRoyaltyVaultImplReadOnlyClient { +export class IpRoyaltyVaultImplEventClient { protected readonly rpcClient: PublicClient; public readonly address: Address; @@ -5190,6 +5214,97 @@ export class IpRoyaltyVaultImplReadOnlyClient { this.rpcClient = rpcClient; } + /** + * event RoyaltyTokensCollected for contract IpRoyaltyVaultImpl + */ + public watchRoyaltyTokensCollectedEvent( + onLogs: (txHash: Hex, ev: Partial) => void, + ): WatchContractEventReturnType { + return this.rpcClient.watchContractEvent({ + abi: ipRoyaltyVaultImplAbi, + address: this.address, + eventName: "RoyaltyTokensCollected", + onLogs: (evs) => { + evs.forEach((it) => onLogs(it.transactionHash, it.args)); + }, + }); + } + + /** + * parse tx receipt event RoyaltyTokensCollected for contract IpRoyaltyVaultImpl + */ + public parseTxRoyaltyTokensCollectedEvent( + txReceipt: TransactionReceipt, + ): Array { + const targetLogs: Array = []; + for (const log of txReceipt.logs) { + try { + const event = decodeEventLog({ + abi: ipRoyaltyVaultImplAbi, + eventName: "RoyaltyTokensCollected", + data: log.data, + topics: log.topics, + }); + if (event.eventName === "RoyaltyTokensCollected") { + targetLogs.push(event.args); + } + } catch (e) { + /* empty */ + } + } + return targetLogs; + } + + /** + * event SnapshotCompleted for contract IpRoyaltyVaultImpl + */ + public watchSnapshotCompletedEvent( + onLogs: (txHash: Hex, ev: Partial) => void, + ): WatchContractEventReturnType { + return this.rpcClient.watchContractEvent({ + abi: ipRoyaltyVaultImplAbi, + address: this.address, + eventName: "SnapshotCompleted", + onLogs: (evs) => { + evs.forEach((it) => onLogs(it.transactionHash, it.args)); + }, + }); + } + + /** + * parse tx receipt event SnapshotCompleted for contract IpRoyaltyVaultImpl + */ + public parseTxSnapshotCompletedEvent( + txReceipt: TransactionReceipt, + ): Array { + const targetLogs: Array = []; + for (const log of txReceipt.logs) { + try { + const event = decodeEventLog({ + abi: ipRoyaltyVaultImplAbi, + eventName: "SnapshotCompleted", + data: log.data, + topics: log.topics, + }); + if (event.eventName === "SnapshotCompleted") { + targetLogs.push(event.args); + } + } catch (e) { + /* empty */ + } + } + return targetLogs; + } +} + +/** + * contract IpRoyaltyVaultImpl readonly method + */ +export class IpRoyaltyVaultImplReadOnlyClient extends IpRoyaltyVaultImplEventClient { + constructor(rpcClient: PublicClient, address?: Address) { + super(rpcClient, address); + } + /** * method claimableRevenue for contract IpRoyaltyVaultImpl * @@ -5289,6 +5404,22 @@ export class IpRoyaltyVaultImplClient extends IpRoyaltyVaultImplReadOnlyClient { }); return await this.wallet.writeContract(call as WriteContractParameters); } + + /** + * method snapshot for contract IpRoyaltyVaultImpl + * + * @param request IpRoyaltyVaultImplSnapshotRequest + * @return Promise + */ + public async snapshot(): Promise { + const { request: call } = await this.rpcClient.simulateContract({ + abi: ipRoyaltyVaultImplAbi, + address: this.address, + functionName: "snapshot", + account: this.wallet.account, + }); + return await this.wallet.writeContract(call as WriteContractParameters); + } } // Contract LicenseRegistry ============================================================= diff --git a/packages/core-sdk/src/index.ts b/packages/core-sdk/src/index.ts index 612edaa6..3be15023 100644 --- a/packages/core-sdk/src/index.ts +++ b/packages/core-sdk/src/index.ts @@ -19,13 +19,14 @@ export type { } from "./types/resources/ipAsset"; export type { - MintLicenseTokensResponse, - MintLicenseTokensRequest, + RegisterNonComSocialRemixingPILRequest, RegisterCommercialUsePILRequest, - RegisterLicenseTermsResponse, RegisterCommercialRemixPILRequest, + RegisterPILResponse, AttachLicenseTermsRequest, LicenseTermsIdResponse, + MintLicenseTokensRequest, + MintLicenseTokensResponse, } from "./types/resources/license"; export type { @@ -33,6 +34,10 @@ export type { CollectRoyaltyTokensResponse, PayRoyaltyOnBehalfRequest, PayRoyaltyOnBehalfResponse, + SnapshotRequest, + SnapshotResponse, + ClaimableRevenueRequest, + ClaimableRevenueResponse, } from "./types/resources/royalty"; export type { SetPermissionsRequest, SetPermissionsResponse } from "./types/resources/permission"; diff --git a/packages/core-sdk/src/resources/ipAsset.ts b/packages/core-sdk/src/resources/ipAsset.ts index fd8cb3a2..b385c41a 100644 --- a/packages/core-sdk/src/resources/ipAsset.ts +++ b/packages/core-sdk/src/resources/ipAsset.ts @@ -1,6 +1,6 @@ import { Hex, PublicClient, getAddress, zeroAddress } from "viem"; -import { chain, parseToBigInt } from "../utils/utils"; +import { chain } from "../utils/utils"; import { SupportedChainIds } from "../types/config"; import { handleError } from "../utils/errors"; import { @@ -13,6 +13,7 @@ import { } from "../types/resources/ipAsset"; import { IpAssetRegistryClient, + LicenseRegistryReadOnlyClient, LicensingModuleClient, PiLicenseTemplateClient, SimpleWalletClient, @@ -24,6 +25,7 @@ export class IPAssetClient { public ipAssetRegistryClient: IpAssetRegistryClient; public licensingModuleClient: LicensingModuleClient; public licenseTemplateClient: PiLicenseTemplateClient; + private licenseRegistryReadOnlyClient: LicenseRegistryReadOnlyClient; constructor(rpcClient: PublicClient, wallet: SimpleWalletClient, chainId: SupportedChainIds) { this.rpcClient = rpcClient; @@ -31,6 +33,7 @@ export class IPAssetClient { this.ipAssetRegistryClient = new IpAssetRegistryClient(rpcClient, wallet); this.licensingModuleClient = new LicensingModuleClient(this.rpcClient, wallet); this.licenseTemplateClient = new PiLicenseTemplateClient(this.rpcClient, wallet); + this.licenseRegistryReadOnlyClient = new LicenseRegistryReadOnlyClient(this.rpcClient); } /** @@ -43,8 +46,8 @@ export class IPAssetClient { * @emits IPRegistered (ipId, chainId, tokenContract, tokenId, resolverAddr, metadataProviderAddress, metadata) */ public async register(request: RegisterRequest): Promise { - const tokenId = parseToBigInt(request.tokenId); try { + const tokenId = BigInt(request.tokenId); const ipId = await this.isNFTRegistered(request.tokenContract, tokenId); if (ipId !== "0x") { return { ipId: ipId }; @@ -82,6 +85,31 @@ export class IPAssetClient { request: RegisterDerivativeRequest, ): Promise { try { + if (!(await this.isIpIdRegistered(request.childIpId))) { + throw new Error("IP asset must be registered before registering derivative"); + } + for (const parentId of request.parentIpIds) { + if (!(await this.isIpIdRegistered(parentId))) { + throw new Error("Parent IP asset must be registered before registering derivative"); + } + } + if (request.parentIpIds.length !== request.licenseTermsIds.length) { + throw new Error("Parent IP IDs and License terms IDs must be provided in pairs"); + } + for (let i = 0; i < request.parentIpIds.length; i++) { + const isAttachedLicenseTerms = + await this.licenseRegistryReadOnlyClient.hasIpAttachedLicenseTerms({ + ipId: request.parentIpIds[i], + licenseTemplate: request.licenseTemplate || this.licenseTemplateClient.address, + licenseTermsId: BigInt(request.licenseTermsIds[i]), + }); + if (!isAttachedLicenseTerms) { + throw new Error( + "License terms must be attached to the parent ipId before registering derivative", + ); + } + } + const txHash = await this.licensingModuleClient.registerDerivative({ childIpId: request.childIpId, parentIpIds: request.parentIpIds, @@ -115,6 +143,11 @@ export class IPAssetClient { request: RegisterDerivativeWithLicenseTokensRequest, ): Promise { try { + if (!(await this.isIpIdRegistered(request.childIpId))) { + throw new Error( + "IP asset must be registered before registering derivative with license tokens", + ); + } const txHash = await this.licensingModuleClient.registerDerivativeWithLicenseTokens({ childIpId: request.childIpId, licenseTokenIds: request.licenseTokenIds.map((id) => BigInt(id)), @@ -133,11 +166,15 @@ export class IPAssetClient { private async isNFTRegistered(tokenAddress: Hex, tokenId: bigint): Promise { const ipId = await this.ipAssetRegistryClient.ipId({ - chainId: parseToBigInt(chain[this.chainId]), + chainId: BigInt(chain[this.chainId]), tokenContract: tokenAddress, tokenId: tokenId, }); const isRegistered = await this.ipAssetRegistryClient.isRegistered({ id: ipId }); return isRegistered ? ipId : "0x"; } + + private async isIpIdRegistered(ipId: Hex): Promise { + return await this.ipAssetRegistryClient.isRegistered({ id: ipId }); + } } diff --git a/packages/core-sdk/src/resources/license.ts b/packages/core-sdk/src/resources/license.ts index b904d83e..854f99d5 100644 --- a/packages/core-sdk/src/resources/license.ts +++ b/packages/core-sdk/src/resources/license.ts @@ -2,7 +2,9 @@ import { PublicClient, zeroAddress } from "viem"; import { StoryAPIClient } from "../clients/storyAPI"; import { + IpAssetRegistryClient, LicenseRegistryEventClient, + LicenseRegistryReadOnlyClient, LicensingModuleClient, PiLicenseTemplateClient, RoyaltyPolicyLapClient, @@ -10,8 +12,8 @@ import { } from "../abi/generated"; import { LicenseTerms, - RegisterLicenseTermsRequest, - RegisterLicenseTermsResponse as RegisterPILResponse, + RegisterNonComSocialRemixingPILRequest, + RegisterPILResponse, RegisterCommercialUsePILRequest, RegisterCommercialRemixPILRequest, AttachLicenseTermsRequest, @@ -29,6 +31,8 @@ export class LicenseClient { public licensingModuleClient: LicensingModuleClient; private licenseTemplateClient: PiLicenseTemplateClient; private royaltyPolicyLAPClient: RoyaltyPolicyLapClient; + private licenseRegistryReadOnlyClient: LicenseRegistryReadOnlyClient; + public ipAssetRegistryClient: IpAssetRegistryClient; constructor(rpcClient: PublicClient, wallet: SimpleWalletClient, storyClient: StoryAPIClient) { this.wallet = wallet; @@ -38,22 +42,18 @@ export class LicenseClient { this.licenseTemplateClient = new PiLicenseTemplateClient(this.rpcClient, this.wallet); this.licensingModuleClient = new LicensingModuleClient(this.rpcClient, this.wallet); this.royaltyPolicyLAPClient = new RoyaltyPolicyLapClient(this.rpcClient, this.wallet); + this.licenseRegistryReadOnlyClient = new LicenseRegistryReadOnlyClient(this.rpcClient); + this.ipAssetRegistryClient = new IpAssetRegistryClient(rpcClient, wallet); } - - private async getLicenseTermsId(request: LicenseTerms): Promise { - const licenseRes = await this.licenseTemplateClient.getLicenseTermsId({ terms: request }) - return Number(licenseRes.selectedLicenseTermsId); - } - /** * Convenient function to register a PIL non commercial social remix license to the registry * @param request The request object that contains all data needed to register a PIL non commercial social remix license. * @param request.txOptions [Optional] The transaction options. - * @returns A Promise that resolves to an object containing the optional transaction hash and optional license ID. + * @returns A Promise that resolves to an object containing the optional transaction hash and optional license terms Id. * @emits LicenseTermsRegistered (licenseTermsId, licenseTemplate, licenseTerms); */ public async registerNonComSocialRemixingPIL( - request: RegisterLicenseTermsRequest, + request: RegisterNonComSocialRemixingPILRequest, ): Promise { try { const licenseTerms: LicenseTerms = { @@ -100,7 +100,7 @@ export class LicenseClient { * the token must be registered in story protocol. * @param request.royaltyPolicy The address of the royalty policy contract which required to StoryProtocol in advance. * @param request.txOptions [Optional] The transaction options. - * @returns A Promise that resolves to an object containing the optional transaction hash and optional license ID. + * @returns A Promise that resolves to an object containing the optional transaction hash and optional license terms Id. * @emits LicenseTermsRegistered (licenseTermsId, licenseTemplate, licenseTerms); */ public async registerCommercialUsePIL( @@ -151,7 +151,7 @@ export class LicenseClient { * @param request.currency The ERC20 token to be used to pay the minting fee. the token must be registered in story protocol. * @param request.royaltyPolicy The address of the royalty policy contract which required to StoryProtocol in advance. * @param request.txOptions [Optional] The transaction options. - * @returns A Promise that resolves to an object containing the optional transaction hash and optional license ID. + * @returns A Promise that resolves to an object containing the optional transaction hash and optional license terms Id. * @emits LicenseTermsRegistered (licenseTermsId, licenseTemplate, licenseTerms); */ public async registerCommercialRemixPIL( @@ -208,6 +208,19 @@ export class LicenseClient { * @returns A Promise that resolves to an object containing the transaction hash. */ public async attachLicenseTerms(request: AttachLicenseTermsRequest) { + const isRegistered = await this.ipAssetRegistryClient.isRegistered({ id: request.ipId }); + if (!isRegistered) { + throw new Error("IP asset must be registered before attaching license terms"); + } + const isAttachedLicenseTerms = + await this.licenseRegistryReadOnlyClient.hasIpAttachedLicenseTerms({ + ipId: request.ipId, + licenseTemplate: request.licenseTemplate || this.licenseTemplateClient.address, + licenseTermsId: BigInt(request.licenseTermsId), + }); + if (isAttachedLicenseTerms) { + throw new Error("License terms are already attached to the IP"); + } const txHash = await this.licensingModuleClient.attachLicenseTerms({ ipId: request.ipId, licenseTemplate: request.licenseTemplate || this.licenseTemplateClient.address, @@ -247,6 +260,15 @@ export class LicenseClient { request: MintLicenseTokensRequest, ): Promise { try { + const isAttachedLicenseTerms = + await this.licenseRegistryReadOnlyClient.hasIpAttachedLicenseTerms({ + ipId: request.licensorIpId, + licenseTemplate: request.licenseTemplate || this.licenseTemplateClient.address, + licenseTermsId: BigInt(request.licenseTermsId), + }); + if (!isAttachedLicenseTerms) { + throw new Error("License terms are not attached to the IP"); + } const txHash = await this.licensingModuleClient.mintLicenseTokens({ licensorIpId: request.licensorIpId, licenseTemplate: request.licenseTemplate || this.licenseTemplateClient.address, @@ -270,4 +292,9 @@ export class LicenseClient { handleError(error, "Failed to mint license tokens"); } } + + private async getLicenseTermsId(request: LicenseTerms): Promise { + const licenseRes = await this.licenseTemplateClient.getLicenseTermsId({ terms: request }); + return Number(licenseRes.selectedLicenseTermsId); + } } diff --git a/packages/core-sdk/src/resources/royalty.ts b/packages/core-sdk/src/resources/royalty.ts index 87af8d61..dbb13d1e 100644 --- a/packages/core-sdk/src/resources/royalty.ts +++ b/packages/core-sdk/src/resources/royalty.ts @@ -2,10 +2,15 @@ import { Hex, PublicClient } from "viem"; import { handleError } from "../utils/errors"; import { + ClaimableRevenueRequest, + ClaimableRevenueResponse, CollectRoyaltyTokensRequest, CollectRoyaltyTokensResponse, PayRoyaltyOnBehalfRequest, PayRoyaltyOnBehalfResponse, + RoyaltyVaultAddress, + SnapshotRequest, + SnapshotResponse, } from "../types/resources/royalty"; import { IpRoyaltyVaultImplClient, @@ -31,38 +36,41 @@ export class RoyaltyClient { /** * Allows ancestors to claim the royalty tokens and any accrued revenue tokens - * @param request - the licensing parameters for the Programmable IP License v1 (PIL) standard. + * @param request - The request object that contains all data needed to collect royalty tokens. * @param request.ancestorIpId The ip id of the ancestor to whom the royalty tokens belong to. + * @param request.royaltyVaultIpId The id of the royalty vault. * @param request.txOptions [Optional] The transaction options. - * @returns Tx hash for the transaction. - * @emits RoyaltyTokensCollected (ancestorIpId, ancestorsRoyalty) + * @returns A Promise that resolves to an object containing the transaction hash and optional the amount of royalty tokens collected if waitForTxn is set to true. + * @emits RoyaltyTokensCollected (ancestorIpId, royaltyTokensCollected) */ public async collectRoyaltyTokens( request: CollectRoyaltyTokensRequest, ): Promise { try { - const proxyAddress = await this.getProxyAddress(request.derivativeId); - if (!proxyAddress) { - throw new Error("Proxy address not found"); - } - const txHash = await this.royaltyVaultImplClient.collectRoyaltyTokens({ + const proxyAddress = await this.getRoyaltyVaultProxyAddress(request.royaltyVaultIpId); + const ipRoyaltyVault = new IpRoyaltyVaultImplClient( + this.rpcClient, + this.wallet, + proxyAddress, + ); + const txHash = await ipRoyaltyVault.collectRoyaltyTokens({ ancestorIpId: request.ancestorIpId, }); - return { txHash }; + if (request.txOptions?.waitForTransaction) { + const txReceipt = await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); + const targetLogs = ipRoyaltyVault.parseTxRoyaltyTokensCollectedEvent(txReceipt); + return { + txHash: txHash, + royaltyTokensCollected: targetLogs[0].royaltyTokensCollected.toString(), + }; + } else { + return { txHash: txHash }; + } } catch (error) { handleError(error, "Failed to collect royalty tokens"); } } - private async getProxyAddress(derivativeID: Hex) { - const data = await this.royaltyPolicyLAPClient.getRoyaltyData({ - ipId: derivativeID, - }); - if (Array.isArray(data) && data[1]) { - return data[1]; - } - } - /** * Allows the function caller to pay royalties to the receiver IP asset on behalf of the payer IP asset. * @param request - The request object that contains all data needed to pay royalty on behalf. @@ -72,7 +80,6 @@ export class RoyaltyClient { * @param request.amount The amount to pay. * @param request.txOptions [Optional] The transaction options. * @returns A Promise that resolves to an object containing the transaction hash. - * @emits RoyaltyPaid (receiverIpId, payerIpId, msg.sender, token, amount) */ public async payRoyaltyOnBehalf( request: PayRoyaltyOnBehalfRequest, @@ -86,10 +93,77 @@ export class RoyaltyClient { }); if (request.txOptions?.waitForTransaction) { await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); + return { txHash }; + } else { + return { txHash }; } - return { txHash }; } catch (error) { handleError(error, "Failed to pay royalty on behalf"); } } + + /** + * Calculates the amount of revenue token claimable by a token holder at certain snapshot. + * @param request - The request object that contains all data needed to claim Revenue. + * @param request.royaltyVaultIpId The id of the royalty vault. + * @param request.account The address of the token holder. + * @param request.snapshotId The snapshot id. + * @param request.token The revenue token to claim. + * @param request.txOptions [Optional] The transaction options. + * @returns A Promise that contains the amount of revenue token claimable + */ + public async claimableRevenue( + request: ClaimableRevenueRequest, + ): Promise { + try { + const proxyAddress = await this.getRoyaltyVaultProxyAddress(request.royaltyVaultIpId); + const ipRoyaltyVault = new IpRoyaltyVaultImplClient( + this.rpcClient, + this.wallet, + proxyAddress, + ); + return await ipRoyaltyVault.claimableRevenue({ + account: request.account, + snapshotId: BigInt(request.snapshotId), + token: request.token, + }); + } catch (error) { + handleError(error, "Failed to calculate claimable revenue"); + } + } + /** + * Snapshots the claimable revenue and royalty token amounts. + * @param request - The request object that contains all data needed to snapshot. + * @param request.royaltyVaultIpId The id of the royalty vault. + * @param request.txOptions [Optional] The transaction options. + * @returns A Promise that resolves to an object containing the transaction hash and optional snapshotId if waitForTxn is set to true. + * @emits SnapshotCompleted (snapshotId, snapshotTimestamp, unclaimedTokens). + */ + public async snapshot(request: SnapshotRequest): Promise { + try { + const proxyAddress = await this.getRoyaltyVaultProxyAddress(request.royaltyVaultIpId); + const ipRoyaltyVault = new IpRoyaltyVaultImplClient( + this.rpcClient, + this.wallet, + proxyAddress, + ); + const txHash = await ipRoyaltyVault.snapshot(); + if (request.txOptions?.waitForTransaction) { + const txReceipt = await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); + const targetLogs = ipRoyaltyVault.parseTxSnapshotCompletedEvent(txReceipt); + return { txHash, snapshotId: targetLogs[0].snapshotId }; + } else { + return { txHash }; + } + } catch (error) { + handleError(error, "Failed to snapshot"); + } + } + + private async getRoyaltyVaultProxyAddress(royaltyVaultIpId: Hex): Promise { + const data = await this.royaltyPolicyLAPClient.getRoyaltyData({ + ipId: royaltyVaultIpId, + }); + return data[1]; + } } diff --git a/packages/core-sdk/src/types/resources/license.ts b/packages/core-sdk/src/types/resources/license.ts index 120ec505..81872b30 100644 --- a/packages/core-sdk/src/types/resources/license.ts +++ b/packages/core-sdk/src/types/resources/license.ts @@ -12,7 +12,7 @@ export type License = { licensorIpId: Hex; }; -export type RegisterLicenseTermsRequest = { +export type RegisterNonComSocialRemixingPILRequest = { txOptions?: TxOptions; }; @@ -36,7 +36,7 @@ export type LicenseTerms = { }; export type LicenseTermsIdResponse = number; -export type RegisterLicenseTermsResponse = { +export type RegisterPILResponse = { licenseTermsId?: string; txHash?: string; }; diff --git a/packages/core-sdk/src/types/resources/royalty.ts b/packages/core-sdk/src/types/resources/royalty.ts index afef6880..753dd6a6 100644 --- a/packages/core-sdk/src/types/resources/royalty.ts +++ b/packages/core-sdk/src/types/resources/royalty.ts @@ -23,12 +23,13 @@ export type RoyaltyContext = { export type CollectRoyaltyTokensRequest = { ancestorIpId: Hex; - derivativeId: Hex; + royaltyVaultIpId: Hex; txOptions?: TxOptions; }; export type CollectRoyaltyTokensResponse = { txHash: string; + royaltyTokensCollected?: string; }; export type RoyaltyData = [ @@ -40,16 +41,14 @@ export type RoyaltyData = [ ]; export type ClaimableRevenueRequest = { + royaltyVaultIpId: Hex; account: Hex; - snapshotId: bigint; + snapshotId: string; token: Hex; txOptions?: TxOptions; }; -export type ClaimableRevenueResponse = { - claimableRevenueAmount: bigint; - txHash: string; -}; +export type ClaimableRevenueResponse = bigint; export type PayRoyaltyOnBehalfRequest = { receiverIpId: Hex; @@ -63,7 +62,14 @@ export type PayRoyaltyOnBehalfResponse = { txHash: string; }; -export type ApproveResponse = { +export type SnapshotRequest = { + royaltyVaultIpId: Hex; + txOptions?: TxOptions; +}; + +export type SnapshotResponse = { txHash: string; - success: boolean; + snapshotId?: bigint; }; + +export type RoyaltyVaultAddress = Hex; diff --git a/packages/core-sdk/test/env.ts b/packages/core-sdk/test/env.ts deleted file mode 100644 index 889e26bd..00000000 --- a/packages/core-sdk/test/env.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Hex } from "viem"; -import { ContractAddress } from "../src/types/config"; - -const sepolia: Record = { - AccessController: "0x674d6E1f7b5e2d714DBa588e9d046965225517c8", - ArbitrationPolicySP: "0xb41BC78478878B338336C5E7a34292213779cd6F", - DisputeModule: "0x3A96cad7b2aC783a6811c7c3e8DEF30E8a4cfcDb", - IPAccountImpl: "0x7481a227A11860E80f69AB39d0165258f4c139f6", - IPAccountRegistry: "0x74Cbd8CCc22290FeaaE8421D4FFc6760210B5B0C", - IPAssetRegistry: "0xb1534826Bc9D77d818CbC596435f530778C73865", - LicenseRegistry: "0x66f6865668F2B9213Ed05b97eE97beb97A75e243", - LicensingModule: "0x2ac240293f12032E103458451dE8A8096c5A72E8", - PILicenseTemplate: "0xd0Be223ae9719bBD93447ecf5289319CCf8cA227", - RegistrationModule: "0x193f0Cc84d51Fc38a30658d7eFffEB2C5Cc25840", - RoyaltyPolicyLAP: "0xb811a9aD59375eDC449cb3A05eB4672042BB9Daf", -}; - -export const storyTestnetAddress: Record = { - AccessController: "0x7e253Df9b0fC872746877Fa362b2cAf32712d770", - ArbitrationPolicySP: "0xA25bc70932282b35407e0DC08cc9C91f6b00CEf0", - CoreMetadataModule: "0x8A8FBAaEB6A0B7736ebde31c6F49CccD808232bA", - CoreMetadataViewModule: "0x8A8FBAaEB6A0B7736ebde31c6F49CccD808232bA", - DisputeModule: "0x6d54456Ae5DCbDC0C9E2713cC8E650fE4f445c7C", - Governance: "0x63F4A670A8b518ef5eb291559BdAbea4b31c1AC4", - IPAccountImpl: "0x38cAfD16502B1d61c6399A18d6Fa1Ea8CEca3678", - IPAccountRegistry: "0x8448d0F77D7e67e0814f83D988aB3344D46bb1E4", - IPAssetRegistry: "0x862de97662a1231FFc14038eC1BE93aB129D2169", - IpRoyaltyVaultBeacon: "0xE92Cdf428f07D92248b6b15ce59a9d5597428F21", - IpRoyaltyVaultImpl: "0x8Be22cc2D13ADF496a417D9C616dA4a253c68Af8", - LicenseRegistry: "0x0c3D467537FAd845a78728CEdc3D9447338c5422", - LicenseToken: "0xD40b7bCA204f96a346021e31c9ad54FF495226e7", - LicensingModule: "0xEeDDE5529122b621105798860F235c28FD3aBA40", - MockERC20: "0xA36F2A4A02f5C215d1b3630f71A4Ff55B5492AAE", - MockERC721: "0x83DD606d14CcEb629dE9Bf8Aad7aE63767dB476f", - MockTokenGatedHook: "0x80519d82FBE474AB9E863A066AC32E3eeAFc8F11", - ModuleRegistry: "0xf2965E3B6251905Dd1E8671077760D07b0408cf2", - PILicenseTemplate: "0xd0Be223ae9719bBD93447ecf5289319CCf8cA227", - RoyaltyModule: "0x551AD8CD7893003cE00500aC2aCF1E327763D9f6", - RoyaltyPolicyLAP: "0x2EcdB5bD12a037dCb9De0Ab7957f35FEeF758eA6", - TokenWithdrawalModule: "0xC573E5c36B8FA5108b78f7357947972D030699d5", -}; - -export const contractAddress: ContractAddress = { - sepolia, - 11155111: sepolia, - storyTestnet: storyTestnetAddress, - 1513: storyTestnetAddress, -}; diff --git a/packages/core-sdk/test/integration/storyTestNet/ipAsset.storyTest.test.ts b/packages/core-sdk/test/integration/storyTestNet/ipAsset.storyTest.test.ts index 63bf6423..e4996f37 100644 --- a/packages/core-sdk/test/integration/storyTestNet/ipAsset.storyTest.test.ts +++ b/packages/core-sdk/test/integration/storyTestNet/ipAsset.storyTest.test.ts @@ -1,18 +1,17 @@ import chai from "chai"; import { StoryClient, StoryConfig } from "../../../src"; -import { Hex, createPublicClient, createWalletClient, http } from "viem"; +import { Hex, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; -import { chainStringToViemChain } from "../../../src/utils/utils"; -import { storyTestnetAddress } from "../../env"; import chaiAsPromised from "chai-as-promised"; +import { MockERC721, getTokenId } from "./util"; chai.use(chaiAsPromised); const expect = chai.expect; -const parentIpId = "0xca2def24ec4A50633a922245F84518504aaAE562"; +let parentIpId: Hex; +let childIpId: Hex; const noCommercialLicenseTermsId = "6"; -let startTokenId = 126; -let ipId: Hex; +let startTokenId = 176; describe.skip("IP Asset Functions in storyTestnet", () => { let client: StoryClient; before(function () { @@ -23,53 +22,14 @@ describe.skip("IP Asset Functions in storyTestnet", () => { }; client = StoryClient.newClient(config); }); - const getTokenId = async (tokenId: number): Promise => { - const baseConfig = { - chain: chainStringToViemChain("storyTestnet"), - transport: http(process.env.STORY_TEST_NET_RPC_PROVIDER_URL), - } as const; - const publicClient = createPublicClient(baseConfig); - const walletClient = createWalletClient({ - ...baseConfig, - account: privateKeyToAccount(process.env.STORY_TEST_NET_WALLET_PRIVATE_KEY as Hex), - }); - const { request } = await publicClient.simulateContract({ - abi: [ - { - inputs: [ - { internalType: "address", name: "to", type: "address" }, - { - internalType: "uint256", - name: "tokenId", - type: "uint256", - }, - ], - name: "mintId", - outputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], - stateMutability: "nonpayable", - type: "function", - }, - ], - address: storyTestnetAddress.MockERC721, - functionName: "mintId", - args: [process.env.STORY_TEST_NET_TEST_WALLET_ADDRESS as Hex, BigInt(tokenId)], - account: walletClient.account, - }); - const hash = await walletClient.writeContract(request); - const { logs } = await publicClient.waitForTransactionReceipt({ - hash, - }); - if (logs[0].topics[3]) { - return parseInt(logs[0].topics[3], 16).toString(); - } - }; + describe("Create IP Asset", async function () { it("should not throw error when registering a IP Asset", async () => { const tokenId = await getTokenId(startTokenId++); const waitForTransaction: boolean = true; const response = await expect( client.ipAsset.register({ - tokenContract: storyTestnetAddress.MockERC721, + tokenContract: MockERC721, tokenId: tokenId!, txOptions: { waitForTransaction: waitForTransaction, @@ -78,11 +38,21 @@ describe.skip("IP Asset Functions in storyTestnet", () => { ).to.not.be.rejected; if (waitForTransaction) { expect(response.ipId).to.be.a("string").and.not.empty; - ipId = response.ipId; + childIpId = response.ipId; } }); it("should not throw error when registering derivative", async () => { + const tokenId = await getTokenId(startTokenId++); + parentIpId = ( + await client.ipAsset.register({ + tokenContract: MockERC721, + tokenId: tokenId!, + txOptions: { + waitForTransaction: true, + }, + }) + ).ipId!; await client.license.attachLicenseTerms({ ipId: parentIpId, licenseTermsId: noCommercialLicenseTermsId, @@ -92,7 +62,7 @@ describe.skip("IP Asset Functions in storyTestnet", () => { }); const response = await expect( client.ipAsset.registerDerivative({ - childIpId: ipId, + childIpId: childIpId, parentIpIds: [parentIpId], licenseTermsIds: [noCommercialLicenseTermsId], txOptions: { @@ -107,7 +77,7 @@ describe.skip("IP Asset Functions in storyTestnet", () => { const tokenId = await getTokenId(startTokenId++); const ipId = ( await client.ipAsset.register({ - tokenContract: storyTestnetAddress.MockERC721, + tokenContract: MockERC721, tokenId: tokenId!, txOptions: { waitForTransaction: true, diff --git a/packages/core-sdk/test/integration/storyTestNet/license.storyTest.test.ts b/packages/core-sdk/test/integration/storyTestNet/license.storyTest.test.ts index 169aed41..80d6c7cd 100644 --- a/packages/core-sdk/test/integration/storyTestNet/license.storyTest.test.ts +++ b/packages/core-sdk/test/integration/storyTestNet/license.storyTest.test.ts @@ -3,8 +3,8 @@ import { StoryClient, StoryConfig } from "../../../src"; import { createPublicClient, createWalletClient, Hex, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import chaiAsPromised from "chai-as-promised"; -import { storyTestnetAddress } from "../../env"; import { chainStringToViemChain } from "../../../src/utils/utils"; +import { MockERC20, MockERC721 } from "./util"; chai.use(chaiAsPromised); const expect = chai.expect; @@ -35,7 +35,7 @@ describe.skip("License Functions in storyTestnet", () => { it("should not throw error when registering license with commercial use", async function () { const result = await client.license.registerCommercialUsePIL({ mintingFee: "1", - currency: storyTestnetAddress.MockERC20, + currency: MockERC20, txOptions: { waitForTransaction: true, }, @@ -48,7 +48,7 @@ describe.skip("License Functions in storyTestnet", () => { const result = await client.license.registerCommercialRemixPIL({ mintingFee: "1", commercialRevShare: 100, - currency: storyTestnetAddress.MockERC20, + currency: MockERC20, txOptions: { waitForTransaction: true, }, @@ -89,7 +89,7 @@ describe.skip("License Functions in storyTestnet", () => { type: "function", }, ], - address: storyTestnetAddress.MockERC721, + address: MockERC721, functionName: "mintId", args: [account.address, BigInt(Math.round(new Date().getTime() / 1000))], }); @@ -102,7 +102,7 @@ describe.skip("License Functions in storyTestnet", () => { } const registerResult = await client.ipAsset.register({ - tokenContract: storyTestnetAddress.MockERC721, + tokenContract: MockERC721, tokenId: tokenId, txOptions: { waitForTransaction: true, @@ -121,7 +121,6 @@ describe.skip("License Functions in storyTestnet", () => { it("should not throw error when attach License Terms", async function () { const result = await client.license.attachLicenseTerms({ ipId: ipId, - licenseTemplate: storyTestnetAddress.PILicenseTemplate, licenseTermsId: licenseId, txOptions: { waitForTransaction: true, diff --git a/packages/core-sdk/test/integration/storyTestNet/royalty.storyTest.test.ts b/packages/core-sdk/test/integration/storyTestNet/royalty.storyTest.test.ts index b74fbcde..4744605d 100644 --- a/packages/core-sdk/test/integration/storyTestNet/royalty.storyTest.test.ts +++ b/packages/core-sdk/test/integration/storyTestNet/royalty.storyTest.test.ts @@ -1,225 +1,212 @@ -// import chai from "chai"; -// import { StoryClient, StoryConfig } from "../../../src"; -// import { -// Hex, -// http, -// Account, -// createPublicClient, -// createWalletClient, -// PublicClient, -// WalletClient, -// } from "viem"; -// import { privateKeyToAccount } from "viem/accounts"; -// import { -// getIPAssetRegistryConfig, -// getLicenseRegistryConfig, -// getLicensingModuleConfig, -// getRoyaltyPolicyLAPConfig, -// getRoyaltyVaultImplConfig, -// } from "../../config"; -// import chaiAsPromised from "chai-as-promised"; -// import { storyTestnetAddress } from "../../env"; -// import { chainStringToViemChain, waitTx } from "../../../src/utils/utils"; -// chai.use(chaiAsPromised); -// const expect = chai.expect; +import chai from "chai"; +import { StoryClient, StoryConfig } from "../../../src"; +import { + Hex, + http, + createPublicClient, + createWalletClient, + PublicClient, + WalletClient, +} from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import chaiAsPromised from "chai-as-promised"; +import { chainStringToViemChain, waitTx } from "../../../src/utils/utils"; +import { MockERC721, MockERC20, getTokenId } from "./util"; -// describe.skip("Test royalty Functions", () => { -// let client: StoryClient; -// let senderAddress: string; -// let publicClient: PublicClient; -// let walletClient: WalletClient; -// before(function () { -// const config: StoryConfig = { -// chainId: "storyTestnet", -// transport: http(process.env.STORY_TEST_NET_RPC_PROVIDER_URL), -// account: privateKeyToAccount(process.env.STORY_TEST_NET_WALLET_PRIVATE_KEY as Hex), -// }; -// const configAccount: Account = config.account as Account; -// senderAddress = configAccount.address; -// client = StoryClient.newClient(config); -// client.ipAsset.ipAssetRegistryConfig = getIPAssetRegistryConfig("1513"); -// client.license.licenseRegistryConfig = getLicenseRegistryConfig("1513"); -// client.license.licensingModuleConfig = getLicensingModuleConfig("1513"); -// client.royalty.royaltyPolicyLAPConfig = getRoyaltyPolicyLAPConfig("1513"); -// client.royalty.royaltyVaultImplConfig = getRoyaltyVaultImplConfig("1513"); -// const baseConfig = { -// chain: chainStringToViemChain("storyTestnet"), -// transport: http(process.env.STORY_TEST_NET_RPC_PROVIDER_URL), -// } as const; -// publicClient = createPublicClient(baseConfig); -// walletClient = createWalletClient({ -// ...baseConfig, -// account: privateKeyToAccount(process.env.STORY_TEST_NET_WALLET_PRIVATE_KEY as Hex), -// }); -// }); -// describe("Royalty in storyTestNet", async function () { -// let ipId1: Hex; -// let ipId2: Hex; -// let tokenId = 44; -// const getIpId = async (): Promise => { -// tokenId++; +chai.use(chaiAsPromised); +const expect = chai.expect; +let startTokenId = 180; +let snapshotId: bigint; +describe.skip("Test royalty Functions", () => { + let client: StoryClient; + let publicClient: PublicClient; + let walletClient: WalletClient; -// const { request } = await publicClient.simulateContract({ -// abi: [ -// { -// inputs: [ -// { internalType: "address", name: "to", type: "address" }, -// { -// internalType: "uint256", -// name: "tokenId", -// type: "uint256", -// }, -// ], -// name: "mintId", -// outputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], -// stateMutability: "nonpayable", -// type: "function", -// }, -// ], -// address: storyTestnetAddress.MockERC721, -// functionName: "mintId", -// args: [process.env.STORY_TEST_NET_TEST_WALLET_ADDRESS as Hex, BigInt(tokenId)], -// account: walletClient.account, -// }); -// const hash = await walletClient.writeContract(request); -// const { logs } = await publicClient.waitForTransactionReceipt({ -// hash, -// }); -// const response = await client.ipAsset.register({ -// tokenContract: storyTestnetAddress.MockERC721, -// tokenId: parseInt(logs[0].topics[3]!, 16).toString(), -// txOptions: { -// waitForTransaction: true, -// }, -// }); -// return response.ipId! as Hex; -// }; -// const getCommercialPolicyId = async (): Promise => { -// const response = await client.license.registerCommercialUsePIL({ -// mintingFee: "1", -// currency: storyTestnetAddress.MockERC20, -// txOptions: { -// waitForTransaction: true, -// }, -// }); -// return response.licenseTermsId!; -// }; + before(function () { + const config: StoryConfig = { + chainId: "storyTestnet", + transport: http(process.env.STORY_TEST_NET_RPC_PROVIDER_URL), + account: privateKeyToAccount(process.env.STORY_TEST_NET_WALLET_PRIVATE_KEY as Hex), + }; + client = StoryClient.newClient(config); + const baseConfig = { + chain: chainStringToViemChain("storyTestnet"), + transport: http(process.env.STORY_TEST_NET_RPC_PROVIDER_URL), + } as const; + publicClient = createPublicClient(baseConfig); + walletClient = createWalletClient({ + ...baseConfig, + account: privateKeyToAccount(process.env.STORY_TEST_NET_WALLET_PRIVATE_KEY as Hex), + }); + }); + describe("Royalty in storyTestNet", async function () { + let ipId1: Hex; + let ipId2: Hex; + const getIpId = async (): Promise => { + console.log("startTokenId", startTokenId); + const tokenId = await getTokenId(startTokenId++); + const response = await client.ipAsset.register({ + tokenContract: MockERC721, + tokenId: tokenId!, + txOptions: { + waitForTransaction: true, + }, + }); + return response.ipId! as Hex; + }; + const getCommercialPolicyId = async (): Promise => { + const response = await client.license.registerCommercialRemixPIL({ + mintingFee: "1", + currency: MockERC20, + commercialRevShare: 100, + txOptions: { + waitForTransaction: true, + }, + }); + console.log("licenseTermsId", response.licenseTermsId); + return response.licenseTermsId!; + }; -// const attachLicenseTerms = async (ipId: Hex, licenseTermsId: string) => { -// await client.license.attachLicenseTerms({ -// ipId, -// licenseTermsId: licenseTermsId, -// txOptions: { -// waitForTransaction: true, -// }, -// }); -// }; + const attachLicenseTerms = async (ipId: Hex, licenseTermsId: string) => { + await client.license.attachLicenseTerms({ + ipId, + licenseTermsId: licenseTermsId, + txOptions: { + waitForTransaction: true, + }, + }); + }; -// const registerDerivative = async (ipId: Hex, parentIpId: Hex, licenseTermsIds: string) => { -// const result = await client.ipAsset.registerDerivative({ -// childIpId: ipId, -// parentIpIds: [parentIpId], -// licenseTermsIds: [licenseTermsIds], -// txOptions: { -// waitForTransaction: false, -// }, -// }); -// }; -// before(async () => { -// ipId1 = await getIpId(); -// ipId2 = await getIpId(); -// const licenseTermsId = await getCommercialPolicyId(); -// await attachLicenseTerms(ipId1, licenseTermsId); -// await registerDerivative(ipId2, ipId1, licenseTermsId); -// }); + before(async () => { + ipId1 = await getIpId(); + ipId2 = await getIpId(); + console.log("ipId1", ipId1, "ipId2", ipId2); + const licenseTermsId = await getCommercialPolicyId(); + await attachLicenseTerms(ipId1, licenseTermsId); + await client.ipAsset.registerDerivative({ + childIpId: ipId2, + parentIpIds: [ipId1], + licenseTermsIds: [licenseTermsId], + txOptions: { + waitForTransaction: true, + }, + }); + }); -// it("should not throw error when pay royalty on behalf", async () => { -// //1. approve the spender -// const abi = [ -// { -// inputs: [ -// { -// internalType: "address", -// name: "spender", -// type: "address", -// }, -// { -// internalType: "uint256", -// name: "value", -// type: "uint256", -// }, -// ], -// name: "approve", -// outputs: [ -// { -// internalType: "bool", -// name: "", -// type: "bool", -// }, -// ], -// stateMutability: "nonpayable", -// type: "function", -// }, -// ]; -// const { request: call } = await publicClient.simulateContract({ -// abi: abi, -// address: storyTestnetAddress.MockERC20, -// functionName: "approve", -// args: [client.royalty.royaltyPolicyLAPConfig.address, BigInt(100)], -// account: walletClient.account, -// }); -// const approveHash = await walletClient.writeContract(call); -// await waitTx(publicClient, approveHash); -// //2. mint the token -// const { request } = await publicClient.simulateContract({ -// abi: [ -// { -// inputs: [ -// { -// internalType: "address", -// name: "to", -// type: "address", -// }, -// { -// internalType: "uint256", -// name: "amount", -// type: "uint256", -// }, -// ], -// name: "mint", -// outputs: [], -// stateMutability: "nonpayable", -// type: "function", -// }, -// ], -// address: storyTestnetAddress.MockERC20, -// functionName: "mint", -// account: walletClient.account, -// args: [process.env.STORY_TEST_NET_TEST_WALLET_ADDRESS! as Hex, BigInt(100)], -// }); -// const mintHash = await walletClient.writeContract(request); -// await waitTx(publicClient, mintHash); -// const response = await client.royalty.payRoyaltyOnBehalf({ -// receiverIpId: ipId1, -// payerIpId: ipId2, -// token: storyTestnetAddress.MockERC20, -// amount: BigInt(10), -// txOptions: { -// waitForTransaction: true, -// }, -// }); -// expect(response.txHash).to.be.a("string").not.empty; -// }); + it("should not throw error when pay royalty on behalf", async () => { + //1. approve the spender + const abi = [ + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "approve", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + ]; + const { request: call } = await publicClient.simulateContract({ + abi: abi, + address: MockERC20, + functionName: "approve", + args: [client.royalty.royaltyPolicyLAPClient.address, BigInt(100)], + account: walletClient.account, + }); + const approveHash = await walletClient.writeContract(call); + await waitTx(publicClient, approveHash); + //2. mint the token + const { request } = await publicClient.simulateContract({ + abi: [ + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + ], + address: MockERC20, + functionName: "mint", + account: walletClient.account, + args: [process.env.STORY_TEST_NET_TEST_WALLET_ADDRESS! as Hex, BigInt(1000)], + }); + const mintHash = await walletClient.writeContract(request); + await waitTx(publicClient, mintHash); + const response = await client.royalty.payRoyaltyOnBehalf({ + receiverIpId: ipId1, + payerIpId: ipId2, + token: MockERC20, + amount: BigInt(10), + txOptions: { + waitForTransaction: true, + }, + }); + expect(response.txHash).to.be.a("string").not.empty; + }); -// it("should not throw error when collect royalty tokens", async () => { -// const response = await client.royalty.collectRoyaltyTokens({ -// ancestorIpId: ipId1, -// derivativeId: ipId2, -// txOptions: { -// waitForTransaction: true, -// }, -// }); -// expect(response.txHash).to.be.a("string").not.empty; -// }); -// }); -// }); + it("should not throw error when snapshot", async () => { + const response = await client.royalty.snapshot({ + royaltyVaultIpId: ipId2, + txOptions: { + waitForTransaction: true, + }, + }); + expect(response.txHash).to.be.a("string").not.empty; + expect(response.snapshotId).to.be.a("bigint"); + snapshotId = response.snapshotId!; + console.log("snapshot", snapshotId); + }); + + it("should not throw error when collect royalty tokens", async () => { + const response = await client.royalty.collectRoyaltyTokens({ + ancestorIpId: ipId1, + royaltyVaultIpId: ipId2, + txOptions: { + waitForTransaction: true, + }, + }); + expect(response.txHash).to.be.a("string").not.empty; + expect(response.royaltyTokensCollected).to.be.a("string").not.empty; + }); + + it("should not throw error when claimable revenue", async () => { + const response = await client.royalty.claimableRevenue({ + royaltyVaultIpId: ipId2, + account: ipId1, + snapshotId: snapshotId.toString(), + token: "0xA36F2A4A02f5C215d1b3630f71A4Ff55B5492AAE", + txOptions: { + waitForTransaction: true, + }, + }); + expect(response).to.be.a("bigint"); + }); + }); +}); diff --git a/packages/core-sdk/test/integration/storyTestNet/util.ts b/packages/core-sdk/test/integration/storyTestNet/util.ts new file mode 100644 index 00000000..f9c9e834 --- /dev/null +++ b/packages/core-sdk/test/integration/storyTestNet/util.ts @@ -0,0 +1,47 @@ +import { http, createPublicClient, createWalletClient, Hex } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { chainStringToViemChain } from "../../../src/utils/utils"; + +export const getTokenId = async (tokenId: number): Promise => { + const baseConfig = { + chain: chainStringToViemChain("storyTestnet"), + transport: http(process.env.STORY_TEST_NET_RPC_PROVIDER_URL), + } as const; + const publicClient = createPublicClient(baseConfig); + const walletClient = createWalletClient({ + ...baseConfig, + account: privateKeyToAccount(process.env.STORY_TEST_NET_WALLET_PRIVATE_KEY as Hex), + }); + const { request } = await publicClient.simulateContract({ + abi: [ + { + inputs: [ + { internalType: "address", name: "to", type: "address" }, + { + internalType: "uint256", + name: "tokenId", + type: "uint256", + }, + ], + name: "mintId", + outputs: [{ internalType: "uint256", name: "tokenId", type: "uint256" }], + stateMutability: "nonpayable", + type: "function", + }, + ], + address: MockERC721, + functionName: "mintId", + args: [process.env.STORY_TEST_NET_TEST_WALLET_ADDRESS as Hex, BigInt(tokenId)], + account: walletClient.account, + }); + const hash = await walletClient.writeContract(request); + const { logs } = await publicClient.waitForTransactionReceipt({ + hash, + }); + if (logs[0].topics[3]) { + return parseInt(logs[0].topics[3], 16).toString(); + } +}; + +export const MockERC20 = "0xA36F2A4A02f5C215d1b3630f71A4Ff55B5492AAE"; +export const MockERC721 = "0x83DD606d14CcEb629dE9Bf8Aad7aE63767dB476f"; diff --git a/packages/wagmi-generater/wagmi.config.ts b/packages/wagmi-generater/wagmi.config.ts index d0a9aa9f..4a35caa2 100644 --- a/packages/wagmi-generater/wagmi.config.ts +++ b/packages/wagmi-generater/wagmi.config.ts @@ -122,6 +122,9 @@ export default defineConfig(async () => { "claimableRevenue", "collectRoyaltyTokens", "ipId", + "RoyaltyTokensCollected", + "snapshot", + "SnapshotCompleted" ], "PiLicenseTemplate": [ "getLicenseTermsId",