From 058eb0750808b3f5770955b3f2a18b8c54248cb5 Mon Sep 17 00:00:00 2001 From: Don <100505855+DonFungible@users.noreply.github.com> Date: Fri, 10 May 2024 11:02:03 -0700 Subject: [PATCH 1/2] export SupportedChainIds (#174) --- packages/core-sdk/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core-sdk/src/index.ts b/packages/core-sdk/src/index.ts index 191691dc..5da4aedc 100644 --- a/packages/core-sdk/src/index.ts +++ b/packages/core-sdk/src/index.ts @@ -7,7 +7,7 @@ export { LicenseClient } from "./resources/license"; export { DisputeClient } from "./resources/dispute"; export { NftClient } from "./resources/nftClient"; -export type { StoryConfig } from "./types/config"; +export type { StoryConfig, SupportedChainIds } from "./types/config"; export type { TypedData } from "./types/common"; export type { From 6f1c4a2a233e84c5db6f6c7be31312b030b5f323 Mon Sep 17 00:00:00 2001 From: Ze Date: Fri, 10 May 2024 22:51:52 -0700 Subject: [PATCH 2/2] Integrate mintAndRegisterIpAndAttachPilTerms method in spg and skip ip account execute (#175) * Extract test class about the MockERC20 * Extract spg module * Make signature * Adjust input and output type to ensure flexibility of input parameters and keep same type about smart contract in output * Change Hex type into Address * Call executeWithSig successfully * Delete spg module * Add registerIpAndAttachPilTerms method * Add unit test about createIpAssetWithPilTerms method * Add unit test about getIpAccountNonce * Bump version to 1.0.0-rc.11 * Add registerDerivativeIp and the related tests * Delete spg type * Add registerIpAndAttachPilTerms and the related tests * Add nftClient tests * Cancel skip tests * Skip ip account test --------- Co-authored-by: bonnie --- packages/core-sdk/package.json | 2 +- packages/core-sdk/src/abi/generated.ts | 368 ++++++++++++++++- packages/core-sdk/src/index.ts | 12 +- packages/core-sdk/src/resources/dispute.ts | 2 +- packages/core-sdk/src/resources/ipAccount.ts | 23 +- packages/core-sdk/src/resources/ipAsset.ts | 232 +++++++++-- packages/core-sdk/src/resources/license.ts | 42 +- packages/core-sdk/src/resources/permission.ts | 3 +- packages/core-sdk/src/resources/royalty.ts | 14 +- .../core-sdk/src/types/resources/dispute.ts | 26 +- .../core-sdk/src/types/resources/ipAccount.ts | 20 +- .../core-sdk/src/types/resources/ipAsset.ts | 76 +++- .../core-sdk/src/types/resources/license.ts | 40 +- .../src/types/resources/permission.ts | 8 +- .../core-sdk/src/types/resources/royalty.ts | 48 +-- .../core-sdk/src/types/resources/tagging.ts | 8 +- .../src/utils/getLicenseTermsByType.ts | 2 +- packages/core-sdk/src/utils/utils.ts | 10 +- .../core-sdk/test/integration/dispute.test.ts | 4 +- .../test/integration/ipAccount.test.ts | 127 +++--- .../core-sdk/test/integration/ipAsset.test.ts | 296 +++++++++++-- .../core-sdk/test/integration/license.test.ts | 19 +- .../test/integration/permission.test.ts | 4 +- .../core-sdk/test/integration/royalty.test.ts | 145 ++----- .../test/integration/utils/mockERC20.ts | 98 +++++ .../test/integration/{ => utils}/util.ts | 35 +- packages/core-sdk/test/unit/client.test.ts | 7 + .../test/unit/resources/ipAccount.test.ts | 11 + .../test/unit/resources/ipAsset.test.ts | 391 +++++++++++++++++- .../test/unit/resources/license.test.ts | 16 +- .../test/unit/resources/nftClient.test.ts | 23 +- .../test/unit/resources/royalty.test.ts | 36 +- .../core-sdk/test/unit/utils/utils.test.ts | 5 - packages/wagmi-generater/wagmi.config.ts | 14 +- 34 files changed, 1705 insertions(+), 462 deletions(-) create mode 100644 packages/core-sdk/test/integration/utils/mockERC20.ts rename packages/core-sdk/test/integration/{ => utils}/util.ts (56%) diff --git a/packages/core-sdk/package.json b/packages/core-sdk/package.json index 91e757ea..22306690 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.10", + "version": "1.0.0-rc.11", "description": "Story Protocol Core SDK", "main": "dist/story-protocol-core-sdk.cjs.js", "module": "dist/story-protocol-core-sdk.esm.js", diff --git a/packages/core-sdk/src/abi/generated.ts b/packages/core-sdk/src/abi/generated.ts index 1bf0a91c..c1c2db17 100644 --- a/packages/core-sdk/src/abi/generated.ts +++ b/packages/core-sdk/src/abi/generated.ts @@ -400,6 +400,177 @@ export const accessControllerConfig = { abi: accessControllerAbi, } as const; +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// CoreMetadataModule +////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * [__View Contract on Sepolia Etherscan__](https://sepolia.etherscan.io/address/0xDa498A3f7c8a88cb72201138C366bE3778dB9575) + */ +export const coreMetadataModuleAbi = [ + { + type: "constructor", + inputs: [ + { name: "accessController", internalType: "address", type: "address" }, + { name: "ipAccountRegistry", internalType: "address", type: "address" }, + ], + stateMutability: "nonpayable", + }, + { + type: "error", + inputs: [{ name: "ipAccount", internalType: "address", type: "address" }], + name: "AccessControlled__NotIpAccount", + }, + { type: "error", inputs: [], name: "AccessControlled__ZeroAddress" }, + { + type: "error", + inputs: [], + name: "CoreMetadataModule__MetadataAlreadyFrozen", + }, + { + type: "event", + anonymous: false, + inputs: [{ name: "ipId", internalType: "address", type: "address", indexed: true }], + name: "MetadataFrozen", + }, + { + type: "event", + anonymous: false, + inputs: [ + { name: "ipId", internalType: "address", type: "address", indexed: true }, + { + name: "metadataURI", + internalType: "string", + type: "string", + indexed: false, + }, + { + name: "metadataHash", + internalType: "bytes32", + type: "bytes32", + indexed: false, + }, + ], + name: "MetadataURISet", + }, + { + type: "event", + anonymous: false, + inputs: [ + { name: "ipId", internalType: "address", type: "address", indexed: true }, + { + name: "nftTokenURI", + internalType: "string", + type: "string", + indexed: false, + }, + { + name: "nftMetadataHash", + internalType: "bytes32", + type: "bytes32", + indexed: false, + }, + ], + name: "NFTTokenURISet", + }, + { + type: "function", + inputs: [], + name: "ACCESS_CONTROLLER", + outputs: [{ name: "", internalType: "contract IAccessController", type: "address" }], + stateMutability: "view", + }, + { + type: "function", + inputs: [], + name: "IP_ACCOUNT_REGISTRY", + outputs: [ + { + name: "", + internalType: "contract IIPAccountRegistry", + type: "address", + }, + ], + stateMutability: "view", + }, + { + type: "function", + inputs: [{ name: "ipId", internalType: "address", type: "address" }], + name: "freezeMetadata", + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + inputs: [{ name: "ipId", internalType: "address", type: "address" }], + name: "isMetadataFrozen", + outputs: [{ name: "", internalType: "bool", type: "bool" }], + stateMutability: "view", + }, + { + type: "function", + inputs: [], + name: "name", + outputs: [{ name: "", internalType: "string", type: "string" }], + stateMutability: "view", + }, + { + type: "function", + inputs: [ + { name: "ipId", internalType: "address", type: "address" }, + { name: "metadataURI", internalType: "string", type: "string" }, + { name: "metadataHash", internalType: "bytes32", type: "bytes32" }, + { name: "nftMetadataHash", internalType: "bytes32", type: "bytes32" }, + ], + name: "setAll", + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + inputs: [ + { name: "ipId", internalType: "address", type: "address" }, + { name: "metadataURI", internalType: "string", type: "string" }, + { name: "metadataHash", internalType: "bytes32", type: "bytes32" }, + ], + name: "setMetadataURI", + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + inputs: [{ name: "interfaceId", internalType: "bytes4", type: "bytes4" }], + name: "supportsInterface", + outputs: [{ name: "", internalType: "bool", type: "bool" }], + stateMutability: "view", + }, + { + type: "function", + inputs: [ + { name: "ipId", internalType: "address", type: "address" }, + { name: "nftMetadataHash", internalType: "bytes32", type: "bytes32" }, + ], + name: "updateNftTokenURI", + outputs: [], + stateMutability: "nonpayable", + }, +] as const; + +/** + * [__View Contract on Sepolia Etherscan__](https://sepolia.etherscan.io/address/0xDa498A3f7c8a88cb72201138C366bE3778dB9575) + */ +export const coreMetadataModuleAddress = { + 11155111: "0xDa498A3f7c8a88cb72201138C366bE3778dB9575", +} as const; + +/** + * [__View Contract on Sepolia Etherscan__](https://sepolia.etherscan.io/address/0xDa498A3f7c8a88cb72201138C366bE3778dB9575) + */ +export const coreMetadataModuleConfig = { + address: coreMetadataModuleAddress, + abi: coreMetadataModuleAbi, +} as const; + ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DisputeModule ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -7346,6 +7517,55 @@ export class AccessControllerClient extends AccessControllerEventClient { } } +// Contract CoreMetadataModule ============================================================= + +/** + * CoreMetadataModuleSetAllRequest + * + * @param ipId address + * @param metadataURI string + * @param metadataHash bytes32 + * @param nftMetadataHash bytes32 + */ +export type CoreMetadataModuleSetAllRequest = { + ipId: Address; + metadataURI: string; + metadataHash: Hex; + nftMetadataHash: Hex; +}; + +/** + * contract CoreMetadataModule write method + */ +export class CoreMetadataModuleClient { + protected readonly wallet: SimpleWalletClient; + protected readonly rpcClient: PublicClient; + public readonly address: Address; + + constructor(rpcClient: PublicClient, wallet: SimpleWalletClient, address?: Address) { + this.address = address || getAddress(coreMetadataModuleAddress, rpcClient.chain?.id); + this.rpcClient = rpcClient; + this.wallet = wallet; + } + + /** + * method setAll for contract CoreMetadataModule + * + * @param request CoreMetadataModuleSetAllRequest + * @return Promise + */ + public async setAll(request: CoreMetadataModuleSetAllRequest): Promise { + const { request: call } = await this.rpcClient.simulateContract({ + abi: coreMetadataModuleAbi, + address: this.address, + functionName: "setAll", + account: this.wallet.account, + args: [request.ipId, request.metadataURI, request.metadataHash, request.nftMetadataHash], + }); + return await this.wallet.writeContract(call as WriteContractParameters); + } +} + // Contract DisputeModule ============================================================= /** @@ -7633,6 +7853,8 @@ export class DisputeModuleClient extends DisputeModuleEventClient { // Contract IPAccountImpl ============================================================= +export type IpAccountImplStateResponse = bigint; + /** * IpAccountImplExecuteRequest * @@ -7666,16 +7888,40 @@ export type IpAccountImplExecuteWithSigRequest = { }; /** - * contract IPAccountImpl write method + * contract IPAccountImpl readonly method */ -export class IpAccountImplClient { - protected readonly wallet: SimpleWalletClient; +export class IpAccountImplReadOnlyClient { protected readonly rpcClient: PublicClient; public readonly address: Address; - constructor(rpcClient: PublicClient, wallet: SimpleWalletClient, address?: Address) { + constructor(rpcClient: PublicClient, address?: Address) { this.address = address || getAddress(ipAccountImplAddress, rpcClient.chain?.id); this.rpcClient = rpcClient; + } + + /** + * method state for contract IPAccountImpl + * + * @param request IpAccountImplStateRequest + * @return Promise + */ + public async state(): Promise { + return await this.rpcClient.readContract({ + abi: ipAccountImplAbi, + address: this.address, + functionName: "state", + }); + } +} + +/** + * contract IPAccountImpl write method + */ +export class IpAccountImplClient extends IpAccountImplReadOnlyClient { + protected readonly wallet: SimpleWalletClient; + + constructor(rpcClient: PublicClient, wallet: SimpleWalletClient, address?: Address) { + super(rpcClient, address); this.wallet = wallet; } @@ -7725,6 +7971,23 @@ export class IpAccountImplClient { // Contract IPAssetRegistry ============================================================= +/** + * IpAssetRegistryIpAccountRegisteredEvent + * + * @param account address + * @param implementation address + * @param chainId uint256 + * @param tokenContract address + * @param tokenId uint256 + */ +export type IpAssetRegistryIpAccountRegisteredEvent = { + account: Address; + implementation: Address; + chainId: bigint; + tokenContract: Address; + tokenId: bigint; +}; + /** * IpAssetRegistryIpRegisteredEvent * @@ -7797,6 +8060,47 @@ export class IpAssetRegistryEventClient { this.rpcClient = rpcClient; } + /** + * event IPAccountRegistered for contract IPAssetRegistry + */ + public watchIpAccountRegisteredEvent( + onLogs: (txHash: Hex, ev: Partial) => void, + ): WatchContractEventReturnType { + return this.rpcClient.watchContractEvent({ + abi: ipAssetRegistryAbi, + address: this.address, + eventName: "IPAccountRegistered", + onLogs: (evs) => { + evs.forEach((it) => onLogs(it.transactionHash, it.args)); + }, + }); + } + + /** + * parse tx receipt event IPAccountRegistered for contract IPAssetRegistry + */ + public parseTxIpAccountRegisteredEvent( + txReceipt: TransactionReceipt, + ): Array { + const targetLogs: Array = []; + for (const log of txReceipt.logs) { + try { + const event = decodeEventLog({ + abi: ipAssetRegistryAbi, + eventName: "IPAccountRegistered", + data: log.data, + topics: log.topics, + }); + if (event.eventName === "IPAccountRegistered") { + targetLogs.push(event.args); + } + } catch (e) { + /* empty */ + } + } + return targetLogs; + } + /** * event IPRegistered for contract IPAssetRegistry */ @@ -9682,6 +9986,21 @@ export class LicenseTokenReadOnlyClient { // Contract LicensingModule ============================================================= +/** + * LicensingModuleLicenseTermsAttachedEvent + * + * @param caller address + * @param ipId address + * @param licenseTemplate address + * @param licenseTermsId uint256 + */ +export type LicensingModuleLicenseTermsAttachedEvent = { + caller: Address; + ipId: Address; + licenseTemplate: Address; + licenseTermsId: bigint; +}; + /** * LicensingModuleLicenseTokensMintedEvent * @@ -9777,6 +10096,47 @@ export class LicensingModuleEventClient { this.rpcClient = rpcClient; } + /** + * event LicenseTermsAttached for contract LicensingModule + */ + public watchLicenseTermsAttachedEvent( + onLogs: (txHash: Hex, ev: Partial) => void, + ): WatchContractEventReturnType { + return this.rpcClient.watchContractEvent({ + abi: licensingModuleAbi, + address: this.address, + eventName: "LicenseTermsAttached", + onLogs: (evs) => { + evs.forEach((it) => onLogs(it.transactionHash, it.args)); + }, + }); + } + + /** + * parse tx receipt event LicenseTermsAttached for contract LicensingModule + */ + public parseTxLicenseTermsAttachedEvent( + txReceipt: TransactionReceipt, + ): Array { + const targetLogs: Array = []; + for (const log of txReceipt.logs) { + try { + const event = decodeEventLog({ + abi: licensingModuleAbi, + eventName: "LicenseTermsAttached", + data: log.data, + topics: log.topics, + }); + if (event.eventName === "LicenseTermsAttached") { + targetLogs.push(event.args); + } + } catch (e) { + /* empty */ + } + } + return targetLogs; + } + /** * event LicenseTokensMinted for contract LicensingModule */ diff --git a/packages/core-sdk/src/index.ts b/packages/core-sdk/src/index.ts index 5da4aedc..b9526e89 100644 --- a/packages/core-sdk/src/index.ts +++ b/packages/core-sdk/src/index.ts @@ -17,6 +17,12 @@ export type { RegisterDerivativeRequest, RegisterDerivativeWithLicenseTokensRequest, RegisterDerivativeWithLicenseTokensResponse, + CreateIpAssetWithPilTermsRequest, + CreateIpAssetWithPilTermsResponse, + RegisterIpAndMakeDerivativeRequest, + RegisterIpAndMakeDerivativeResponse, + RegisterIpAndAttachPilTermsRequest, + RegisterIpAndAttachPilTermsResponse, } from "./types/resources/ipAsset"; export type { @@ -28,6 +34,7 @@ export type { LicenseTermsIdResponse, MintLicenseTokensRequest, MintLicenseTokensResponse, + PIL_TYPE, } from "./types/resources/license"; export type { @@ -68,4 +75,7 @@ export type { CreateNFTCollectionResponse, } from "./types/resources/nftClient"; -export type { PiLicenseTemplateGetLicenseTermsResponse } from "./abi/generated"; +export type { + PiLicenseTemplateGetLicenseTermsResponse, + IpAccountImplStateResponse, +} from "./abi/generated"; diff --git a/packages/core-sdk/src/resources/dispute.ts b/packages/core-sdk/src/resources/dispute.ts index da9b4ccc..2cfd30fe 100644 --- a/packages/core-sdk/src/resources/dispute.ts +++ b/packages/core-sdk/src/resources/dispute.ts @@ -50,7 +50,7 @@ export class DisputeClient { const targetLogs = this.disputeModuleClient.parseTxDisputeRaisedEvent(txReceipt); return { txHash: txHash, - disputeId: BigInt(targetLogs[0].disputeId).toString() as `0x${string}`, + disputeId: targetLogs[0].disputeId, }; } return { txHash: txHash }; diff --git a/packages/core-sdk/src/resources/ipAccount.ts b/packages/core-sdk/src/resources/ipAccount.ts index ea56535a..fa285c82 100644 --- a/packages/core-sdk/src/resources/ipAccount.ts +++ b/packages/core-sdk/src/resources/ipAccount.ts @@ -7,8 +7,11 @@ import { IPAccountExecuteWithSigResponse, } from "../types/resources/ipAccount"; import { handleError } from "../utils/errors"; -import { parseToBigInt } from "../utils/utils"; -import { IpAccountImplClient, SimpleWalletClient } from "../abi/generated"; +import { + IpAccountImplClient, + IpAccountImplStateResponse, + SimpleWalletClient, +} from "../abi/generated"; export class IPAccountClient { private readonly wallet: SimpleWalletClient; @@ -37,7 +40,7 @@ export class IPAccountClient { const txHash = await ipAccountClient.execute({ to: request.to, - value: parseToBigInt(0), + value: BigInt(0), data: request.data, }); @@ -72,11 +75,10 @@ export class IPAccountClient { const txHash = await ipAccountClient.executeWithSig({ to: request.to, - value: parseToBigInt(0), + value: BigInt(0), data: request.data, signer: request.signer, - deadline: parseToBigInt(request.deadline), - // 712 signature + deadline: BigInt(request.deadline), signature: request.signature, }); @@ -88,4 +90,13 @@ export class IPAccountClient { handleError(error, "Failed to execute with signature for the IP Account transaction"); } } + + /** Returns the IPAccount's internal nonce for transaction ordering. + * @param ipId The derivative IP ID + * @returns The IPAccount's internal nonce for transaction ordering. + */ + public async getIpAccountNonce(ipId: string): Promise { + const ipAccount = new IpAccountImplClient(this.rpcClient, this.wallet, getAddress(ipId)); + return await ipAccount.state(); + } } diff --git a/packages/core-sdk/src/resources/ipAsset.ts b/packages/core-sdk/src/resources/ipAsset.ts index 16fdbbe9..8692a093 100644 --- a/packages/core-sdk/src/resources/ipAsset.ts +++ b/packages/core-sdk/src/resources/ipAsset.ts @@ -1,15 +1,19 @@ -import { Hex, PublicClient, getAddress, toHex, zeroAddress } from "viem"; +import { Hex, PublicClient, getAddress, zeroAddress, toHex, Address } from "viem"; import { chain } from "../utils/utils"; import { SupportedChainIds } from "../types/config"; import { handleError } from "../utils/errors"; import { CreateIpAssetWithPilTermsRequest, + CreateIpAssetWithPilTermsResponse, RegisterDerivativeRequest, RegisterDerivativeResponse, RegisterDerivativeWithLicenseTokensRequest, RegisterDerivativeWithLicenseTokensResponse, + RegisterIpAndAttachPilTermsRequest, + RegisterIpAndAttachPilTermsResponse, RegisterIpAndMakeDerivativeRequest, + RegisterIpAndMakeDerivativeResponse, RegisterIpResponse, RegisterRequest, } from "../types/resources/ipAsset"; @@ -23,10 +27,10 @@ import { SimpleWalletClient, SpgClient, SpgMintAndRegisterIpAndAttachPilTermsRequest, + SpgRegisterIpAndAttachPilTermsRequest, SpgRegisterIpAndMakeDerivativeRequest, } from "../abi/generated"; import { getLicenseTermByType } from "../utils/getLicenseTermsByType"; -import { PIL_TYPE } from "../types/resources/license"; export class IPAssetClient { public licensingModuleClient: LicensingModuleClient; @@ -56,7 +60,7 @@ export class IPAssetClient { /** * Registers an NFT as IP, creating a corresponding IP record. * @param request - The request object that contains all data needed to register IP. - * @param request.tokenContract The address of the NFT. + * @param request.nftContract The address of the NFT. * @param request.tokenId The token identifier of the NFT. * @param request.txOptions [Optional] The transaction options. * @returns A Promise that resolves to an object containing the transaction hash and optional IP ID if waitForTxn is set to true. @@ -65,14 +69,14 @@ export class IPAssetClient { public async register(request: RegisterRequest): Promise { try { const tokenId = BigInt(request.tokenId); - const ipId = await this.isNFTRegistered(request.tokenContract, tokenId); + const ipId = await this.isNftRegistered(request.nftContract, tokenId); if (ipId !== "0x") { return { ipId: ipId }; } const txHash = await this.ipAssetRegistryClient.register({ - tokenContract: getAddress(request.tokenContract), + tokenContract: getAddress(request.nftContract), tokenId, - chainid: BigInt(chain[this.chainId]), + chainid: chain[this.chainId], }); if (request.txOptions?.waitForTransaction) { const txReceipt = await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); @@ -169,9 +173,10 @@ export class IPAssetClient { if (!isChildIpIdRegistered) { throw new Error(`The child IP with id ${request.childIpId} is not registered.`); } + request.licenseTokenIds = request.licenseTokenIds.map((id) => BigInt(id)); for (const licenseTokenId of request.licenseTokenIds) { const tokenOwnerAddress = await this.licenseTokenReadOnlyClient.ownerOf({ - tokenId: BigInt(licenseTokenId), + tokenId: licenseTokenId, }); if (!tokenOwnerAddress) { throw new Error(`License token id ${licenseTokenId} must be owned by the caller.`); @@ -179,7 +184,7 @@ export class IPAssetClient { } const txHash = await this.licensingModuleClient.registerDerivativeWithLicenseTokens({ childIpId: getAddress(request.childIpId), - licenseTokenIds: request.licenseTokenIds.map((id) => BigInt(id)), + licenseTokenIds: request.licenseTokenIds, royaltyContext: zeroAddress, }); if (request.txOptions?.waitForTransaction) { @@ -207,30 +212,20 @@ export class IPAssetClient { * @param request.commercialRevShare [Optional] Percentage of revenue that must be shared with the licensor. * @param request.currency [Optional] The ERC20 token to be used to pay the minting fee. the token must be registered in story protocol. * @param request.txOptions [Optional] The transaction options. - * @returns A Promise that resolves to an object containing the transaction hash. + * @returns A Promise that resolves to an object containing the transaction hash and optional IP ID, Token ID, License Terms Id if waitForTxn is set to true. + * @emits IPRegistered (ipId, chainId, tokenContract, tokenId, name, uri, registrationDate) + * @emits LicenseTermsAttached (caller, ipId, licenseTemplate, licenseTermsId) */ - public async createIpAssetWithPilTerms(request: CreateIpAssetWithPilTermsRequest) { + public async createIpAssetWithPilTerms( + request: CreateIpAssetWithPilTermsRequest, + ): Promise { try { if (request.pilType === undefined || request.pilType === null) { throw new Error("PIL type is required."); } - if ( - request.pilType === PIL_TYPE.COMMERCIAL_USE && - (!request.mintingFee || !request.currency) - ) { - throw new Error("Minting fee and currency are required for commercial use PIL."); - } - if ( - request.pilType === PIL_TYPE.COMMERCIAL_REMIX && - (!request.mintingFee || !request.currency || !request.commercialRevShare) - ) { - throw new Error( - "Minting fee, currency and commercialRevShare are required for commercial remix PIL.", - ); - } const licenseTerm = getLicenseTermByType(request.pilType, { mintingFee: request.mintingFee, - currency: request.currency && getAddress(request.currency), + currency: request.currency, royaltyPolicyLAPAddress: this.royaltyPolicyLAPClient.address, commercialRevShare: request.commercialRevShare, }); @@ -248,9 +243,9 @@ export class IPAssetClient { }; if ( request.metadata && - !request.metadata.metadataURI && - !request.metadata.metadata && - !request.metadata.nftMetadata + request.metadata.metadataURI && + request.metadata.metadata && + request.metadata.nftMetadata ) { object.metadata = { metadataURI: request.metadata.metadataURI, @@ -259,11 +254,121 @@ export class IPAssetClient { }; } const txHash = await this.spgClient.mintAndRegisterIpAndAttachPilTerms(object); - return txHash; + if (request.txOptions?.waitForTransaction) { + const txReceipt = await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); + const iPRegisteredLog = this.ipAssetRegistryClient.parseTxIpRegisteredEvent(txReceipt)[0]; + const licenseTermsId = + this.licensingModuleClient.parseTxLicenseTermsAttachedEvent(txReceipt)[0].licenseTermsId; + return { + txHash: txHash, + ipId: iPRegisteredLog.ipId, + licenseTermsId, + tokenId: iPRegisteredLog.tokenId, + }; + } + return { txHash }; } catch (error) { handleError(error, "Failed to mint and register IP and attach PIL terms"); } } + /** + * Register a given NFT as an IP and attach Programmable IP License Terms.R. + * @param request - The request object that contains all data needed to mint and register ip. + * @param request.nftContract The address of the NFT collection. + * @param request.tokenId The ID of the NFT. + * @param request.pilType The type of the PIL. + * @param request.metadata - [Optional] The desired metadata for the newly registered IP. + * @param request.metadataURI The the metadata for the IP hash. + * @param request.metadata The metadata for the IP. + * @param request.nftMetadata The metadata for the IP NFT. + * @param request.sigMetadata - [Optional] The signature data for execution via IP Account. + * @param request.sigMetadata.signer The address of the signer for execution with signature. + * @param request.sigMetadata.deadline The deadline for the signature. + * @param request.sigMetadata.signature The signature for the execution via IP Account. + * @param request.sigAttach - The signature data for execution via IP Account. + * @param request.sigAttach.signer The address of the signer for execution with signature. + * @param request.sigAttach.deadline The deadline for the signature. + * @param request.sigAttach.signature The signature for the execution via IP Account. + * @param request.mintingFee [Optional] The fee to be paid when minting a license. + * @param request.commercialRevShare [Optional] Percentage of revenue that must be shared with the licensor. + * @param request.currency [Optional] The ERC20 token to be used to pay the minting fee. the token must be registered in story protocol. + * @param request.txOptions [Optional] The transaction options. + * @returns A Promise that resolves to an object containing the transaction hash and optional IP ID, License Terms Id if waitForTxn is set to true. + * @emits LicenseTermsAttached (caller, ipId, licenseTemplate, licenseTermsId) + */ + public async registerIpAndAttachPilTerms( + request: RegisterIpAndAttachPilTermsRequest, + ): Promise { + try { + if (request.pilType === undefined || request.pilType === null) { + throw new Error("PIL type is required."); + } + request.tokenId = BigInt(request.tokenId); + const ipId = await this.isNftRegistered(request.nftContract, request.tokenId); + if (ipId !== "0x") { + throw new Error(`The NFT with id ${request.tokenId} is already registered as IP.`); + } + const licenseTerm = getLicenseTermByType(request.pilType, { + mintingFee: request.mintingFee, + currency: request.currency, + royaltyPolicyLAPAddress: this.royaltyPolicyLAPClient.address, + commercialRevShare: request.commercialRevShare, + }); + const object: SpgRegisterIpAndAttachPilTermsRequest = { + nftContract: getAddress(request.nftContract), + tokenId: request.tokenId, + terms: licenseTerm, + metadata: { + metadataURI: "", + metadataHash: toHex("", { size: 32 }), + nftMetadataHash: toHex("", { size: 32 }), + }, + sigMetadata: { + signer: zeroAddress, + deadline: BigInt(0), + signature: zeroAddress, + }, + sigAttach: { + signer: getAddress(request.sigAttach.signer), + deadline: BigInt(request.sigAttach.deadline), + signature: request.sigAttach.signature, + }, + }; + if ( + request.metadata && + request.metadata.metadataURI && + request.metadata.metadata && + request.metadata.nftMetadata + ) { + object.metadata = { + metadataURI: request.metadata.metadataURI, + metadataHash: toHex(request.metadata.metadata, { size: 32 }), + nftMetadataHash: toHex(request.metadata.nftMetadata, { size: 32 }), + }; + } + if ( + request.sigMetadata && + request.sigMetadata.signature && + request.sigMetadata.signer && + request.sigMetadata.deadline + ) { + object.sigMetadata = { + signer: getAddress(request.sigMetadata.signer), + deadline: BigInt(request.sigMetadata.deadline), + signature: request.sigMetadata.signature, + }; + } + const txHash = await this.spgClient.registerIpAndAttachPilTerms(object); + if (request.txOptions?.waitForTransaction) { + const txReceipt = await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); + const log = this.licensingModuleClient.parseTxLicenseTermsAttachedEvent(txReceipt)[0]; + return { txHash, licenseTermsId: log.licenseTermsId, ipId: log.ipId }; + } + return { txHash }; + } catch (error) { + handleError(error, "Failed to register IP and attach PIL terms"); + } + } /** * Register the given NFT as a derivative IP with metadata without using license tokens. * @param request - The request object that contains all data needed to register derivative IP. @@ -277,19 +382,46 @@ export class IPAssetClient { * @param request.sigRegister.signer The address of the signer for execution with signature. * @param request.sigRegister.deadline The deadline for the signature. * @param request.sigRegister.signature The signature for the execution via IP Account. - * @param request.metadata [Optional] The desired metadata for the newly registered IP. + * @param request.metadata - [Optional] The desired metadata for the newly registered IP. * @param request.metadata.metadataURI The URI of the metadata for the IP. * @param request.metadata.metadata The metadata for the IP. * @param request.metadata.nftMetadata The the metadata for the IP NFT. - * @param request.sigMetadata [Optional] Signature data for setAll (metadata) for the IP via the Core Metadata Module. + * @param request.sigMetadata - [Optional] Signature data for setAll (metadata) for the IP via the Core Metadata Module. * @param request.sigMetadata.signer The address of the signer for execution with signature. * @param request.sigMetadata.deadline The deadline for the signature. * @param request.sigMetadata.signature The signature for the execution via IP Account. * @param request.txOptions [Optional] The transaction options. - * @returns A Promise that resolves to an object containing the transaction hash. + * @returns A Promise that resolves to an object containing the transaction hash and optional IP ID if waitForTxn is set to true. + * @emits IPRegistered (ipId, chainId, tokenContract, tokenId, name, uri, registrationDate) */ - private async registerDerivativeIp(request: RegisterIpAndMakeDerivativeRequest) { + public async registerDerivativeIp( + request: RegisterIpAndMakeDerivativeRequest, + ): Promise { try { + const tokenId = BigInt(request.tokenId); + const ipId = await this.isNftRegistered(request.nftContract, tokenId); + if (ipId !== "0x") { + throw new Error(`The NFT with id ${tokenId} is already registered as IP.`); + } + if (request.derivData.parentIpIds.length !== request.derivData.licenseTermsIds.length) { + throw new Error("Parent IP IDs and License terms IDs must be provided in pairs."); + } + for (let i = 0; i < request.derivData.parentIpIds.length; i++) { + const isAttachedLicenseTerms = + await this.licenseRegistryReadOnlyClient.hasIpAttachedLicenseTerms({ + ipId: getAddress(request.derivData.parentIpIds[i]), + licenseTemplate: + (request.derivData.licenseTemplate && + getAddress(request.derivData.licenseTemplate)) || + this.licenseTemplateClient.address, + licenseTermsId: BigInt(request.derivData.licenseTermsIds[i]), + }); + if (!isAttachedLicenseTerms) { + throw new Error( + `License terms id ${request.derivData.licenseTermsIds[i]} must be attached to the parent ipId ${request.derivData.parentIpIds[i]} before registering derivative.`, + ); + } + } const object: SpgRegisterIpAndMakeDerivativeRequest = { nftContract: getAddress(request.nftContract), tokenId: BigInt(request.tokenId), @@ -320,10 +452,10 @@ export class IPAssetClient { if ( request.sigMetadata && request.sigMetadata.signature && - request.sigMetadata.signature !== zeroAddress && + request.sigMetadata.signature.length > 0 && request.sigMetadata.signer && request.sigMetadata.signer !== zeroAddress && - request.sigMetadata.deadline + request.sigMetadata.deadline !== 0n ) { object.sigMetadata = { signer: getAddress(request.sigMetadata.signer), @@ -343,19 +475,37 @@ export class IPAssetClient { nftMetadataHash: toHex(request.metadata.nftMetadata, { size: 32 }), }; } - const txHash = await this.spgClient.registerIpAndMakeDerivative(object); - return txHash; + if (request.txOptions?.waitForTransaction) { + const receipt = await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); + const log = this.ipAssetRegistryClient.parseTxIpRegisteredEvent(receipt)[0]; + return { txHash, ipId: log.ipId }; + } + return { txHash }; } catch (error) { handleError(error, "Failed to register derivative IP"); } } - private async isNFTRegistered(tokenAddress: Hex, tokenId: bigint): Promise { + /** + * Gets the canonical IP identifier associated with an IP NFT. + * @param nftContract The address of the NFT collection. + * @param tokenId The token identifier of the IP. + * @returns The IP's canonical address identifier. + */ + public async getIpIdAddress( + nftContract: Address, + tokenId: bigint | string | number, + ): Promise
{ const ipId = await this.ipAssetRegistryClient.ipId({ - chainId: BigInt(chain[this.chainId]), - tokenContract: getAddress(tokenAddress), - tokenId: tokenId, + chainId: chain[this.chainId], + tokenContract: getAddress(nftContract), + tokenId: BigInt(tokenId), }); + return ipId; + } + + private async isNftRegistered(nftContract: Address, tokenId: bigint): Promise { + const ipId = await this.getIpIdAddress(nftContract, tokenId); const isRegistered = await this.ipAssetRegistryClient.isRegistered({ id: ipId }); return isRegistered ? ipId : "0x"; } diff --git a/packages/core-sdk/src/resources/license.ts b/packages/core-sdk/src/resources/license.ts index 76843397..798997b8 100644 --- a/packages/core-sdk/src/resources/license.ts +++ b/packages/core-sdk/src/resources/license.ts @@ -61,14 +61,14 @@ export class LicenseClient { try { const licenseTerms = getLicenseTermByType(PIL_TYPE.NON_COMMERCIAL_REMIX); const licenseTermsId = await this.getLicenseTermsId(licenseTerms); - if (licenseTermsId !== 0) { - return { licenseTermsId: licenseTermsId.toString() }; + if (licenseTermsId !== 0n) { + return { licenseTermsId: licenseTermsId }; } const txHash = await this.licenseTemplateClient.registerLicenseTerms({ terms: licenseTerms }); if (request?.txOptions?.waitForTransaction) { const txReceipt = await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); const targetLogs = this.licenseTemplateClient.parseTxLicenseTermsRegisteredEvent(txReceipt); - return { txHash: txHash, licenseTermsId: targetLogs[0].licenseTermsId.toString() }; + return { txHash: txHash, licenseTermsId: targetLogs[0].licenseTermsId }; } else { return { txHash: txHash }; } @@ -91,18 +91,18 @@ export class LicenseClient { try { const licenseTerms = getLicenseTermByType(PIL_TYPE.COMMERCIAL_USE, { mintingFee: request.mintingFee, - currency: request.currency && getAddress(request.currency), + currency: request.currency, royaltyPolicyLAPAddress: this.royaltyPolicyLAPClient.address, }); const licenseTermsId = await this.getLicenseTermsId(licenseTerms); - if (licenseTermsId !== 0) { - return { licenseTermsId: licenseTermsId.toString() }; + if (licenseTermsId !== 0n) { + return { licenseTermsId: licenseTermsId }; } const txHash = await this.licenseTemplateClient.registerLicenseTerms({ terms: licenseTerms }); if (request.txOptions?.waitForTransaction) { const txReceipt = await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); const targetLogs = this.licenseTemplateClient.parseTxLicenseTermsRegisteredEvent(txReceipt); - return { txHash: txHash, licenseTermsId: targetLogs[0].licenseTermsId.toString() }; + return { txHash: txHash, licenseTermsId: targetLogs[0].licenseTermsId }; } else { return { txHash: txHash }; } @@ -126,19 +126,19 @@ export class LicenseClient { try { const licenseTerms = getLicenseTermByType(PIL_TYPE.COMMERCIAL_REMIX, { mintingFee: request.mintingFee, - currency: request.currency && getAddress(request.currency), + currency: request.currency, royaltyPolicyLAPAddress: this.royaltyPolicyLAPClient.address, commercialRevShare: request.commercialRevShare, }); const licenseTermsId = await this.getLicenseTermsId(licenseTerms); - if (licenseTermsId !== 0) { - return { licenseTermsId: licenseTermsId.toString() }; + if (licenseTermsId !== 0n) { + return { licenseTermsId: licenseTermsId }; } const txHash = await this.licenseTemplateClient.registerLicenseTerms({ terms: licenseTerms }); if (request.txOptions?.waitForTransaction) { const txReceipt = await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); const targetLogs = this.licenseTemplateClient.parseTxLicenseTermsRegisteredEvent(txReceipt); - return { txHash: txHash, licenseTermsId: targetLogs[0].licenseTermsId.toString() }; + return { txHash: txHash, licenseTermsId: targetLogs[0].licenseTermsId }; } else { return { txHash: txHash }; } @@ -158,6 +158,7 @@ export class LicenseClient { */ public async attachLicenseTerms(request: AttachLicenseTermsRequest) { try { + request.licenseTermsId = BigInt(request.licenseTermsId); const isRegistered = await this.ipAssetRegistryClient.isRegistered({ id: getAddress(request.ipId), }); @@ -165,7 +166,7 @@ export class LicenseClient { throw new Error(`The IP with id ${request.ipId} is not registered.`); } const isExisted = await this.piLicenseTemplateReadOnlyClient.exists({ - licenseTermsId: BigInt(request.licenseTermsId), + licenseTermsId: request.licenseTermsId, }); if (!isExisted) { throw new Error(`License terms id ${request.licenseTermsId} do not exist.`); @@ -176,7 +177,7 @@ export class LicenseClient { licenseTemplate: (request.licenseTemplate && getAddress(request.licenseTemplate)) || this.licenseTemplateClient.address, - licenseTermsId: BigInt(request.licenseTermsId), + licenseTermsId: request.licenseTermsId, }); if (isAttachedLicenseTerms) { throw new Error( @@ -186,7 +187,7 @@ export class LicenseClient { const txHash = await this.licensingModuleClient.attachLicenseTerms({ ipId: request.ipId, licenseTemplate: request.licenseTemplate || this.licenseTemplateClient.address, - licenseTermsId: BigInt(request.licenseTermsId), + licenseTermsId: request.licenseTermsId, }); if (request.txOptions?.waitForTransaction) { await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); @@ -225,6 +226,7 @@ export class LicenseClient { request: MintLicenseTokensRequest, ): Promise { try { + request.licenseTermsId = BigInt(request.licenseTermsId); const isLicenseIpIdRegistered = await this.ipAssetRegistryClient.isRegistered({ id: getAddress(request.licensorIpId), }); @@ -232,7 +234,7 @@ export class LicenseClient { throw new Error(`The licensor IP with id ${request.licensorIpId} is not registered.`); } const isExisted = await this.piLicenseTemplateReadOnlyClient.exists({ - licenseTermsId: BigInt(request.licenseTermsId), + licenseTermsId: request.licenseTermsId, }); if (!isExisted) { throw new Error(`License terms id ${request.licenseTermsId} do not exist.`); @@ -243,7 +245,7 @@ export class LicenseClient { licenseTemplate: (request.licenseTemplate && getAddress(request.licenseTemplate)) || this.licenseTemplateClient.address, - licenseTermsId: BigInt(request.licenseTermsId), + licenseTermsId: request.licenseTermsId, }); if (!isAttachedLicenseTerms) { throw new Error( @@ -253,7 +255,7 @@ export class LicenseClient { const txHash = await this.licensingModuleClient.mintLicenseTokens({ licensorIpId: request.licensorIpId, licenseTemplate: request.licenseTemplate || this.licenseTemplateClient.address, - licenseTermsId: BigInt(request.licenseTermsId), + licenseTermsId: request.licenseTermsId, amount: BigInt(request.amount || 1), receiver: (request.receiver && getAddress(request.receiver)) || this.wallet.account!.address, @@ -265,7 +267,7 @@ export class LicenseClient { return { txHash: txHash, - licenseTokenId: targetLogs[0].startLicenseTokenId.toString(), + licenseTokenId: targetLogs[0].startLicenseTokenId, }; } else { return { txHash: txHash }; @@ -281,7 +283,7 @@ export class LicenseClient { * @returns A Promise that resolves to an object containing the PILTerms associate with the given ID. */ public async getLicenseTerms( - selectedLicenseTermsId: string, + selectedLicenseTermsId: string | number | bigint, ): Promise { try { return await this.piLicenseTemplateReadOnlyClient.getLicenseTerms({ @@ -294,6 +296,6 @@ export class LicenseClient { private async getLicenseTermsId(request: LicenseTerms): Promise { const licenseRes = await this.licenseTemplateClient.getLicenseTermsId({ terms: request }); - return Number(licenseRes.selectedLicenseTermsId); + return licenseRes.selectedLicenseTermsId; } } diff --git a/packages/core-sdk/src/resources/permission.ts b/packages/core-sdk/src/resources/permission.ts index 74a9e8a6..2f0c4f10 100644 --- a/packages/core-sdk/src/resources/permission.ts +++ b/packages/core-sdk/src/resources/permission.ts @@ -2,7 +2,6 @@ import { PublicClient, getAddress, Hex, encodeFunctionData } from "viem"; import { handleError } from "../utils/errors"; import { SetPermissionsRequest, SetPermissionsResponse } from "../types/resources/permission"; -import { parseToBigInt } from "../utils/utils"; import { accessControllerAbi, AccessControllerClient, @@ -50,7 +49,7 @@ export class PermissionClient { const txHash = await ipAccountClient.execute({ to: this.accessControllerClient.address, - value: parseToBigInt(0), + value: BigInt(0), data: encodeFunctionData({ abi: accessControllerAbi, functionName: "setPermission", diff --git a/packages/core-sdk/src/resources/royalty.ts b/packages/core-sdk/src/resources/royalty.ts index 68254dac..c9d4bef2 100644 --- a/packages/core-sdk/src/resources/royalty.ts +++ b/packages/core-sdk/src/resources/royalty.ts @@ -74,7 +74,7 @@ export class RoyaltyClient { const targetLogs = ipRoyaltyVault.parseTxRoyaltyTokensCollectedEvent(txReceipt); return { txHash: txHash, - royaltyTokensCollected: targetLogs[0].royaltyTokensCollected.toString(), + royaltyTokensCollected: targetLogs[0].royaltyTokensCollected, }; } else { return { txHash: txHash }; @@ -147,12 +147,11 @@ export class RoyaltyClient { this.wallet, proxyAddress, ); - const amount = await ipRoyaltyVault.claimableRevenue({ + return await ipRoyaltyVault.claimableRevenue({ account: getAddress(request.account), snapshotId: BigInt(request.snapshotId), token: getAddress(request.token), }); - return amount.toString(); } catch (error) { handleError(error, "Failed to calculate claimable revenue"); } @@ -177,6 +176,7 @@ export class RoyaltyClient { this.wallet, proxyAddress, ); + request.snapshotIds = request.snapshotIds.map((item) => BigInt(item)); let txHash: Hex; if (request.account) { const iPAccountExecuteResponse = await this.ipAccountClient.execute({ @@ -189,13 +189,13 @@ export class RoyaltyClient { data: encodeFunctionData({ abi: ipRoyaltyVaultImplAbi, functionName: "claimRevenueBySnapshotBatch", - args: [request.snapshotIds.map((item) => BigInt(item)), request.token], + args: [request.snapshotIds, request.token], }), }); txHash = iPAccountExecuteResponse.txHash as Hex; } else { txHash = await ipRoyaltyVault.claimRevenueBySnapshotBatch({ - snapshotIds: request.snapshotIds.map((item) => BigInt(item)), + snapshotIds: request.snapshotIds, token: getAddress(request.token), }); } @@ -204,7 +204,7 @@ export class RoyaltyClient { hash: txHash, }); const targetLogs = ipRoyaltyVault.parseTxRevenueTokenClaimedEvent(txReceipt); - return { txHash, claimableToken: targetLogs[0].amount.toString() }; + return { txHash, claimableToken: targetLogs[0].amount }; } else { return { txHash }; } @@ -232,7 +232,7 @@ export class RoyaltyClient { if (request.txOptions?.waitForTransaction) { const txReceipt = await this.rpcClient.waitForTransactionReceipt({ hash: txHash }); const targetLogs = ipRoyaltyVault.parseTxSnapshotCompletedEvent(txReceipt); - return { txHash, snapshotId: targetLogs[0].snapshotId.toString() }; + return { txHash, snapshotId: targetLogs[0].snapshotId }; } else { return { txHash }; } diff --git a/packages/core-sdk/src/types/resources/dispute.ts b/packages/core-sdk/src/types/resources/dispute.ts index 45129942..caaf7883 100644 --- a/packages/core-sdk/src/types/resources/dispute.ts +++ b/packages/core-sdk/src/types/resources/dispute.ts @@ -1,35 +1,35 @@ -import { Hex } from "viem"; +import { Address } from "viem"; import { TxOptions } from "../options"; export type Dispute = { - targetIpId: Hex; // The ipId that is the target of the dispute - disputeInitiator: Hex; // The address of the dispute initiator - arbitrationPolicy: Hex; // The address of the arbitration policy + targetIpId: Address; // The ipId that is the target of the dispute + disputeInitiator: Address; // The address of the dispute initiator + arbitrationPolicy: Address; // The address of the arbitration policy linkToDisputeEvidence: string; // The link of the dispute evidence targetTag: string; // The target tag of the dispute currentTag: string; // The current tag of the dispute }; export type RaiseDisputeRequest = { - targetIpId: Hex; - arbitrationPolicy: Hex; + targetIpId: Address; + arbitrationPolicy: Address; linkToDisputeEvidence: string; targetTag: string; - calldata?: Hex; + calldata?: Address; txOptions?: TxOptions; }; export type RaiseDisputeResponse = { txHash: string; - disputeId?: Hex; - arbitrationPolicy?: Hex; + disputeId?: bigint; + arbitrationPolicy?: Address; }; export type SetDisputeJudgementRequest = { disputeId: number; decision: boolean; - calldata?: Hex; + calldata?: Address; txOptions?: TxOptions; }; @@ -37,12 +37,12 @@ export type SetDisputeJudgementResponse = { txHash: string; disputeId?: bigint; decision?: boolean; - data?: Hex; + data?: Address; }; export type CancelDisputeRequest = { disputeId: number | string | bigint; - calldata?: Hex; + calldata?: Address; txOptions?: TxOptions; }; @@ -52,7 +52,7 @@ export type CancelDisputeResponse = { export type ResolveDisputeRequest = { disputeId: number | string | bigint; - data: Hex; + data: Address; txOptions?: TxOptions; }; diff --git a/packages/core-sdk/src/types/resources/ipAccount.ts b/packages/core-sdk/src/types/resources/ipAccount.ts index 844ffb74..f2ddabf8 100644 --- a/packages/core-sdk/src/types/resources/ipAccount.ts +++ b/packages/core-sdk/src/types/resources/ipAccount.ts @@ -1,12 +1,12 @@ -import { Hex } from "viem"; +import { Address } from "viem"; import { TxOptions } from "../options"; export type IPAccountExecuteRequest = { - accountAddress: Hex; - to: Hex; + accountAddress: Address; + to: Address; value: number; - data: Hex; + data: Address; txOptions?: TxOptions; }; @@ -15,13 +15,13 @@ export type IPAccountExecuteResponse = { }; export type IPAccountExecuteWithSigRequest = { - accountAddress: Hex; - to: Hex; + accountAddress: Address; + to: Address; value: number; - data: Hex; - signer: Hex; - deadline: number; - signature: Hex; + data: Address; + signer: Address; + deadline: number | bigint | string; + signature: Address; txOptions?: TxOptions; }; diff --git a/packages/core-sdk/src/types/resources/ipAsset.ts b/packages/core-sdk/src/types/resources/ipAsset.ts index aff9e0d6..4deeb82d 100644 --- a/packages/core-sdk/src/types/resources/ipAsset.ts +++ b/packages/core-sdk/src/types/resources/ipAsset.ts @@ -5,18 +5,18 @@ import { PIL_TYPE } from "./license"; export type RegisterIpResponse = { txHash?: string; - ipId?: Hex; + ipId?: Address; }; export type RegisterRequest = { - tokenContract: Hex; - tokenId: string; + nftContract: Address; + tokenId: string | number | bigint; txOptions?: TxOptions; }; export type RegisterDerivativeWithLicenseTokensRequest = { - childIpId: Hex; - licenseTokenIds: string[]; + childIpId: Address; + licenseTokenIds: string[] | bigint[] | number[]; txOptions?: TxOptions; }; @@ -25,16 +25,16 @@ export type RegisterDerivativeWithLicenseTokensResponse = { }; export type RegisterDerivativeRequest = { - childIpId: Hex; - parentIpIds: Hex[]; - licenseTermsIds: string[]; - licenseTemplate?: Hex; + childIpId: Address; + parentIpIds: Address[]; + licenseTermsIds: string[] | bigint[] | number[]; + licenseTemplate?: Address; txOptions?: TxOptions; }; export type RegisterDerivativeResponse = { txHash?: string; - childIpId?: Hex; + childIpId?: Address; }; export type CreateIpAssetWithPilTermsRequest = { @@ -45,19 +45,26 @@ export type CreateIpAssetWithPilTermsRequest = { metadata: string; nftMetadata: string; }; - recipient?: Hex; + recipient?: Address; mintingFee?: string; - currency?: Hex; + currency?: Address; commercialRevShare?: number; txOptions?: TxOptions; }; +export type CreateIpAssetWithPilTermsResponse = { + txHash: string; + ipId?: Address; + tokenId?: bigint; + licenseTermsId?: bigint; +}; + export type RegisterIpAndMakeDerivativeRequest = { nftContract: Address; - tokenId: string; + tokenId: string | number | bigint; derivData: { parentIpIds: Address[]; - licenseTermsIds: string[]; + licenseTermsIds: string[] | bigint[] | number[]; licenseTemplate?: Address; }; metadata?: { @@ -67,12 +74,49 @@ export type RegisterIpAndMakeDerivativeRequest = { }; sigMetadata?: { signer: Address; - deadline: string; + deadline: string | number | bigint; signature: Hex; }; sigRegister: { signer: Address; - deadline: string; + deadline: string | number | bigint; + signature: Hex; + }; + txOptions?: TxOptions; +}; + +export type RegisterIpAndMakeDerivativeResponse = { + txHash: string; + ipId?: Address; +}; + +export type RegisterIpAndAttachPilTermsRequest = { + nftContract: Address; + tokenId: bigint | string | number; + metadata: { + metadataURI: string; + metadata: string; + nftMetadata: string; + }; + pilType: PIL_TYPE; + sigMetadata: { + signer: Address; + deadline: bigint | number | string; + signature: Hex; + }; + sigAttach: { + signer: Address; + deadline: bigint | number | string; signature: Hex; }; + mintingFee?: string; + currency?: Address; + commercialRevShare?: number; + txOptions?: TxOptions; +}; + +export type RegisterIpAndAttachPilTermsResponse = { + txHash: string; + ipId?: Address; + licenseTermsId?: bigint; }; diff --git a/packages/core-sdk/src/types/resources/license.ts b/packages/core-sdk/src/types/resources/license.ts index 14ea7781..57be7346 100644 --- a/packages/core-sdk/src/types/resources/license.ts +++ b/packages/core-sdk/src/types/resources/license.ts @@ -1,4 +1,4 @@ -import { Hex } from "viem"; +import { Address } from "viem"; import { TxOptions } from "../options"; @@ -9,7 +9,7 @@ export type LicenseApiResponse = { export type License = { id: string; policyId: string; - licensorIpId: Hex; + licensorIpId: Address; }; export type RegisterNonComSocialRemixingPILRequest = { @@ -21,58 +21,58 @@ export type LicenseTerms = { expiration: bigint; commercialRevCelling: bigint; derivativeRevCelling: bigint; - commercializerCheckerData: Hex; + commercializerCheckerData: Address; transferable: boolean; - royaltyPolicy: Hex; + royaltyPolicy: Address; commercialUse: boolean; commercialAttribution: boolean; - commercializerChecker: Hex; + commercializerChecker: Address; commercialRevShare: number; derivativesAllowed: boolean; derivativesAttribution: boolean; derivativesApproval: boolean; derivativesReciprocal: boolean; - currency: Hex; + currency: Address; uri: string; }; -export type LicenseTermsIdResponse = number; +export type LicenseTermsIdResponse = bigint; export type RegisterPILResponse = { - licenseTermsId?: string; + licenseTermsId?: bigint; txHash?: string; }; export type RegisterCommercialUsePILRequest = { - mintingFee: string; - currency: Hex; + mintingFee: string | number | bigint; + currency: Address; txOptions?: TxOptions; }; export type RegisterCommercialRemixPILRequest = { mintingFee: string; commercialRevShare: number; - currency: Hex; + currency: Address; txOptions?: TxOptions; }; export type AttachLicenseTermsRequest = { - ipId: Hex; - licenseTermsId: string; - licenseTemplate?: Hex; + ipId: Address; + licenseTermsId: string | number | bigint; + licenseTemplate?: Address; txOptions?: TxOptions; }; export type MintLicenseTokensRequest = { - licensorIpId: Hex; - licenseTermsId: string; - licenseTemplate?: Hex; - amount?: number; - receiver?: Hex; + licensorIpId: Address; + licenseTermsId: string | number | bigint; + licenseTemplate?: Address; + amount?: number | string | bigint; + receiver?: Address; txOptions?: TxOptions; }; export type MintLicenseTokensResponse = { - licenseTokenId?: string; + licenseTokenId?: bigint; txHash?: string; }; diff --git a/packages/core-sdk/src/types/resources/permission.ts b/packages/core-sdk/src/types/resources/permission.ts index 4f929997..4e7e3364 100644 --- a/packages/core-sdk/src/types/resources/permission.ts +++ b/packages/core-sdk/src/types/resources/permission.ts @@ -1,9 +1,11 @@ +import { Address } from "viem"; + import { TxOptions } from "../options"; export type SetPermissionsRequest = { - ipId: `0x${string}`; - signer: `0x${string}`; - to: `0x${string}`; + ipId: Address; + signer: Address; + to: Address; func?: string; permission: number; txOptions?: TxOptions; diff --git a/packages/core-sdk/src/types/resources/royalty.ts b/packages/core-sdk/src/types/resources/royalty.ts index 29233638..248347f5 100644 --- a/packages/core-sdk/src/types/resources/royalty.ts +++ b/packages/core-sdk/src/types/resources/royalty.ts @@ -1,4 +1,4 @@ -import { Hex } from "viem"; +import { Address } from "viem"; import { TxOptions } from "../options"; @@ -7,7 +7,7 @@ export type RoyaltyPolicyApiResponse = { }; export type RoyaltyPolicy = { - id: `0x${string}`; // ipId + id: Address; // ipId targetAncestors: string[]; targetRoyaltyAmount: string[]; }; @@ -22,38 +22,38 @@ export type RoyaltyContext = { }; export type CollectRoyaltyTokensRequest = { - parentIpId: Hex; - royaltyVaultIpId: Hex; + parentIpId: Address; + royaltyVaultIpId: Address; txOptions?: TxOptions; }; export type CollectRoyaltyTokensResponse = { txHash: string; - royaltyTokensCollected?: string; + royaltyTokensCollected?: bigint; }; export type RoyaltyData = [ isUnlinkableToParents: boolean, - ipRoyaltyVault: Hex, + ipRoyaltyVault: Address, royaltyStack: bigint, - ancestorsAddresses: Hex, + ancestorsAddresses: Address, ancestorsRoyalties: bigint[], ]; export type ClaimableRevenueRequest = { - royaltyVaultIpId: Hex; - account: Hex; - snapshotId: string; - token: Hex; + royaltyVaultIpId: Address; + account: Address; + snapshotId: string | number | bigint; + token: Address; }; -export type ClaimableRevenueResponse = string; +export type ClaimableRevenueResponse = bigint; export type PayRoyaltyOnBehalfRequest = { - receiverIpId: Hex; - payerIpId: Hex; - token: Hex; - amount: string; + receiverIpId: Address; + payerIpId: Address; + token: Address; + amount: string | number | bigint; txOptions?: TxOptions; }; @@ -62,26 +62,26 @@ export type PayRoyaltyOnBehalfResponse = { }; export type SnapshotRequest = { - royaltyVaultIpId: Hex; + royaltyVaultIpId: Address; txOptions?: TxOptions; }; export type ClaimRevenueRequest = { - snapshotIds: string[]; - token: Hex; - royaltyVaultIpId: Hex; - account?: Hex; + snapshotIds: string[] | number[] | bigint[]; + token: Address; + royaltyVaultIpId: Address; + account?: Address; txOptions?: TxOptions; }; export type ClaimRevenueResponse = { txHash: string; - claimableToken?: string; + claimableToken?: bigint; }; export type SnapshotResponse = { txHash: string; - snapshotId?: string; + snapshotId?: bigint; }; -export type RoyaltyVaultAddress = Hex; +export type RoyaltyVaultAddress = Address; diff --git a/packages/core-sdk/src/types/resources/tagging.ts b/packages/core-sdk/src/types/resources/tagging.ts index 1241b270..e5b7a5f9 100644 --- a/packages/core-sdk/src/types/resources/tagging.ts +++ b/packages/core-sdk/src/types/resources/tagging.ts @@ -1,14 +1,16 @@ +import { Address } from "viem"; + import { TxOptions } from "../options"; export type Tag = { id: string; - ipId: `0x${string}`; + ipId: Address; tag: string; }; export type SetTagRequest = { tag: string; - ipId: `0x${string}`; + ipId: Address; txOptions?: TxOptions; }; @@ -18,7 +20,7 @@ export type SetTagResponse = { export type RemoveTagRequest = { tag: string; - ipId: `0x${string}`; + ipId: Address; txOptions?: TxOptions; }; diff --git a/packages/core-sdk/src/utils/getLicenseTermsByType.ts b/packages/core-sdk/src/utils/getLicenseTermsByType.ts index 74d35e06..7dc50b90 100644 --- a/packages/core-sdk/src/utils/getLicenseTermsByType.ts +++ b/packages/core-sdk/src/utils/getLicenseTermsByType.ts @@ -5,7 +5,7 @@ import { PIL_TYPE, LicenseTerms } from "../types/resources/license"; export function getLicenseTermByType( type: PIL_TYPE, term?: { - mintingFee?: string; + mintingFee?: string | number | bigint; currency?: Hex; royaltyPolicyLAPAddress: Hex; commercialRevShare?: number; diff --git a/packages/core-sdk/src/utils/utils.ts b/packages/core-sdk/src/utils/utils.ts index 52c67cd5..97eaa0f9 100644 --- a/packages/core-sdk/src/utils/utils.ts +++ b/packages/core-sdk/src/utils/utils.ts @@ -20,10 +20,6 @@ export function isIntegerString(s: string): boolean { return !isNaN(num) && parseInt(s, 10) === num; } -export function parseToBigInt(num: string | number): bigint { - return BigInt(num); -} - export async function waitTxAndFilterLog< const TAbi extends Abi | readonly unknown[], TEventName extends ContractEventName | undefined = ContractEventName, @@ -154,7 +150,7 @@ export function chainStringToViemChain(chainId: SupportedChainIds): Chain { } } -export const chain: { [key in SupportedChainIds]: string } = { - sepolia: "11155111", - 11155111: "11155111", +export const chain: { [key in SupportedChainIds]: bigint } = { + sepolia: 11155111n, + 11155111: 11155111n, }; diff --git a/packages/core-sdk/test/integration/dispute.test.ts b/packages/core-sdk/test/integration/dispute.test.ts index 158fba58..1f0db0f0 100644 --- a/packages/core-sdk/test/integration/dispute.test.ts +++ b/packages/core-sdk/test/integration/dispute.test.ts @@ -5,7 +5,7 @@ import { RaiseDisputeRequest, ResolveDisputeRequest, } from "../../src/types/resources/dispute"; -import { MockERC721, getStoryClientInSepolia, getTokenId } from "./util"; +import { MockERC721, getStoryClientInSepolia, getTokenId } from "./utils/util"; import chaiAsPromised from "chai-as-promised"; chai.use(chaiAsPromised); const expect = chai.expect; @@ -21,7 +21,7 @@ describe.skip("Dispute Functions", () => { it("raise a dispute", async () => { const tokenId = await getTokenId(); const registerResult = await client.ipAsset.register({ - tokenContract: MockERC721, + nftContract: MockERC721, tokenId: tokenId!, txOptions: { waitForTransaction: true, diff --git a/packages/core-sdk/test/integration/ipAccount.test.ts b/packages/core-sdk/test/integration/ipAccount.test.ts index 3328c11d..b6985bab 100644 --- a/packages/core-sdk/test/integration/ipAccount.test.ts +++ b/packages/core-sdk/test/integration/ipAccount.test.ts @@ -1,24 +1,27 @@ import chai from "chai"; import chaiAsPromised from "chai-as-promised"; import { StoryClient } from "../../src"; -import { MockERC721, getStoryClientInSepolia, getTokenId } from "./util"; -import { Hex, encodeFunctionData, getAddress, zeroAddress } from "viem"; +import { MockERC721, getBlockTimestamp, getStoryClientInSepolia, getTokenId } from "./utils/util"; +import { Hex, PublicClient, createPublicClient, encodeFunctionData, getAddress, http } from "viem"; import { accessControllerAbi, accessControllerAddress } from "../../src/abi/generated"; import { privateKeyToAccount } from "viem/accounts"; +import { chainStringToViemChain } from "../../src/utils/utils"; chai.use(chaiAsPromised); const expect = chai.expect; -const sepoliaChainId = BigInt(11155111); +const sepoliaChainId = 11155111; describe("Ip Account functions", () => { let client: StoryClient; let ipId: Hex; let data: Hex; + let publicClient: PublicClient; + const permissionAddress = accessControllerAddress[sepoliaChainId]; before(async function () { client = getStoryClientInSepolia(); const tokenId = await getTokenId(); const registerResult = await client.ipAsset.register({ - tokenContract: MockERC721, + nftContract: MockERC721, tokenId: tokenId!, txOptions: { waitForTransaction: true, @@ -36,72 +39,66 @@ describe("Ip Account functions", () => { 1, ], }); + publicClient = await createPublicClient({ + chain: chainStringToViemChain("sepolia"), + transport: http(process.env.SEPOLIA_RPC_PROVIDER_URL), + }); }); - describe("Execute ipAccount", async function () { - it("should not throw error when execute", async () => { - const response = await client.ipAccount.execute({ - to: accessControllerAddress[11155111], - value: 0, - data, - accountAddress: ipId, - }); - expect(response.txHash).to.be.a("string").and.not.empty; + it("should not throw error when execute", async () => { + const response = await client.ipAccount.execute({ + to: permissionAddress, + value: 0, + data, + accountAddress: ipId, }); + expect(response.txHash).to.be.a("string").and.not.empty; }); - describe.skip("Execute with sig", async function () { - // collect signature and help other execute method - it("should not throw error when executeWithSig setting permission", async () => { - const account = privateKeyToAccount(process.env.SEPOLIA_TEST_WALLET_PRIVATE_KEY as Hex); - - const signature = await account.signTypedData({ - types: { - EIP712Domain: [ - { name: "name", type: "string" }, - { name: "chainId", type: "uint256" }, - { name: "verifyingContract", type: "address" }, - ], - ExecuteWithSig: [ - { name: "accountAddress", type: "address" }, - { name: "value", type: "uint256" }, - { name: "to", type: "address" }, - { name: "data", type: "bytes" }, - { name: "deadline", type: "uint256" }, - ], - }, - primaryType: "ExecuteWithSig", - domain: { - name: "sepolia", - chainId: sepoliaChainId, - verifyingContract: client.ipAsset.ipAssetRegistryClient.address, - }, - message: { - accountAddress: ipId, - value: BigInt(0), - to: client.ipAsset.ipAssetRegistryClient.address, - data: data, - deadline: BigInt(111), - }, - }); - const waitForTransaction: boolean = true; - const response = await expect( - client.ipAccount.executeWithSig({ - accountAddress: ipId, - value: 0, - to: client.ipAsset.ipAssetRegistryClient.address, - data: data, - deadline: 111, - signer: process.env.SEPOLIA_TEST_WALLET_ADDRESS as Hex, - signature: signature, - txOptions: { - waitForTransaction: waitForTransaction, - }, - }), - ).to.not.be.rejected; - - expect(response.txHash).to.be.a("string"); - expect(response.txHash).not.empty; + it.skip("should not throw error when executeWithSig setting permission", async () => { + const account = privateKeyToAccount(process.env.SEPOLIA_WALLET_PRIVATE_KEY as Hex); + const deadline = (await getBlockTimestamp()) + 100n; + const state = await client.ipAccount.getIpAccountNonce(ipId); + const expectedState = state + 1n; + const signature = await account.signTypedData({ + domain: { + name: "Story Protocol IP Account", + version: "1", + chainId: sepoliaChainId, + verifyingContract: ipId, + }, + types: { + Execute: [ + { name: "to", type: "address" }, + { name: "value", type: "uint256" }, + { name: "data", type: "bytes" }, + { name: "nonce", type: "uint256" }, + { name: "deadline", type: "uint256" }, + ], + }, + primaryType: "Execute", + message: { + to: permissionAddress, + value: BigInt(0), + data: data, + nonce: expectedState, + deadline: BigInt(deadline), + }, }); + const response = await client.ipAccount.executeWithSig({ + accountAddress: ipId, + value: 0, + to: permissionAddress, + data: data, + deadline: deadline, + signer: process.env.SEPOLIA_TEST_WALLET_ADDRESS as Hex, + signature: signature, + txOptions: { + waitForTransaction: true, + }, + }); + + expect(response.txHash).to.be.a("string"); + expect(response.txHash).not.empty; }); }); diff --git a/packages/core-sdk/test/integration/ipAsset.test.ts b/packages/core-sdk/test/integration/ipAsset.test.ts index 372d82f3..16e1b208 100644 --- a/packages/core-sdk/test/integration/ipAsset.test.ts +++ b/packages/core-sdk/test/integration/ipAsset.test.ts @@ -1,36 +1,46 @@ import chai from "chai"; -import chaiAsPromised from "chai-as-promised"; -import { Hex } from "viem"; - import { StoryClient } from "../../src"; +import { Hex, encodeFunctionData, getAddress, toFunctionSelector, Address } from "viem"; +import chaiAsPromised from "chai-as-promised"; +import { MockERC721, getBlockTimestamp, getStoryClientInSepolia, getTokenId } from "./utils/util"; import { PIL_TYPE } from "../../src/types/resources/license"; -import { MockERC721, getStoryClientInSepolia, getTokenId } from "./util"; +import { MockERC20 } from "./utils/mockERC20"; +import { privateKeyToAccount } from "viem/accounts"; +import { + accessControllerAbi, + accessControllerAddress, + licensingModuleAddress, + spgAddress, +} from "../../src/abi/generated"; +const sepoliaChainId = 11155111; chai.use(chaiAsPromised); const expect = chai.expect; -let parentIpId: Hex; -let childIpId: Hex; -let noCommercialLicenseTermsId: string; describe("IP Asset Functions ", () => { let client: StoryClient; before(async function () { client = getStoryClientInSepolia(); - const registerResult = await client.license.registerNonComSocialRemixingPIL({ - txOptions: { - waitForTransaction: true, - }, - }); - noCommercialLicenseTermsId = registerResult.licenseTermsId!; }); describe("Create IP Asset", async function () { + let parentIpId: Hex; + let childIpId: Hex; + let noCommercialLicenseTermsId: bigint; + before(async () => { + const registerResult = await client.license.registerNonComSocialRemixingPIL({ + txOptions: { + waitForTransaction: true, + }, + }); + noCommercialLicenseTermsId = registerResult.licenseTermsId!; + }); it("should not throw error when registering a IP Asset", async () => { const tokenId = await getTokenId(); const waitForTransaction: boolean = true; const response = await expect( client.ipAsset.register({ - tokenContract: MockERC721, + nftContract: MockERC721, tokenId: tokenId!, txOptions: { waitForTransaction: waitForTransaction, @@ -47,7 +57,7 @@ describe("IP Asset Functions ", () => { const tokenId = await getTokenId(); parentIpId = ( await client.ipAsset.register({ - tokenContract: MockERC721, + nftContract: MockERC721, tokenId: tokenId!, txOptions: { waitForTransaction: true, @@ -78,7 +88,7 @@ describe("IP Asset Functions ", () => { const tokenId = await getTokenId(); const ipId = ( await client.ipAsset.register({ - tokenContract: MockERC721, + nftContract: MockERC721, tokenId: tokenId!, txOptions: { waitForTransaction: true, @@ -107,6 +117,11 @@ describe("IP Asset Functions ", () => { describe("NFT Client (SPG)", () => { let nftContract: Hex; + const permissionAddress = accessControllerAddress[sepoliaChainId]; + const spContractAddress = spgAddress[sepoliaChainId]; + const licensingContractModuleAddress = licensingModuleAddress[sepoliaChainId]; + const coreMetadataModuleAddress = "0xDa498A3f7c8a88cb72201138C366bE3778dB9575"; + const account = privateKeyToAccount(process.env.SEPOLIA_WALLET_PRIVATE_KEY as Address); before(async () => { // Create a NFT collection for this test-suite @@ -119,14 +134,13 @@ describe("IP Asset Functions ", () => { waitForTransaction: true, }, }); - expect(txData.nftContract).to.be.a("string").and.not.empty; nftContract = txData.nftContract; }); describe("should not throw error when mint and register ip and attach pil terms", async () => { it("Non-Commercial Remix", async () => { - const txHash = await client.ipAsset.createIpAssetWithPilTerms({ + const result = await client.ipAsset.createIpAssetWithPilTerms({ nftContract, pilType: PIL_TYPE.NON_COMMERCIAL_REMIX, metadata: { @@ -135,40 +149,272 @@ describe("IP Asset Functions ", () => { nftMetadata: "test-nft-metadata-hash", }, }); - expect(txHash).to.be.a("string").and.not.empty; + expect(result.txHash).to.be.a("string").and.not.empty; }); it("Commercial Use", async () => { - const txHash = await client.ipAsset.createIpAssetWithPilTerms({ + const result = await client.ipAsset.createIpAssetWithPilTerms({ nftContract, pilType: PIL_TYPE.COMMERCIAL_USE, commercialRevShare: 10, mintingFee: "100", - currency: "0xB132A6B7AE652c974EE1557A3521D53d18F6739f", + currency: MockERC20.address, metadata: { metadataURI: "test-uri", metadata: "test-metadata-hash", nftMetadata: "test-nft-metadata-hash", }, }); - expect(txHash).to.be.a("string").and.not.empty; + expect(result.txHash).to.be.a("string").and.not.empty; }); it("Commercial Remix", async () => { - const txHash = await client.ipAsset.createIpAssetWithPilTerms({ + const result = await client.ipAsset.createIpAssetWithPilTerms({ + nftContract, + pilType: PIL_TYPE.COMMERCIAL_REMIX, + commercialRevShare: 10, + mintingFee: "100", + currency: MockERC20.address, + metadata: { + metadataURI: "test-uri", + metadata: "test-metadata-hash", + nftMetadata: "test-nft-metadata-hash", + }, + }); + expect(result.txHash).to.be.a("string").and.not.empty; + }); + it("should get the related log when createIpAssetWithPilTerms given waitForTransaction is true ", async () => { + const result = await client.ipAsset.createIpAssetWithPilTerms({ nftContract, pilType: PIL_TYPE.COMMERCIAL_REMIX, commercialRevShare: 10, mintingFee: "100", - currency: "0xB132A6B7AE652c974EE1557A3521D53d18F6739f", + currency: MockERC20.address, metadata: { metadataURI: "test-uri", metadata: "test-metadata-hash", nftMetadata: "test-nft-metadata-hash", }, + txOptions: { + waitForTransaction: true, + }, }); - expect(txHash).to.be.a("string").and.not.empty; + expect(result.txHash).to.be.a("string").and.not.empty; + expect(result.ipId).to.be.a("string").and.not.empty; + expect(result.tokenId).to.be.a("bigint"); + expect(result.licenseTermsId).to.be.a("bigint"); + }); + }); + + it("should not throw error when register registerDerivativeIp", async () => { + const tokenChildId = await getTokenId(nftContract); + const { ipId: parentIpId, licenseTermsId } = await client.ipAsset.createIpAssetWithPilTerms({ + nftContract, + pilType: PIL_TYPE.NON_COMMERCIAL_REMIX, + commercialRevShare: 10, + mintingFee: "100", + currency: MockERC20.address, + metadata: { + metadataURI: "test-uri", + metadata: "test-metadata-hash", + nftMetadata: "test-nft-metadata-hash", + }, + txOptions: { + waitForTransaction: true, + }, + }); + const childIpId = await client.ipAsset.getIpIdAddress(nftContract, tokenChildId!); + const deadline = (await getBlockTimestamp()) + 1000n; + const sigMetadata = await account.signTypedData({ + domain: { + name: "Story Protocol IP Account", + version: "1", + chainId: sepoliaChainId, + verifyingContract: childIpId, + }, + types: { + Execute: [ + { name: "to", type: "address" }, + { name: "value", type: "uint256" }, + { name: "data", type: "bytes" }, + { name: "nonce", type: "uint256" }, + { name: "deadline", type: "uint256" }, + ], + }, + primaryType: "Execute", + message: { + to: permissionAddress, + value: BigInt(0), + data: encodeFunctionData({ + abi: accessControllerAbi, + functionName: "setPermission", + args: [ + getAddress(childIpId), + getAddress(spContractAddress), + getAddress(coreMetadataModuleAddress), + toFunctionSelector("function setAll(address,string,bytes32,bytes32)"), + 1, + ], + }), + nonce: 1n, + deadline, + }, + }); + const sigRegister = await account.signTypedData({ + domain: { + name: "Story Protocol IP Account", + version: "1", + chainId: sepoliaChainId, + verifyingContract: childIpId, + }, + types: { + Execute: [ + { name: "to", type: "address" }, + { name: "value", type: "uint256" }, + { name: "data", type: "bytes" }, + { name: "nonce", type: "uint256" }, + { name: "deadline", type: "uint256" }, + ], + }, + primaryType: "Execute", + message: { + to: permissionAddress, + value: BigInt(0), + data: encodeFunctionData({ + abi: accessControllerAbi, + functionName: "setPermission", + args: [ + getAddress(childIpId), + getAddress(spContractAddress), + getAddress(licensingContractModuleAddress), + toFunctionSelector( + "function registerDerivative(address,address[],uint256[],address,bytes)", + ), + 1, + ], + }), + nonce: 2n, + deadline, + }, + }); + const result = await client.ipAsset.registerDerivativeIp({ + nftContract: nftContract, + tokenId: tokenChildId!, + derivData: { + parentIpIds: [parentIpId!], + licenseTermsIds: [licenseTermsId!], + }, + metadata: { + metadataURI: "test-uri", + metadata: "test-metadata-hash", + nftMetadata: "test-nft-metadata-hash", + }, + sigMetadata: { + signer: process.env.SEPOLIA_TEST_WALLET_ADDRESS as Hex, + deadline: deadline, + signature: sigMetadata, + }, + sigRegister: { + signer: process.env.SEPOLIA_TEST_WALLET_ADDRESS as Hex, + deadline: deadline, + signature: sigRegister, + }, + txOptions: { + waitForTransaction: true, + }, + }); + expect(result.txHash).to.be.a("string").and.not.empty; + expect(result.ipId).to.be.a("string").and.not.empty; + }); + + it("should not throw error when register registerIpAndAttachPilTerms", async () => { + const getPermissionSignatureForSpg = async (params: { + ipId: Address; + moduleAddress: Address; + deadline: bigint; + nonce: bigint; + selectorHash: Hex; + }) => { + const { ipId, moduleAddress, deadline, nonce, selectorHash } = params; + return await account.signTypedData({ + domain: { + name: "Story Protocol IP Account", + version: "1", + chainId: sepoliaChainId, + verifyingContract: ipId, + }, + types: { + Execute: [ + { name: "to", type: "address" }, + { name: "value", type: "uint256" }, + { name: "data", type: "bytes" }, + { name: "nonce", type: "uint256" }, + { name: "deadline", type: "uint256" }, + ], + }, + primaryType: "Execute", + message: { + to: permissionAddress, + value: BigInt(0), + data: encodeFunctionData({ + abi: accessControllerAbi, + functionName: "setPermission", + args: [ + getAddress(ipId), + getAddress(spContractAddress), + getAddress(moduleAddress), + selectorHash, + 1, + ], + }), + nonce, + deadline, + }, + }); + }; + const tokenId = await getTokenId(nftContract); + const ipId = await client.ipAsset.getIpIdAddress(nftContract, tokenId!); + const deadline = (await getBlockTimestamp()) + 1000n; + const sigMetadata = await getPermissionSignatureForSpg({ + ipId, + moduleAddress: coreMetadataModuleAddress, + deadline, + nonce: 1n, + selectorHash: toFunctionSelector("function setAll(address,string,bytes32,bytes32)"), + }); + const sigAttach = await getPermissionSignatureForSpg({ + ipId, + moduleAddress: licensingModuleAddress[sepoliaChainId], + deadline, + nonce: 2n, + selectorHash: toFunctionSelector("function attachLicenseTerms(address,address,uint256)"), + }); + const result = await client.ipAsset.registerIpAndAttachPilTerms({ + nftContract: nftContract, + tokenId: tokenId!, + metadata: { + metadataURI: "test-uri", + metadata: "test-metadata-hash", + nftMetadata: "test-nft-metadata-hash", + }, + sigMetadata: { + signer: process.env.SEPOLIA_TEST_WALLET_ADDRESS as Address, + deadline, + signature: sigMetadata, + }, + sigAttach: { + signer: process.env.SEPOLIA_TEST_WALLET_ADDRESS as Address, + deadline, + signature: sigAttach, + }, + pilType: PIL_TYPE.NON_COMMERCIAL_REMIX, + txOptions: { + waitForTransaction: true, + }, }); + expect(result.txHash).to.be.a("string").and.not.empty; + expect(result.ipId).to.be.a("string").and.not.empty; + expect(result.licenseTermsId).to.be.a("bigint"); }); }); }); diff --git a/packages/core-sdk/test/integration/license.test.ts b/packages/core-sdk/test/integration/license.test.ts index 21ea640c..f5f4661c 100644 --- a/packages/core-sdk/test/integration/license.test.ts +++ b/packages/core-sdk/test/integration/license.test.ts @@ -2,7 +2,8 @@ import chai from "chai"; import { StoryClient } from "../../src"; import { Hex } from "viem"; import chaiAsPromised from "chai-as-promised"; -import { MockERC20, MockERC721, getStoryClientInSepolia, getTokenId } from "./util"; +import { MockERC721, getStoryClientInSepolia, getTokenId } from "./utils/util"; +import { MockERC20 } from "./utils/mockERC20"; chai.use(chaiAsPromised); const expect = chai.expect; @@ -20,41 +21,41 @@ describe("License Functions", () => { waitForTransaction: true, }, }); - expect(result.licenseTermsId).to.be.a("string").and.not.empty; + expect(result.licenseTermsId).to.be.a("bigint"); }); it("should not throw error when registering license with commercial use", async function () { const result = await client.license.registerCommercialUsePIL({ mintingFee: "1", - currency: MockERC20, + currency: MockERC20.address, txOptions: { waitForTransaction: true, }, }); - expect(result.licenseTermsId).to.be.a("string").not.empty; + expect(result.licenseTermsId).to.be.a("bigint"); }); it("should not throw error when registering license with commercial Remix use", async function () { const result = await client.license.registerCommercialRemixPIL({ mintingFee: "1", commercialRevShare: 100, - currency: MockERC20, + currency: MockERC20.address, txOptions: { waitForTransaction: true, }, }); - expect(result.licenseTermsId).to.be.a("string").and.not.empty; + expect(result.licenseTermsId).to.be.a("bigint"); }); }); describe("attach License Terms and mint license tokens", async function () { let ipId: Hex; - let licenseId: string; + let licenseId: bigint; let tokenId; before(async function () { tokenId = await getTokenId(); const registerResult = await client.ipAsset.register({ - tokenContract: MockERC721, + nftContract: MockERC721, tokenId: tokenId!, txOptions: { waitForTransaction: true, @@ -90,7 +91,7 @@ describe("License Functions", () => { }, }); expect(result.txHash).to.be.a("string").and.not.empty; - expect(result.licenseTokenId).to.be.a("string").and.not.empty; + expect(result.licenseTokenId).to.be.a("bigint"); }); it("should not throw error when get license terms", async function () { diff --git a/packages/core-sdk/test/integration/permission.test.ts b/packages/core-sdk/test/integration/permission.test.ts index e072c95a..9a3aa3d5 100644 --- a/packages/core-sdk/test/integration/permission.test.ts +++ b/packages/core-sdk/test/integration/permission.test.ts @@ -1,6 +1,6 @@ import { expect } from "chai"; import { StoryClient } from "../../src"; -import { MockERC721, getStoryClientInSepolia, getTokenId } from "./util"; +import { MockERC721, getStoryClientInSepolia, getTokenId } from "./utils/util"; import { Hex } from "viem"; describe("Permission Functions", () => { @@ -15,7 +15,7 @@ describe("Permission Functions", () => { const waitForTransaction: boolean = true; const tokenId = await getTokenId(); const registerResult = await client.ipAsset.register({ - tokenContract: MockERC721, + nftContract: MockERC721, tokenId: tokenId!, txOptions: { waitForTransaction: true, diff --git a/packages/core-sdk/test/integration/royalty.test.ts b/packages/core-sdk/test/integration/royalty.test.ts index f7579d51..828c7442 100644 --- a/packages/core-sdk/test/integration/royalty.test.ts +++ b/packages/core-sdk/test/integration/royalty.test.ts @@ -1,47 +1,26 @@ import chai from "chai"; import { StoryClient } from "../../src"; -import { - Hex, - http, - createPublicClient, - createWalletClient, - PublicClient, - WalletClient, - encodeFunctionData, - isBytes, -} from "viem"; -import { privateKeyToAccount } from "viem/accounts"; +import { Hex, encodeFunctionData } from "viem"; import chaiAsPromised from "chai-as-promised"; -import { chainStringToViemChain, waitTx } from "../../src/utils/utils"; -import { MockERC721, MockERC20, getTokenId, getStoryClientInSepolia } from "./util"; +import { MockERC721, getTokenId, getStoryClientInSepolia } from "./utils/util"; +import { MockERC20 } from "./utils/mockERC20"; chai.use(chaiAsPromised); const expect = chai.expect; -let snapshotId: string; +let snapshotId: bigint; describe("Test royalty Functions", () => { let client: StoryClient; - let publicClient: PublicClient; - let walletClient: WalletClient; before(function () { client = getStoryClientInSepolia(); - const baseConfig = { - chain: chainStringToViemChain("sepolia"), - transport: http(process.env.TEST_SEPOLIA_RPC_PROVIDER_URL), - } as const; - publicClient = createPublicClient(baseConfig); - walletClient = createWalletClient({ - ...baseConfig, - account: privateKeyToAccount(process.env.SEPOLIA_WALLET_PRIVATE_KEY as Hex), - }); }); - describe("Royalty in storyTestNet", async function () { + describe("Royalty Functions", async function () { let ipId1: Hex; let ipId2: Hex; const getIpId = async (): Promise => { const tokenId = await getTokenId(); const response = await client.ipAsset.register({ - tokenContract: MockERC721, + nftContract: MockERC721, tokenId: tokenId!, txOptions: { waitForTransaction: true, @@ -49,10 +28,10 @@ describe("Test royalty Functions", () => { }); return response.ipId! as Hex; }; - const getCommercialPolicyId = async (): Promise => { + const getCommercialPolicyId = async (): Promise => { const response = await client.license.registerCommercialRemixPIL({ mintingFee: "1", - currency: MockERC20, + currency: MockERC20.address, commercialRevShare: 10000, txOptions: { waitForTransaction: true, @@ -61,7 +40,7 @@ describe("Test royalty Functions", () => { return response.licenseTermsId!; }; - const attachLicenseTerms = async (ipId: Hex, licenseTermsId: string) => { + const attachLicenseTerms = async (ipId: Hex, licenseTermsId: bigint) => { await client.license.attachLicenseTerms({ ipId, licenseTermsId: licenseTermsId, @@ -95,85 +74,13 @@ describe("Test royalty Functions", () => { }, }); expect(response.txHash).to.be.a("string").not.empty; - expect(response.royaltyTokensCollected).to.be.a("string").not.empty; + expect(response.royaltyTokensCollected).to.be.a("bigint"); }); 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(100000 * 10 ** 6)], - 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.SEPOLIA_TEST_WALLET_ADDRESS! as Hex, BigInt(100000 * 10 ** 6)], - }); - const mintHash = await walletClient.writeContract(request); - await waitTx(publicClient, mintHash); - const response = await client.royalty.payRoyaltyOnBehalf({ - receiverIpId: ipId1, - payerIpId: ipId2, - token: MockERC20, - amount: "10", - txOptions: { - waitForTransaction: true, - }, - }); - expect(response.txHash).to.be.a("string").not.empty; + const mockERC20 = new MockERC20(); + await mockERC20.approve(MockERC721); + await mockERC20.mint(); }); it("should not throw error when snapshot", async () => { @@ -184,7 +91,7 @@ describe("Test royalty Functions", () => { }, }); expect(response.txHash).to.be.a("string").not.empty; - expect(response.snapshotId).to.be.a("string"); + expect(response.snapshotId).to.be.a("bigint"); snapshotId = response.snapshotId!; }); it("should not throw error when claimable revenue", async () => { @@ -192,9 +99,9 @@ describe("Test royalty Functions", () => { royaltyVaultIpId: ipId1, account: ipId1, snapshotId: snapshotId.toString(), - token: MockERC20, + token: MockERC20.address, }); - expect(response).to.be.a("string"); + expect(response).to.be.a("bigint"); }); it("should not throw error when claim revenue by ipAccount", async () => { @@ -202,18 +109,18 @@ describe("Test royalty Functions", () => { royaltyVaultIpId: ipId1, snapshotIds: [snapshotId.toString()], account: ipId1, - token: MockERC20, + token: MockERC20.address, txOptions: { waitForTransaction: true, }, }); - expect(response.claimableToken).to.be.a("string"); + expect(response.claimableToken).to.be.a("bigint"); }); it("should not throw error when claim revenue by ipAccount by EOA", async () => { const proxyAddress = await client.royalty.getRoyaltyVaultAddress(ipId1); //1.transfer token to eoa - const iPAccountExecuteResponse = await client.ipAccount.execute({ + await client.ipAccount.execute({ to: proxyAddress, value: 0, accountAddress: ipId1, @@ -252,10 +159,10 @@ describe("Test royalty Functions", () => { }), }); //2. transfer token to royaltyVault,revenue token - const response2 = await client.royalty.payRoyaltyOnBehalf({ + await client.royalty.payRoyaltyOnBehalf({ receiverIpId: ipId1, payerIpId: ipId2, - token: MockERC20, + token: MockERC20.address, amount: "10", txOptions: { waitForTransaction: true, @@ -265,20 +172,16 @@ describe("Test royalty Functions", () => { royaltyVaultIpId: ipId1, txOptions: { waitForTransaction: true }, }); - const claimableRevenue = await client.royalty.claimableRevenue({ - royaltyVaultIpId: ipId1, - account: process.env.SEPOLIA_TEST_WALLET_ADDRESS as Hex, - snapshotId: snapshotId.snapshotId!, - token: MockERC20, - }); + const response = await client.royalty.claimRevenue({ royaltyVaultIpId: ipId1, snapshotIds: [snapshotId.snapshotId!], - token: MockERC20, + token: MockERC20.address, txOptions: { waitForTransaction: true, }, }); + expect(response.claimableToken).to.be.a("bigint"); }); }); }); diff --git a/packages/core-sdk/test/integration/utils/mockERC20.ts b/packages/core-sdk/test/integration/utils/mockERC20.ts new file mode 100644 index 00000000..9ab62f5f --- /dev/null +++ b/packages/core-sdk/test/integration/utils/mockERC20.ts @@ -0,0 +1,98 @@ +import { + PublicClient, + WalletClient, + http, + createPublicClient, + createWalletClient, + Hex, + Address, +} from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { chainStringToViemChain, waitTx } from "../../../src/utils/utils"; + +export class MockERC20 { + private publicClient: PublicClient; + private walletClient: WalletClient; + static address: Hex = "0xB132A6B7AE652c974EE1557A3521D53d18F6739f"; + + constructor() { + const baseConfig = { + chain: chainStringToViemChain("sepolia"), + transport: http(process.env.SEPOLIA_RPC_PROVIDER_URL), + } as const; + this.publicClient = createPublicClient(baseConfig); + this.walletClient = createWalletClient({ + ...baseConfig, + account: privateKeyToAccount(process.env.SEPOLIA_WALLET_PRIVATE_KEY as Hex), + }); + } + + public async approve(contract: Address): Promise { + 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 this.publicClient.simulateContract({ + abi: abi, + address: MockERC20.address, + functionName: "approve", + args: [contract, BigInt(100000 * 10 ** 6)], + account: this.walletClient.account, + }); + const approveHash = await this.walletClient.writeContract(call); + await waitTx(this.publicClient, approveHash); + } + + public async mint(): Promise { + const { request } = await this.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.address, + functionName: "mint", + account: this.walletClient.account, + args: [process.env.SEPOLIA_TEST_WALLET_ADDRESS! as Address, BigInt(100000 * 10 ** 6)], + }); + const mintHash = await this.walletClient.writeContract(request); + await waitTx(this.publicClient, mintHash); + } +} diff --git a/packages/core-sdk/test/integration/util.ts b/packages/core-sdk/test/integration/utils/util.ts similarity index 56% rename from packages/core-sdk/test/integration/util.ts rename to packages/core-sdk/test/integration/utils/util.ts index 0be88421..6e25caf8 100644 --- a/packages/core-sdk/test/integration/util.ts +++ b/packages/core-sdk/test/integration/utils/util.ts @@ -1,18 +1,18 @@ import { privateKeyToAccount } from "viem/accounts"; -import { chainStringToViemChain } from "../../src/utils/utils"; -import { http, createPublicClient, createWalletClient, Hex } from "viem"; -import { StoryClient, StoryConfig } from "../../src"; +import { chainStringToViemChain } from "../../../src/utils/utils"; +import { http, createPublicClient, createWalletClient, Hex, Address } from "viem"; +import { StoryClient, StoryConfig } from "../../../src"; +const baseConfig = { + chain: chainStringToViemChain("sepolia"), + transport: http(process.env.TEST_SEPOLIA_RPC_PROVIDER_URL), +} as const; +const publicClient = createPublicClient(baseConfig); +const walletClient = createWalletClient({ + ...baseConfig, + account: privateKeyToAccount(process.env.SEPOLIA_WALLET_PRIVATE_KEY as Hex), +}); -export const getTokenId = async (): Promise => { - const baseConfig = { - chain: chainStringToViemChain("sepolia"), - transport: http(process.env.TEST_SEPOLIA_RPC_PROVIDER_URL), - } as const; - const publicClient = createPublicClient(baseConfig); - const walletClient = createWalletClient({ - ...baseConfig, - account: privateKeyToAccount(process.env.SEPOLIA_WALLET_PRIVATE_KEY as Hex), - }); +export const getTokenId = async (nftContract?: Address): Promise => { const { request } = await publicClient.simulateContract({ abi: [ { @@ -23,7 +23,7 @@ export const getTokenId = async (): Promise => { type: "function", }, ], - address: MockERC721, + address: nftContract || MockERC721, functionName: "mint", args: [process.env.SEPOLIA_TEST_WALLET_ADDRESS as Hex], account: walletClient.account, @@ -33,11 +33,10 @@ export const getTokenId = async (): Promise => { hash, }); if (logs[0].topics[3]) { - return parseInt(logs[0].topics[3], 16).toString(); + return parseInt(logs[0].topics[3], 16); } }; -export const MockERC20 = "0xB132A6B7AE652c974EE1557A3521D53d18F6739f"; export const MockERC721 = "0x7ee32b8B515dEE0Ba2F25f612A04a731eEc24F49"; export const getStoryClientInSepolia = (): StoryClient => { @@ -48,3 +47,7 @@ export const getStoryClientInSepolia = (): StoryClient => { }; return StoryClient.newClient(config); }; + +export const getBlockTimestamp = async (): Promise => { + return (await publicClient.getBlock()).timestamp; +}; diff --git a/packages/core-sdk/test/unit/client.test.ts b/packages/core-sdk/test/unit/client.test.ts index dfef91c3..3f5b295c 100644 --- a/packages/core-sdk/test/unit/client.test.ts +++ b/packages/core-sdk/test/unit/client.test.ts @@ -5,6 +5,7 @@ import { Account, createPublicClient, createWalletClient, http, Transport } from import { DisputeClient, LicenseClient, + NftClient, PermissionClient, StoryClient, StoryConfig, @@ -126,5 +127,11 @@ describe("Test StoryClient", function () { expect(client.royalty).to.not.equal(null); expect(client.royalty).to.not.equal(undefined); }); + + it("should return client nft", () => { + const royalty = new NftClient(rpcClient, wallet); + expect(client.nftClient).to.not.equal(null); + expect(client.nftClient).to.not.equal(undefined); + }); }); }); diff --git a/packages/core-sdk/test/unit/resources/ipAccount.test.ts b/packages/core-sdk/test/unit/resources/ipAccount.test.ts index 876f5471..d40ed54d 100644 --- a/packages/core-sdk/test/unit/resources/ipAccount.test.ts +++ b/packages/core-sdk/test/unit/resources/ipAccount.test.ts @@ -5,6 +5,7 @@ import { IPAccountClient } from "../../../src/resources/ipAccount"; import { IPAccountExecuteRequest, IPAccountExecuteWithSigRequest } from "../../../src"; import * as utils from "../../../src/utils/utils"; import { Account, PublicClient, WalletClient, zeroAddress } from "viem"; +const { IpAccountImplClient } = require("../../../src/abi/generated"); describe("Test IPAccountClient", () => { let ipAccountClient: IPAccountClient; @@ -255,4 +256,14 @@ describe("Test IPAccountClient", () => { expect(result.txHash).to.equal(txHash); }); }); + + describe("Test getIpAccountNonce", () => { + it("should return the state of the IP Account", async function () { + sinon.stub(IpAccountImplClient.prototype, "state").resolves(1n); + const state = await ipAccountClient.getIpAccountNonce( + "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + ); + expect(state).to.equal(1n); + }); + }); }); diff --git a/packages/core-sdk/test/unit/resources/ipAsset.test.ts b/packages/core-sdk/test/unit/resources/ipAsset.test.ts index 837fcf9b..2bb64997 100644 --- a/packages/core-sdk/test/unit/resources/ipAsset.test.ts +++ b/packages/core-sdk/test/unit/resources/ipAsset.test.ts @@ -1,9 +1,10 @@ import chai from "chai"; import { createMock } from "../testUtils"; import * as sinon from "sinon"; -import { IPAssetClient } from "../../../src"; +import { CreateIpAssetWithPilTermsRequest, IPAssetClient } from "../../../src"; import { PublicClient, WalletClient, Account } from "viem"; import chaiAsPromised from "chai-as-promised"; +import { RegisterIpAndAttachPilTermsRequest } from "../../../src/types/resources/ipAsset"; chai.use(chaiAsPromised); const expect = chai.expect; @@ -33,7 +34,7 @@ describe("Test IpAssetClient", function () { sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(true); const res = await ipAssetClient.register({ - tokenContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", tokenId: "3", }); @@ -51,7 +52,7 @@ describe("Test IpAssetClient", function () { .resolves("0x129f7dd802200f096221dd89d5b086e4bd3ad6eafb378a0c75e3b04fc375f997"); const res = await ipAssetClient.register({ - tokenContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", tokenId: "3", }); @@ -81,7 +82,7 @@ describe("Test IpAssetClient", function () { ]); const response = await ipAssetClient.register({ - tokenContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", tokenId: "3", txOptions: { waitForTransaction: true, @@ -102,7 +103,7 @@ describe("Test IpAssetClient", function () { sinon.stub(ipAssetClient.ipAssetRegistryClient, "register").throws(new Error("revert error")); try { await ipAssetClient.register({ - tokenContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", tokenId: "3", txOptions: { waitForTransaction: true, @@ -143,6 +144,7 @@ describe("Test IpAssetClient", function () { childIpId: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", parentIpIds: ["0x1daAE3197Bc469Cb97B917aa460a12dD95c6627a"], licenseTermsIds: ["1"], + licenseTemplate: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", }); } catch (err) { expect((err as Error).message).equal( @@ -239,6 +241,7 @@ describe("Test IpAssetClient", function () { childIpId: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", parentIpIds: ["0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4"], licenseTermsIds: ["1"], + licenseTemplate: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", txOptions: { waitForTransaction: true, }, @@ -338,4 +341,382 @@ describe("Test IpAssetClient", function () { ); }); }); + + describe("Test ipAssetClient.createIpAssetWithPilTerms", async function () { + it("throw PIL_TYPE error when createIpAssetWithPilTerms given PIL_TYPE is not match", async () => { + try { + await ipAssetClient.createIpAssetWithPilTerms({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + } as unknown as CreateIpAssetWithPilTermsRequest); + } catch (err) { + expect((err as Error).message).equal( + "Failed to mint and register IP and attach PIL terms: PIL type is required.", + ); + } + }); + + it("should throw address error when createIpAssetWithPilTerms given nftContract is not registered", async () => { + sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(false); + + try { + await ipAssetClient.createIpAssetWithPilTerms({ + nftContract: "0x", + pilType: 0, + }); + } catch (err) { + expect((err as Error).message).contains( + `Failed to mint and register IP and attach PIL terms: Address "0x" is invalid.`, + ); + } + }); + + it("should return txHash when createIpAssetWithPilTerms given correct args", async () => { + const hash = "0x129f7dd802200f096221dd89d5b086e4bd3ad6eafb378a0c75e3b04fc375f997"; + sinon.stub(ipAssetClient.spgClient, "mintAndRegisterIpAndAttachPilTerms").resolves(hash); + const result = await ipAssetClient.createIpAssetWithPilTerms({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + pilType: 0, + recipient: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + }); + + expect(result.txHash).to.equal(hash); + }); + it("should return ipId, tokenId, licenseTermsId,txHash when createIpAssetWithPilTerms given correct args and waitForTransaction of true", async () => { + const hash = "0x129f7dd802200f096221dd89d5b086e4bd3ad6eafb378a0c75e3b04fc375f997"; + sinon.stub(ipAssetClient.spgClient, "mintAndRegisterIpAndAttachPilTerms").resolves(hash); + sinon.stub(ipAssetClient.ipAssetRegistryClient, "parseTxIpRegisteredEvent").returns([ + { + ipId: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + chainId: 0n, + tokenContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + tokenId: 1n, + name: "", + uri: "", + registrationDate: 0n, + }, + ]); + sinon.stub(ipAssetClient.licensingModuleClient, "parseTxLicenseTermsAttachedEvent").returns([ + { + ipId: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + caller: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + licenseTemplate: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + licenseTermsId: 0n, + }, + ]); + const result = await ipAssetClient.createIpAssetWithPilTerms({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c662ac", + pilType: 0, + metadata: { + metadataURI: "https://", + metadata: "metadata", + nftMetadata: "nftMetadata", + }, + txOptions: { + waitForTransaction: true, + }, + }); + + expect(result.txHash).to.equal(hash); + expect(result.ipId).to.equal("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + expect(result.licenseTermsId).to.equal(0n); + expect(result.tokenId).to.equal(1n); + }); + }); + + describe("Test ipAssetClient.registerDerivativeIp", async function () { + it("should throw ipId have registered error when registerDerivativeIp given tokenId have registered", async () => { + sinon + .stub(ipAssetClient.ipAssetRegistryClient, "ipId") + .resolves("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(true); + + try { + await ipAssetClient.registerDerivativeIp({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + tokenId: "3", + derivData: { + parentIpIds: ["0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4"], + licenseTermsIds: ["1"], + }, + sigRegister: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + }); + } catch (err) { + expect((err as Error).message).equal( + "Failed to register derivative IP: The NFT with id 3 is already registered as IP.", + ); + } + }); + + it("should throw not match error when registerDerivativeIp given parentIds'length is not equal licenseTermsIds'length", async () => { + sinon + .stub(ipAssetClient.ipAssetRegistryClient, "ipId") + .resolves("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(false); + + try { + await ipAssetClient.registerDerivativeIp({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + tokenId: "3", + derivData: { + parentIpIds: ["0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4"], + licenseTermsIds: ["1", "2"], + }, + sigRegister: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + }); + } catch (err) { + expect((err as Error).message).equal( + "Failed to register derivative IP: Parent IP IDs and License terms IDs must be provided in pairs.", + ); + } + }); + + it("should throw not attach error when registerDerivativeIp given licenseTermsIds is not attached parentIpIds", async () => { + sinon + .stub(ipAssetClient.ipAssetRegistryClient, "ipId") + .resolves("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(false); + sinon + .stub(ipAssetClient.licenseRegistryReadOnlyClient, "hasIpAttachedLicenseTerms") + .resolves(false); + + try { + await ipAssetClient.registerDerivativeIp({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + tokenId: "3", + derivData: { + parentIpIds: ["0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4"], + licenseTermsIds: ["1"], + }, + sigRegister: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + }); + } catch (err) { + expect((err as Error).message).equal( + "Failed to register derivative IP: License terms id 1 must be attached to the parent ipId 0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4 before registering derivative.", + ); + } + }); + + it("should return txHash when registerDerivativeIp given correct args", async () => { + sinon + .stub(ipAssetClient.ipAssetRegistryClient, "ipId") + .resolves("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(false); + sinon + .stub(ipAssetClient.licenseRegistryReadOnlyClient, "hasIpAttachedLicenseTerms") + .resolves(true); + sinon + .stub(ipAssetClient.spgClient, "registerIpAndMakeDerivative") + .resolves("0x129f7dd802200f096221dd89d5b086e4bd3ad6eafb378a0c75e3b04fc375f997"); + + const res = await ipAssetClient.registerDerivativeIp({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + tokenId: "3", + derivData: { + parentIpIds: ["0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4"], + licenseTermsIds: ["1"], + licenseTemplate: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + }, + sigRegister: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + }); + + expect(res.txHash).equal( + "0x129f7dd802200f096221dd89d5b086e4bd3ad6eafb378a0c75e3b04fc375f997", + ); + }); + + it("should return txHash and ipId when registerDerivativeIp given correct args and waitForTransaction of true", async () => { + sinon + .stub(ipAssetClient.ipAssetRegistryClient, "ipId") + .resolves("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(false); + sinon + .stub(ipAssetClient.licenseRegistryReadOnlyClient, "hasIpAttachedLicenseTerms") + .resolves(true); + sinon + .stub(ipAssetClient.spgClient, "registerIpAndMakeDerivative") + .resolves("0x129f7dd802200f096221dd89d5b086e4bd3ad6eafb378a0c75e3b04fc375f997"); + sinon.stub(ipAssetClient.ipAssetRegistryClient, "parseTxIpRegisteredEvent").returns([ + { + ipId: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + chainId: 0n, + tokenContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + tokenId: 1n, + name: "", + uri: "", + registrationDate: 0n, + }, + ]); + + const res = await ipAssetClient.registerDerivativeIp({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + tokenId: "3", + derivData: { + parentIpIds: ["0xd142822Dc1674154EaF4DDF38bbF7EF8f0D8ECe4"], + licenseTermsIds: ["1"], + }, + sigRegister: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + metadata: { + metadataURI: "https://", + metadata: "metadata", + nftMetadata: "nftMetadata", + }, + sigMetadata: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + txOptions: { + waitForTransaction: true, + }, + }); + + expect(res.txHash).equal( + "0x129f7dd802200f096221dd89d5b086e4bd3ad6eafb378a0c75e3b04fc375f997", + ); + expect(res.ipId).equal("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + }); + }); + + describe("Test ipAssetClient.registerIpAndAttachPilTerms", async function () { + it("should throw ipId have registered error when registerIpAndAttachPilTerms given tokenId have registered", async () => { + sinon + .stub(ipAssetClient.ipAssetRegistryClient, "ipId") + .resolves("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(true); + + try { + await ipAssetClient.registerIpAndAttachPilTerms({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + tokenId: "3", + metadata: { + metadataURI: "https://", + metadata: "metadata", + nftMetadata: "nftMetadata", + }, + pilType: 0, + sigAttach: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + sigMetadata: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + }); + } catch (err) { + expect((err as Error).message).equal( + "Failed to register IP and attach PIL terms: The NFT with id 3 is already registered as IP.", + ); + } + }); + it("should throw PIL_TYPE error when registerIpAndAttachPilTerms given PIL_TYPE is not match", async () => { + try { + await ipAssetClient.registerIpAndAttachPilTerms({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + tokenId: "3", + } as unknown as RegisterIpAndAttachPilTermsRequest); + } catch (err) { + expect((err as Error).message).equal( + "Failed to register IP and attach PIL terms: PIL type is required.", + ); + } + }); + it("should return hash when registerIpAndAttachPilTerms given correct args", async () => { + const hash = "0x129f7dd802200f096221dd89d5b086e4bd3ad6eafb378a0c75e3b04fc375f997"; + sinon.stub(ipAssetClient.spgClient, "registerIpAndAttachPilTerms").resolves(hash); + sinon + .stub(ipAssetClient.ipAssetRegistryClient, "ipId") + .resolves("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(false); + + const result = await ipAssetClient.registerIpAndAttachPilTerms({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + tokenId: "3", + metadata: { + metadataURI: "https://", + metadata: "metadata", + nftMetadata: "nftMetadata", + }, + pilType: 0, + sigAttach: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + sigMetadata: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + }); + + expect(result.txHash).to.equal(hash); + }); + + it("should return txHash and ipId when registerIpAndAttachPilTerms given correct args and waitForTransaction of true", async () => { + const hash = "0x129f7dd802200f096221dd89d5b086e4bd3ad6eafb378a0c75e3b04fc375f997"; + sinon + .stub(ipAssetClient.ipAssetRegistryClient, "ipId") + .resolves("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + sinon.stub(ipAssetClient.ipAssetRegistryClient, "isRegistered").resolves(false); + + sinon.stub(ipAssetClient.spgClient, "registerIpAndAttachPilTerms").resolves(hash); + sinon.stub(ipAssetClient.licensingModuleClient, "parseTxLicenseTermsAttachedEvent").returns([ + { + ipId: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + caller: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + licenseTemplate: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", + licenseTermsId: 0n, + }, + ]); + const result = await ipAssetClient.registerIpAndAttachPilTerms({ + nftContract: "0x1daAE3197Bc469Cb97B917aa460a12dD95c662ac", + tokenId: "3", + metadata: { + metadataURI: "https://", + metadata: "metadata", + nftMetadata: "nftMetadata", + }, + pilType: 0, + sigAttach: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + sigMetadata: { + signer: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", + deadline: "1", + signature: "0x", + }, + txOptions: { + waitForTransaction: true, + }, + }); + + expect(result.txHash).to.equal(hash); + expect(result.ipId).to.equal("0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c"); + }); + }); }); diff --git a/packages/core-sdk/test/unit/resources/license.test.ts b/packages/core-sdk/test/unit/resources/license.test.ts index 0b5e00e5..ede362be 100644 --- a/packages/core-sdk/test/unit/resources/license.test.ts +++ b/packages/core-sdk/test/unit/resources/license.test.ts @@ -43,7 +43,7 @@ describe("Test LicenseClient", function () { const result = await licenseClient.registerNonComSocialRemixingPIL(); - expect(result.licenseTermsId).to.equal("1"); + expect(result.licenseTermsId).to.equal(1n); }); it("should return txhash when call registerNonComSocialRemixingPIL given licenseTermsId is not registered", async function () { @@ -79,7 +79,7 @@ describe("Test LicenseClient", function () { }); expect(result.txHash).to.equal(txHash); - expect(result.licenseTermsId).to.equal("1"); + expect(result.licenseTermsId).to.equal(1n); }); it("should return throw error when call registerNonComSocialRemixingPIL given request fail", async function () { @@ -110,11 +110,11 @@ describe("Test LicenseClient", function () { .resolves({ selectedLicenseTermsId: BigInt(1) }); const result = await licenseClient.registerCommercialUsePIL({ - mintingFee: "1", + mintingFee: 1, currency: zeroAddress, }); - expect(result.licenseTermsId).to.equal("1"); + expect(result.licenseTermsId).to.equal(1n); }); it("should return txhash when call registerCommercialUsePIL given licenseTermsId is not registered", async function () { @@ -155,7 +155,7 @@ describe("Test LicenseClient", function () { }); expect(result.txHash).to.equal(txHash); - expect(result.licenseTermsId).to.equal("1"); + expect(result.licenseTermsId).to.equal(1n); }); it("should return throw error when call registerCommercialUsePIL given request fail", async function () { @@ -191,7 +191,7 @@ describe("Test LicenseClient", function () { currency: zeroAddress, }); - expect(result.licenseTermsId).to.equal("1"); + expect(result.licenseTermsId).to.equal(1n); }); it("should return txhash when call registerCommercialRemixPIL given licenseTermsId is not registered", async function () { @@ -234,7 +234,7 @@ describe("Test LicenseClient", function () { }); expect(result.txHash).to.equal(txHash); - expect(result.licenseTermsId).to.equal("1"); + expect(result.licenseTermsId).to.equal(1n); }); it("should return throw error when call registerCommercialRemixPIL given request fail", async function () { @@ -497,7 +497,7 @@ describe("Test LicenseClient", function () { }); expect(result.txHash).to.equal(txHash); - expect(result.licenseTokenId).to.equal("1"); + expect(result.licenseTokenId).to.equal(1n); }); }); diff --git a/packages/core-sdk/test/unit/resources/nftClient.test.ts b/packages/core-sdk/test/unit/resources/nftClient.test.ts index 516c9f25..fa68e710 100644 --- a/packages/core-sdk/test/unit/resources/nftClient.test.ts +++ b/packages/core-sdk/test/unit/resources/nftClient.test.ts @@ -20,7 +20,7 @@ describe("Test NftClient", function () { beforeEach(function () { rpcMock = createMock(); - walletMock = createMock(); + walletMock = createMock({ account: { address: "0x" } }); nftClient = new NftClient(rpcMock, walletMock); }); @@ -63,6 +63,19 @@ describe("Test NftClient", function () { } }); + it("should throw Invalid mintCost and mintToken error if mintCost is 0", async () => { + rpcMock.simulateContract = sinon.stub().resolves({ request: null }); + try { + await nftClient.createNFTCollection({ ...reqBody, mintCost: 6n }); + } catch (err) { + expect( + (err as Error).message.includes( + "Invalid mint token address, mint cost is greater than 0", + ), + ); + } + }); + it("should return txHash and nftContract if txOptions.waitForTransaction is truthy", async () => { rpcMock.simulateContract = sinon.stub().resolves({ request: null }); rpcMock.waitForTransactionReceipt = sinon.stub().resolves(); @@ -76,6 +89,7 @@ describe("Test NftClient", function () { const result = await nftClient.createNFTCollection({ ...reqBody, + owner: undefined, txOptions: { waitForTransaction: true, }, @@ -88,7 +102,12 @@ describe("Test NftClient", function () { rpcMock.simulateContract = sinon.stub().resolves({ request: null }); walletMock.writeContract = sinon.stub().resolves(mock.txHash); - const result = await nftClient.createNFTCollection(reqBody); + const result = await nftClient.createNFTCollection({ + ...reqBody, + maxSupply: undefined, + mintCost: undefined, + mintToken: undefined, + }); expect(result.txHash).to.equal(mock.txHash); }); }); diff --git a/packages/core-sdk/test/unit/resources/royalty.test.ts b/packages/core-sdk/test/unit/resources/royalty.test.ts index ca62622b..5afbc60b 100644 --- a/packages/core-sdk/test/unit/resources/royalty.test.ts +++ b/packages/core-sdk/test/unit/resources/royalty.test.ts @@ -147,7 +147,7 @@ describe("Test RoyaltyClient", function () { }); expect(result.txHash).equals(txHash); - expect(result.royaltyTokensCollected).equals("1"); + expect(result.royaltyTokensCollected).equals(1); }); }); @@ -160,7 +160,7 @@ describe("Test RoyaltyClient", function () { receiverIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", payerIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - amount: "1", + amount: 1, }); } catch (err) { expect((err as Error).message).equals( @@ -182,7 +182,7 @@ describe("Test RoyaltyClient", function () { receiverIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", payerIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - amount: "1", + amount: 1, }); } catch (err) { expect((err as Error).message).equals( @@ -199,7 +199,7 @@ describe("Test RoyaltyClient", function () { receiverIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", payerIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - amount: "1", + amount: 1, }); expect(result.txHash).equals(txHash); @@ -213,7 +213,7 @@ describe("Test RoyaltyClient", function () { receiverIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", payerIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - amount: "1", + amount: 1, txOptions: { waitForTransaction: true }, }); @@ -229,7 +229,7 @@ describe("Test RoyaltyClient", function () { await royaltyClient.claimableRevenue({ royaltyVaultIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", account: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - snapshotId: "1", + snapshotId: 1, token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", }); } catch (err) { @@ -249,7 +249,7 @@ describe("Test RoyaltyClient", function () { await royaltyClient.claimableRevenue({ royaltyVaultIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", account: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - snapshotId: "1", + snapshotId: 1, token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", }); } catch (err) { @@ -275,10 +275,10 @@ describe("Test RoyaltyClient", function () { const result = await royaltyClient.claimableRevenue({ royaltyVaultIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", account: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - snapshotId: "1", + snapshotId: 1, token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", }); - expect(result).equals("1"); + expect(result).equals(1); }); }); @@ -289,7 +289,7 @@ describe("Test RoyaltyClient", function () { try { await royaltyClient.claimRevenue({ account: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - snapshotIds: ["1"], + snapshotIds: [1], token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", royaltyVaultIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", }); @@ -309,7 +309,7 @@ describe("Test RoyaltyClient", function () { try { await royaltyClient.claimRevenue({ account: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - snapshotIds: ["1"], + snapshotIds: [1], token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", royaltyVaultIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", }); @@ -334,7 +334,7 @@ describe("Test RoyaltyClient", function () { sinon.stub(royaltyClient.ipAccountClient, "execute").resolves({ txHash }); const result = await royaltyClient.claimRevenue({ account: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - snapshotIds: ["1"], + snapshotIds: [1], token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", royaltyVaultIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", }); @@ -366,14 +366,14 @@ describe("Test RoyaltyClient", function () { const result = await royaltyClient.claimRevenue({ account: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", - snapshotIds: ["1"], + snapshotIds: [1], token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", royaltyVaultIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", txOptions: { waitForTransaction: true }, }); expect(result.txHash).equals(txHash); - expect(result.claimableToken).equals("1"); + expect(result.claimableToken).equals(1); }); it("should return txHash when call claimRevenue given correct args and waitForTransaction is true by EOA", async function () { @@ -400,14 +400,14 @@ describe("Test RoyaltyClient", function () { ]); const result = await royaltyClient.claimRevenue({ - snapshotIds: ["1"], + snapshotIds: [1], token: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", royaltyVaultIpId: "0x73fcb515cee99e4991465ef586cfe2b072ebb512", txOptions: { waitForTransaction: true }, }); expect(result.txHash).equals(txHash); - expect(result.claimableToken).equals("1"); + expect(result.claimableToken).equals(1); }); }); @@ -478,7 +478,7 @@ describe("Test RoyaltyClient", function () { { snapshotId: 1, snapshotTimestamp: 1, - unclaimedTokens: "1", + unclaimedTokens: 1, }, ]); @@ -488,7 +488,7 @@ describe("Test RoyaltyClient", function () { }); expect(result.txHash).equals(txHash); - expect(result.snapshotId).equals("1"); + expect(result.snapshotId).equals(1); }); }); }); diff --git a/packages/core-sdk/test/unit/utils/utils.test.ts b/packages/core-sdk/test/unit/utils/utils.test.ts index c136606f..9d01ebe4 100644 --- a/packages/core-sdk/test/unit/utils/utils.test.ts +++ b/packages/core-sdk/test/unit/utils/utils.test.ts @@ -6,7 +6,6 @@ import { TypedData } from "../../../src/types/common"; import { SupportedChainIds } from "../../../src/types/config"; import { isIntegerString, - parseToBigInt, decodeShortstring, splitIntoBytes32, waitTxAndFilterLog, @@ -26,10 +25,6 @@ describe("Test isIntegerString", function () { it("should return false when passing in a non-integer string", function () { expect(isIntegerString("a")).to.be.false; }); - - it("should parse string to big int", function () { - expect(parseToBigInt("7")).to.be.equal(7n); - }); }); describe("Test decodeShortstring", function () { diff --git a/packages/wagmi-generater/wagmi.config.ts b/packages/wagmi-generater/wagmi.config.ts index bf2734d7..c5a0cbe9 100644 --- a/packages/wagmi-generater/wagmi.config.ts +++ b/packages/wagmi-generater/wagmi.config.ts @@ -4,7 +4,6 @@ import { sdk } from "./sdk"; import type { Evaluate } from "@wagmi/cli/src/types"; import type { ContractConfig } from "@wagmi/cli/src/config"; import { resolveProxyContracts } from "./resolveProxyContracts"; -const storyTestnetId = 1513; const sepoliaChainId = 11155111; import "dotenv/config"; @@ -143,8 +142,14 @@ export default defineConfig(async () => { "raiseDispute", "resolveDispute", ], - IPAccountImpl: ["execute", "executeWithSig"], - IPAssetRegistry: ["IPRegistered", "ipId", "isRegistered", "register"], + IPAccountImpl: ["execute", "executeWithSig", "state"], + IPAssetRegistry: [ + "IPRegistered", + "ipId", + "isRegistered", + "register", + "IPAccountRegistered", + ], IpRoyaltyVaultImpl: [ "claimRevenueBySnapshotBatch", "claimRevenueByTokenBatch", @@ -168,6 +173,7 @@ export default defineConfig(async () => { "registerDerivativeWithLicenseTokens", "registerDerivative", "getLicenseTerms", + "LicenseTermsAttached", ], ModuleRegistry: ["isRegistered"], RoyaltyModule: ["payRoyaltyOnBehalf"], @@ -183,7 +189,7 @@ export default defineConfig(async () => { "mintAndRegisterIpAndMakeDerivative", "registerIpAndMakeDerivative", "mintAndRegisterIpAndMakeDerivativeWithLicenseTokens", - "registerIpAndMakeDerivativeWithLicenseTokens" + "registerIpAndMakeDerivativeWithLicenseTokens", ], }, }),