diff --git a/packages/core-sdk/src/abi/accessController.abi.ts b/packages/core-sdk/src/abi/accessController.abi.ts index 989f0204..18fa2c54 100644 --- a/packages/core-sdk/src/abi/accessController.abi.ts +++ b/packages/core-sdk/src/abi/accessController.abi.ts @@ -1,13 +1,14 @@ -import { formatAbi } from "abitype"; import { getAddress } from "viem"; import AccessControllerABI from "./json/AccessController.abi"; +import errorsJson from "./json/Errors.json"; -export const AccessControllerRaw = AccessControllerABI; -export const AccessControllerReadable = formatAbi(AccessControllerRaw); +export const ErrorsAbi = errorsJson; + +export const AccessControllerABImerged = [...AccessControllerABI, ...ErrorsAbi]; export const AccessControllerConfig = { - abi: AccessControllerRaw, + abi: AccessControllerABImerged, address: getAddress( process.env.ACCESS_CONTROLLER || process.env.NEXT_PUBLIC_ACCESS_CONTROLLER || "", ), diff --git a/packages/core-sdk/src/abi/ipAccountImpl.abi.ts b/packages/core-sdk/src/abi/ipAccountImpl.abi.ts new file mode 100644 index 00000000..e7b7f9ea --- /dev/null +++ b/packages/core-sdk/src/abi/ipAccountImpl.abi.ts @@ -0,0 +1,6 @@ +import IPAccountImplABI from "./json/IPAccountImpl.abi"; +import errorsJson from "./json/Errors.json"; + +export const ErrorsAbi = errorsJson; + +export const IPAccountImplMerged = [...IPAccountImplABI, ...ErrorsAbi]; diff --git a/packages/core-sdk/src/abi/json/AccessController.abi.ts b/packages/core-sdk/src/abi/json/AccessController.abi.ts index 3268a621..d5910eeb 100644 --- a/packages/core-sdk/src/abi/json/AccessController.abi.ts +++ b/packages/core-sdk/src/abi/json/AccessController.abi.ts @@ -32,4 +32,41 @@ export default [ stateMutability: "nonpayable", type: "function", }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "ipAccount", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "signer", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "bytes4", + name: "func", + type: "bytes4", + }, + { + indexed: false, + internalType: "uint8", + name: "permission", + type: "uint8", + }, + ], + name: "PermissionSet", + type: "event", + }, ] as const; diff --git a/packages/core-sdk/src/abi/json/IIPAccountRegistry.abi.ts b/packages/core-sdk/src/abi/json/IIPAccountRegistry.abi.ts index 1a49afa5..d5840b70 100644 --- a/packages/core-sdk/src/abi/json/IIPAccountRegistry.abi.ts +++ b/packages/core-sdk/src/abi/json/IIPAccountRegistry.abi.ts @@ -17,7 +17,7 @@ export default [ type: "uint256", }, ], - name: "ipAccount", + name: "ipAsset", outputs: [ { internalType: "address", diff --git a/packages/core-sdk/src/abi/json/IPAccountRegistry.abi.ts b/packages/core-sdk/src/abi/json/IPAccountRegistry.abi.ts index e575940f..39d193a8 100644 --- a/packages/core-sdk/src/abi/json/IPAccountRegistry.abi.ts +++ b/packages/core-sdk/src/abi/json/IPAccountRegistry.abi.ts @@ -54,7 +54,7 @@ export default [ type: "uint256", }, ], - name: "ipAccount", + name: "ipAsset", outputs: [ { internalType: "address", diff --git a/packages/core-sdk/src/abi/sdkEntities.json b/packages/core-sdk/src/abi/sdkEntities.json index 8bb36bc5..a6cd7de4 100644 --- a/packages/core-sdk/src/abi/sdkEntities.json +++ b/packages/core-sdk/src/abi/sdkEntities.json @@ -1,5 +1,5 @@ [ - "ipAccount", + "ipAsset", "registerRootIp", "registerDerivativeIp", "addPolicy", diff --git a/packages/core-sdk/src/client.ts b/packages/core-sdk/src/client.ts index 49771c2d..ae025e4d 100644 --- a/packages/core-sdk/src/client.ts +++ b/packages/core-sdk/src/client.ts @@ -9,11 +9,13 @@ import { TransactionReadOnlyClient } from "./resources/transactionReadOnly"; import { HTTP_TIMEOUT } from "./constants/http"; import { Client, ReadOnlyClient } from "./types/client"; import { PlatformClient } from "./utils/platform"; -import { IPAccountClient } from "./resources/ipAccount"; -import { IPAccountReadOnlyClient } from "./resources/ipAccountReadOnly"; import { ModuleReadOnlyClient } from "./resources/moduleReadOnly"; import { TaggingClient } from "./resources/tagging"; import { TaggingReadOnlyClient } from "./resources/taggingReadOnly"; +import { IPAssetClient } from "./resources/ipAsset"; +import { IPAssetReadOnlyClient } from "./resources/ipAssetReadOnly"; +import { PermissionClient } from "./resources/permission"; +import { PermissionReadOnlyClient } from "./resources/permissionReadOnly"; if (typeof process !== "undefined") { dotenv.config(); @@ -28,7 +30,8 @@ export class StoryClient { private readonly rpcClient: PublicClient; private readonly wallet?: WalletClient; - private _ipAccount: IPAccountClient | IPAccountReadOnlyClient | null = null; + private _ipAccount: IPAssetClient | IPAssetReadOnlyClient | null = null; + private _permission: PermissionClient | PermissionReadOnlyClient | null = null; private _transaction: TransactionClient | TransactionReadOnlyClient | null = null; private _platform: PlatformClient | null = null; private _module: ModuleReadOnlyClient | null = null; @@ -88,16 +91,26 @@ export class StoryClient { return new StoryClient(config, false) as Client; } - public get ipAccount(): IPAccountClient | IPAccountReadOnlyClient { + public get ipAsset(): IPAssetClient | IPAssetReadOnlyClient { if (this._ipAccount === null) { this._ipAccount = this.isReadOnly - ? new IPAccountReadOnlyClient(this.httpClient, this.rpcClient) - : new IPAccountClient(this.httpClient, this.rpcClient, this.wallet!); + ? new IPAssetReadOnlyClient(this.httpClient, this.rpcClient) + : new IPAssetClient(this.httpClient, this.rpcClient, this.wallet!); } return this._ipAccount; } + public get permission(): PermissionClient | PermissionReadOnlyClient { + if (this._permission === null) { + this._permission = this.isReadOnly + ? new PermissionReadOnlyClient(this.httpClient, this.rpcClient) + : new PermissionClient(this.httpClient, this.rpcClient, this.wallet!); + } + + return this._permission; + } + /** * Getter for the transaction client. The client is lazily created when * this method is called. diff --git a/packages/core-sdk/src/index.ts b/packages/core-sdk/src/index.ts index 020fa341..8929509b 100644 --- a/packages/core-sdk/src/index.ts +++ b/packages/core-sdk/src/index.ts @@ -5,12 +5,12 @@ export { TransactionClient } from "./resources/transaction"; export { PlatformClient } from "./utils/platform"; export { AddressZero, HashZero } from "./constants/common"; -export { IPAccountClient } from "./resources/ipAccount"; -export { IPAccountReadOnlyClient } from "./resources/ipAccountReadOnly"; -export { AccessControlClient } from "./resources/accessControl"; -export { AccessControlReadOnlyClient } from "./resources/accessControlReadOnly"; export { TaggingReadOnlyClient } from "./resources/taggingReadOnly"; export { ModuleReadOnlyClient } from "./resources/moduleReadOnly"; +export { IPAssetClient } from "./resources/ipAsset"; +export { IPAssetReadOnlyClient } from "./resources/ipAssetReadOnly"; +export { PermissionClient } from "./resources/permission"; +export { PermissionReadOnlyClient } from "./resources/permissionReadOnly"; export type { StoryConfig, StoryReadOnlyConfig } from "./types/config"; export type { Client, ReadOnlyClient } from "./types/client"; diff --git a/packages/core-sdk/src/resources/accessControl.ts b/packages/core-sdk/src/resources/accessControl.ts deleted file mode 100644 index 77837c4a..00000000 --- a/packages/core-sdk/src/resources/accessControl.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { AxiosInstance } from "axios"; -import { PublicClient, WalletClient, getAddress } from "viem"; - -import { handleError } from "../utils/errors"; -import { setPermissionsRequest, setPermissionsResponse } from "../types/resources/accessControl"; -// import { parseToBigInt, waitTxAndFilterLog } from "../utils/utils"; -import { AccessControlReadOnlyClient } from "./accessControlReadOnly"; -import { AccessControllerConfig } from "../abi/accessController.abi"; -// import { HashZero } from "../constants/common"; - -export class AccessControlClient extends AccessControlReadOnlyClient { - private readonly wallet: WalletClient; - - constructor(httpClient: AxiosInstance, rpcClient: PublicClient, wallet: WalletClient) { - super(httpClient, rpcClient); - this.wallet = wallet; - } - - /** - * Set Permission based on the specified input - * - * @param request - the request object that contains all data needed to set permission. - * @returns the response object that contains results from the set permission. - */ - public async setPermission(request: setPermissionsRequest): Promise { - try { - const { request: call } = await this.rpcClient.simulateContract({ - ...AccessControllerConfig, - functionName: "setPermission", - args: [ - getAddress(request.ipAccount), // 0x Address - getAddress(request.signer), // 0x Address - getAddress(request.to), // 0x Address - getAddress(request.func), // bytes4 - request.permission, // uint8 - ], - }); - - const txHash = await this.wallet.writeContract(call); - // if (request.txOptions?.waitForTransaction) { - // const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, { - // ...IPAccountRegistryConfig, - // eventName: "IPAccountRegistered", - // }); - // return { txHash: txHash }; - // } else { - return { txHash: txHash }; - // } - } catch (error) { - handleError(error, "Failed to set permissions"); - } - } -} diff --git a/packages/core-sdk/src/resources/accessControlReadOnly.ts b/packages/core-sdk/src/resources/accessControlReadOnly.ts deleted file mode 100644 index fcf55a1a..00000000 --- a/packages/core-sdk/src/resources/accessControlReadOnly.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AxiosInstance } from "axios"; -import { PublicClient } from "viem"; - -/** - * IPAssetReadOnlyClient allows you to view and search IP Assets on Story Protocol. - */ -export class AccessControlReadOnlyClient { - protected readonly httpClient: AxiosInstance; - protected readonly rpcClient: PublicClient; - - constructor(httpClient: AxiosInstance, rpcClient: PublicClient) { - this.httpClient = httpClient; - this.rpcClient = rpcClient; - } -} diff --git a/packages/core-sdk/src/resources/ipAccount.ts b/packages/core-sdk/src/resources/ipAsset.ts similarity index 66% rename from packages/core-sdk/src/resources/ipAccount.ts rename to packages/core-sdk/src/resources/ipAsset.ts index fa73d04f..9a79b44e 100644 --- a/packages/core-sdk/src/resources/ipAccount.ts +++ b/packages/core-sdk/src/resources/ipAsset.ts @@ -1,8 +1,7 @@ import { AxiosInstance } from "axios"; import { PublicClient, WalletClient, getAddress } from "viem"; -// import { handleError } from "../utils/errors"; -import { IPAccountReadOnlyClient } from "./ipAccountReadOnly"; +import { IPAssetReadOnlyClient } from "./ipAssetReadOnly"; import { handleError } from "../utils/errors"; import { IPAccountRegistryConfig } from "../abi/ipAccountRegistry.abi"; import { @@ -10,17 +9,11 @@ import { RegisterDerivativeIpResponse, RegisterRootIpRequest, RegisterRootIpResponse, - addPolicyRequest, - addPolicyResponse, - // addPolicyToIpRequest, - // addPolicyToIpResponse, -} from "../types/resources/ipAccount"; +} from "../types/resources/ipAsset"; import { parseToBigInt, waitTxAndFilterLog } from "../utils/utils"; import { RegistrationModuleConfig } from "../abi/registrationModule.abi"; -import { LicenseRegistryConfig } from "../abi/licenseRegistry.abi"; -// import { HashZero } from "../constants/common"; -export class IPAccountClient extends IPAccountReadOnlyClient { +export class IPAssetClient extends IPAssetReadOnlyClient { private readonly wallet: WalletClient; constructor(httpClient: AxiosInstance, rpcClient: PublicClient, wallet: WalletClient) { @@ -101,40 +94,40 @@ export class IPAccountClient extends IPAccountReadOnlyClient { } // TODO: move to License resource - public async createPolicy(request: addPolicyRequest): Promise { - try { - const { request: call } = await this.rpcClient.simulateContract({ - ...LicenseRegistryConfig, - functionName: "addPolicy", - args: [ - { - frameworkId: parseToBigInt(request.frameworkId), - mintingParamValues: request.mintingParamValues.map((add) => getAddress(add)), - activationParamValues: request.activationParamValues.map((add) => getAddress(add)), - needsActivation: request.needsActivation, - linkParentParamValues: request.linkParentParamValues.map((add) => getAddress(add)), - }, - ], // TODO: add args - }); + // public async createPolicy(request: addPolicyRequest): Promise { + // try { + // const { request: call } = await this.rpcClient.simulateContract({ + // ...LicenseRegistryConfig, + // functionName: "addPolicy", + // args: [ + // { + // frameworkId: parseToBigInt(request.frameworkId), + // mintingParamValues: request.mintingParamValues.map((add) => getAddress(add)), + // activationParamValues: request.activationParamValues.map((add) => getAddress(add)), + // needsActivation: request.needsActivation, + // linkParentParamValues: request.linkParentParamValues.map((add) => getAddress(add)), + // }, + // ], // TODO: add args + // }); - const txHash = await this.wallet.writeContract(call); - // TODO: need an emitted event - // if (request.txOptions?.waitForTransaction) { - // const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, { - // ...IPAccountRegistryConfig, - // eventName: "IPAccountRegistered", - // }); - // return { txHash: txHash, policyId: targetLog?.args.account.toString() }; - // } else { - return { txHash: txHash }; - // } - } catch (error) { - handleError(error, "Failed to register derivative IP"); - } - } + // const txHash = await this.wallet.writeContract(call); + // // TODO: need an emitted event + // // if (request.txOptions?.waitForTransaction) { + // // const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, { + // // ...IPAccountRegistryConfig, + // // eventName: "IPAccountRegistered", + // // }); + // // return { txHash: txHash, policyId: targetLog?.args.account.toString() }; + // // } else { + // return { txHash: txHash }; + // // } + // } catch (error) { + // handleError(error, "Failed to register derivative IP"); + // } + // } // TODO: move to License resource // public async addPolicyToIp(request: addPolicyToIpRequest): Promise { - // // TODO: use getIpAccount to get the ipId + // TODO: use getIpAccount to get the ipId // } } diff --git a/packages/core-sdk/src/resources/ipAccountReadOnly.ts b/packages/core-sdk/src/resources/ipAssetReadOnly.ts similarity index 53% rename from packages/core-sdk/src/resources/ipAccountReadOnly.ts rename to packages/core-sdk/src/resources/ipAssetReadOnly.ts index bd25715b..049ff135 100644 --- a/packages/core-sdk/src/resources/ipAccountReadOnly.ts +++ b/packages/core-sdk/src/resources/ipAssetReadOnly.ts @@ -1,19 +1,18 @@ import { AxiosInstance } from "axios"; -import { PublicClient } from "viem"; +import { PublicClient, isAddress } from "viem"; import { - GetIpAccountRequest, - GetIpAccountResponse, - ListIpAccountRequest, - ListIpAccountResponse, -} from "../types/resources/ipAccount"; + GetIpAssetRequest, + GetIpAssetResponse, + ListIpAssetRequest, + ListIpAssetResponse, +} from "../types/resources/ipAsset"; import { handleError } from "../utils/errors"; -import { isIntegerString } from "../utils/utils"; /** * IPAssetReadOnlyClient allows you to view and search IP Assets on Story Protocol. */ -export class IPAccountReadOnlyClient { +export class IPAssetReadOnlyClient { protected readonly httpClient: AxiosInstance; protected readonly rpcClient: PublicClient; @@ -28,13 +27,13 @@ export class IPAccountReadOnlyClient { * @param request - the request object for getting an IP Asset. * @returns the response object the contains the fetched IP Asset. */ - public async get(request: GetIpAccountRequest): Promise { + public async get(request: GetIpAssetRequest): Promise { try { - if (!isIntegerString(request.ipId)) { - throw new Error(`Invalid chain id. Must be an integer. But get: ${request.ipId}`); + if (!isAddress(request.ipId)) { + throw new Error(`Invalid ip id. Must be an address. But get: ${request.ipId}`); } - const response = await this.httpClient.get(`/protocol/ipaccount/${request.ipId}`); - return response.data as GetIpAccountResponse; + const response = await this.httpClient.get(`/accounts/${request.ipId}`); + return response.data as GetIpAssetResponse; } catch (error: unknown) { handleError(error, "Failed to get IP account"); } @@ -45,10 +44,10 @@ export class IPAccountReadOnlyClient { * * @returns the response object that contains results from listing query. */ - public async list(request?: ListIpAccountRequest): Promise { + public async list(request?: ListIpAssetRequest): Promise { try { - const response = await this.httpClient.post(`/protocol/ipaccount`, request || {}); - return response.data as ListIpAccountResponse; + const response = await this.httpClient.post(`/accounts`, request || {}); + return response.data as ListIpAssetResponse; } catch (error) { handleError(error, "Failed to list IP Asset."); } diff --git a/packages/core-sdk/src/resources/permission.ts b/packages/core-sdk/src/resources/permission.ts new file mode 100644 index 00000000..0847d908 --- /dev/null +++ b/packages/core-sdk/src/resources/permission.ts @@ -0,0 +1,71 @@ +import { AxiosInstance } from "axios"; +import { PublicClient, WalletClient, getAddress, Hex, encodeFunctionData } from "viem"; + +import { handleError } from "../utils/errors"; +import { setPermissionsRequest, setPermissionsResponse } from "../types/resources/permission"; +import { PermissionReadOnlyClient } from "./permissionReadOnly"; +import { IPAccountImplMerged } from "../abi/ipAccountImpl.abi"; +import { AccessControllerABImerged } from "../abi/accessController.abi"; + +// import { HashZero } from "../constants/common"; + +export class PermissionClient extends PermissionReadOnlyClient { + private readonly wallet: WalletClient; + + constructor(httpClient: AxiosInstance, rpcClient: PublicClient, wallet: WalletClient) { + super(httpClient, rpcClient); + this.wallet = wallet; + } + + /** + * Set Permission based on the specified input + * + * @param request - the request object that contains all data needed to set permission. + * @returns the response object that contains results from the set permission. + */ + public async setPermission(request: setPermissionsRequest): Promise { + try { + const IPAccountConfig = { + abi: IPAccountImplMerged, + address: getAddress(request.ipAsset), + }; + const accessController = getAddress( + process.env.ACCESS_CONTROLLER || process.env.NEXT_PUBLIC_ACCESS_CONTROLLER || "", + ); //to + const { request: call } = await this.rpcClient.simulateContract({ + ...IPAccountConfig, + functionName: "execute", + args: [ + accessController, + 0, + encodeFunctionData({ + abi: AccessControllerABImerged, + functionName: "setPermission", + args: [ + getAddress(request.ipAsset), // 0x Address + getAddress(request.signer), // 0x Address + getAddress(request.to), // 0x Address + request.func as Hex, // bytes4 + request.permission, // uint8 + ], + }), + ], + account: this.wallet.account, + }); + + const txHash = await this.wallet.writeContract(call); + // TODO: the emit event doesn't return anything + // if (request.txOptions?.waitForTransaction) { + // await waitTxAndFilterLog(this.rpcClient, txHash, { + // ...AccessControllerConfig, + // eventName: "PermissionSet", + // }); + // return { txHash: txHash }; + // } else { + return { txHash: txHash }; + // } + } catch (error) { + handleError(error, "Failed to set permissions"); + } + } +} diff --git a/packages/core-sdk/src/resources/permissionReadOnly.ts b/packages/core-sdk/src/resources/permissionReadOnly.ts new file mode 100644 index 00000000..2991a62a --- /dev/null +++ b/packages/core-sdk/src/resources/permissionReadOnly.ts @@ -0,0 +1,58 @@ +import { AxiosInstance } from "axios"; +import { PublicClient } from "viem"; + +import { + GetPermissionRequest, + GetPermissionResponse, + ListPermissionsRequest, + ListPermissionsResponse, +} from "../types/resources/permission"; +import { handleError } from "../utils/errors"; +// import { isIntegerString } from "../utils/utils"; + +/** + * IPAssetReadOnlyClient allows you to view and search IP Assets on Story Protocol. + */ +export class PermissionReadOnlyClient { + protected readonly httpClient: AxiosInstance; + protected readonly rpcClient: PublicClient; + + constructor(httpClient: AxiosInstance, rpcClient: PublicClient) { + this.httpClient = httpClient; + this.rpcClient = rpcClient; + } + + /** + * Get permission based on based on the specified IP id. + * + * @param request - the request object for getting an IP Asset. + * @returns the response object the contains the fetched IP Asset. + */ + public async get(request: GetPermissionRequest): Promise { + try { + // if (!(request.permissionId)) { + // throw new Error( + // `Invalid permissionId. Must be an integer. But get: ${request.permissionId}`, + // ); + // } + const response = await this.httpClient.get(`/permissions/${request.permissionId}`); + return response.data as GetPermissionResponse; + } catch (error: unknown) { + handleError(error, "Failed to get IP account"); + } + } + + /** + * List IP accounts. + * + * @returns the response object that contains results from listing query. + */ + public async list(request?: ListPermissionsRequest): Promise { + try { + const response = await this.httpClient.post(`/permissions`, request || {}); + return response.data as ListPermissionsResponse; + } catch (error) { + handleError(error, "Failed to list IP Asset."); + } + } +} diff --git a/packages/core-sdk/src/types/client.ts b/packages/core-sdk/src/types/client.ts index 49223654..bb3a9f2a 100644 --- a/packages/core-sdk/src/types/client.ts +++ b/packages/core-sdk/src/types/client.ts @@ -1,17 +1,23 @@ -import { IPAccountClient } from "../resources/ipAccount"; import { TaggingClient } from "../resources/tagging"; import { ModuleReadOnlyClient } from "../resources/moduleReadOnly"; +import { IPAssetClient } from "../resources/ipAsset"; +import { IPAssetReadOnlyClient } from "../resources/ipAssetReadOnly"; +import { PermissionClient } from "../resources/permission"; +import { PermissionReadOnlyClient } from "../resources/permissionReadOnly"; import { TransactionClient } from "../resources/transaction"; import { TransactionReadOnlyClient } from "../resources/transactionReadOnly"; import { PlatformClient } from "../utils/platform"; export interface ReadOnlyClient { + ipAsset: IPAssetReadOnlyClient; + permission: PermissionReadOnlyClient; transaction: TransactionReadOnlyClient; module: ModuleReadOnlyClient; } export interface Client { - ipAccount: IPAccountClient; + ipAsset: IPAssetClient; + permission: PermissionClient; transaction: TransactionClient; platform: PlatformClient; tagging: TaggingClient; diff --git a/packages/core-sdk/src/types/resources/accessControl.ts b/packages/core-sdk/src/types/resources/accessControl.ts deleted file mode 100644 index 1dedb5ba..00000000 --- a/packages/core-sdk/src/types/resources/accessControl.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { TxOptions } from "../options"; - -export type setPermissionsRequest = { - ipAccount: string; - signer: string; - to: string; - func: string; - permission: number; - txOptions?: TxOptions; -}; - -export type setPermissionsResponse = { - txHash: string; -}; diff --git a/packages/core-sdk/src/types/resources/ipAccount.ts b/packages/core-sdk/src/types/resources/ipAsset.ts similarity index 82% rename from packages/core-sdk/src/types/resources/ipAccount.ts rename to packages/core-sdk/src/types/resources/ipAsset.ts index 04c006b1..c5909b01 100644 --- a/packages/core-sdk/src/types/resources/ipAccount.ts +++ b/packages/core-sdk/src/types/resources/ipAsset.ts @@ -76,39 +76,42 @@ export type ListIPOrgResponse = { ipOrgs: IPOrg[]; }; +// ----------------------------------------------------- // IPAccountRegistry -export type IpAccount = { - IpId: string; +// ----------------------------------------------------- +export type IpAsset = { + id: string; + ipId: string; + chainId: number; + tokenContract: string; + tokenId: number; + metadataResolverAddress: string; }; -export type GetIpAccountRequest = { +export type GetIpAssetRequest = { ipId: string; - - // chainId: string; - // tokenContractAddress: string; - // tokenId: string; }; -export type GetIpAccountResponse = { - ipAccount: IpAccount; +export type GetIpAssetResponse = { + data: IpAsset; }; -export type ListIpAccountRequest = { +export type ListIpAssetRequest = { options?: QueryOptions; }; -export type ListIpAccountResponse = { - data: IpAccount[]; +export type ListIpAssetResponse = { + data: IpAsset[]; }; -export type RegisterIpAccountRequest = { +export type RegisterIpAssetRequest = { chainId: string; tokenContractAddress: string; tokenId: string; txOptions?: TxOptions; }; -export type RegisterIpAccountResponse = { +export type RegisterIpAssetResponse = { txHash: string; ipAccountId?: string; }; diff --git a/packages/core-sdk/src/types/resources/permission.ts b/packages/core-sdk/src/types/resources/permission.ts new file mode 100644 index 00000000..0321fa1b --- /dev/null +++ b/packages/core-sdk/src/types/resources/permission.ts @@ -0,0 +1,41 @@ +import { QueryOptions, TxOptions } from "../options"; + +export type setPermissionsRequest = { + ipAsset: string; + signer: string; + to: string; + func: string; + permission: number; + txOptions?: TxOptions; +}; + +export type Permission = { + id: string; + ipAccount: string; + permission: string; + signer: string; + to: string; + func: string; + blockTimestamp: string; + blockNumber: string; +}; + +export type setPermissionsResponse = { + txHash: string; +}; + +export type GetPermissionRequest = { + permissionId: string; +}; + +export type GetPermissionResponse = { + data: Permission; +}; + +export type ListPermissionsRequest = { + options: QueryOptions; +}; + +export type ListPermissionsResponse = { + data: Permission[]; +}; diff --git a/packages/core-sdk/test/integration/accessControl.test.ts b/packages/core-sdk/test/integration/accessControl.test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/core-sdk/test/integration/accessControlReadOnly.test.ts b/packages/core-sdk/test/integration/accessControlReadOnly.test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/core-sdk/test/integration/ipAccountReadOnly.test.ts b/packages/core-sdk/test/integration/ipAccountReadOnly.test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/core-sdk/test/integration/ipAccount.test.ts b/packages/core-sdk/test/integration/ipAsset.test.ts similarity index 54% rename from packages/core-sdk/test/integration/ipAccount.test.ts rename to packages/core-sdk/test/integration/ipAsset.test.ts index ad454cb8..d2db6941 100644 --- a/packages/core-sdk/test/integration/ipAccount.test.ts +++ b/packages/core-sdk/test/integration/ipAsset.test.ts @@ -1,15 +1,16 @@ import { expect } from "chai"; import { StoryClient, StoryConfig, Client } from "../../src"; -import { sepolia, goerli } from "viem/chains"; +import { sepolia } from "viem/chains"; import { Hex, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; -describe("IP Account Functions", () => { +describe.skip("IP Asset Functions", () => { let client: Client; let senderAddress: string; before(function () { const config: StoryConfig = { + chain: sepolia, transport: http(process.env.RPC_PROVIDER_URL), account: privateKeyToAccount((process.env.WALLET_PRIVATE_KEY || "0x") as Hex), }; @@ -18,33 +19,11 @@ describe("IP Account Functions", () => { client = StoryClient.newClient(config); }); - describe.skip("Create IP Asset", async function () { + describe("Create IP Asset", async function () { it("should not throw error when creating an IP Asset", async () => { - const waitForTransaction: boolean = true; + const waitForTransaction: boolean = false; const response = await expect( - client.ipAccount.registerRootIp({ - policyId: "0", - tokenContractAddress: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", - tokenId: "3", - txOptions: { - waitForTransaction: waitForTransaction, - }, - }), - ).to.not.be.rejected; - - expect(response.txHash).to.be.a("string"); - expect(response.txHash).not.empty; - - if (waitForTransaction) { - expect(response.ipAccountId).to.be.a("string"); - expect(response.ipAccountId).not.empty; - } - }); - - it("should not throw error when creating an IP Asset with contentHash (SHA256)", async () => { - const waitForTransaction: boolean = true; - const response = await expect( - client.ipAccount.registerRootIp({ + client.ipAsset.registerRootIp({ policyId: "0", tokenContractAddress: "0x1daAE3197Bc469Cb97B917aa460a12dD95c6627c", tokenId: "3", diff --git a/packages/core-sdk/test/integration/ipAssetReadOnly.test.ts b/packages/core-sdk/test/integration/ipAssetReadOnly.test.ts new file mode 100644 index 00000000..4bee3d2e --- /dev/null +++ b/packages/core-sdk/test/integration/ipAssetReadOnly.test.ts @@ -0,0 +1,70 @@ +import { expect } from "chai"; +import { StoryClient, StoryReadOnlyConfig, ReadOnlyClient } from "../../src"; +import { IpAsset, ListIpAssetRequest } from "../../src/types/resources/ipAsset"; + +describe("IPAsset client integration tests", function () { + let client: ReadOnlyClient; + + before(async function () { + const config: StoryReadOnlyConfig = {}; + client = StoryClient.newReadOnlyClient(config); + }); + + describe("List IPAssets", async function () { + it("should return array of IPAssets", async function () { + const req = { + options: { + limit: 10, + offset: 0, + }, + } as ListIpAssetRequest; + + const response = await client.ipAsset.list(req); + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectIPAssetFields(response.data[0]); + }); + + it("should return a list of ipAssets successfully without options", async function () { + const response = await client.ipAsset.list(); + + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectIPAssetFields(response.data[0]); + }); + + it("should return a list of ipAssets if the options are invalid", async function () { + const options = { + options: {}, + } as ListIpAssetRequest; + const response = await client.ipAsset.list(options); + + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectIPAssetFields(response.data[0]); + }); + }); + + describe("Get IPAsset", async function () { + it("should return IP Asset from request ipId", async function () { + const response = await client.ipAsset.get({ + ipId: (process.env.TEST_IP_ID as string) || "0x06cb17d43f16ad5cc3cd7757296fa87ce7ac741d", + }); + + expect(response).to.have.property("data"); + expectIPAssetFields(response.data); + }); + }); + + function expectIPAssetFields(ipAsset: IpAsset) { + expect(ipAsset).to.have.property("id"); + expect(ipAsset).to.have.property("ipId"); + expect(ipAsset).to.have.property("chainId"); + expect(ipAsset).to.have.property("tokenContract"); + expect(ipAsset).to.have.property("tokenId"); + expect(ipAsset).to.have.property("metadataResolverAddress"); + } +}); diff --git a/packages/core-sdk/test/integration/permission.test.ts b/packages/core-sdk/test/integration/permission.test.ts new file mode 100644 index 00000000..606517f9 --- /dev/null +++ b/packages/core-sdk/test/integration/permission.test.ts @@ -0,0 +1,44 @@ +import { expect } from "chai"; +import { StoryClient, StoryConfig, Client, AddressZero } from "../../src"; +import { sepolia } from "viem/chains"; +import { Hex, http } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; + +describe("Permission Functions", () => { + let client: Client; + let senderAddress: string; + + before(function () { + const config: StoryConfig = { + chain: sepolia, + transport: http(process.env.RPC_PROVIDER_URL), + account: privateKeyToAccount((process.env.WALLET_PRIVATE_KEY || "0x") as Hex), + }; + + senderAddress = config.account.address; + client = StoryClient.newClient(config); + }); + + describe("Set Permission", async function () { + it("should not throw error when setting permission", async () => { + const waitForTransaction: boolean = false; + + // TODO: this test is failing because only the IPAccount/IPAsset owner can set permission for the IPAccount. (wrong wallet) + const response = await expect( + client.permission.setPermission({ + ipAsset: "0x0F710802c59255110874c58d9051e545f6e75D96", + signer: "0x9A3A5EdDDFEe1E3A1BBef6Fdf0850B10D4979405", + to: "0x32f0471E404096B978248d0ECE3A8998D87a4b67", + func: "0x00000000", + permission: 1, + txOptions: { + waitForTransaction: waitForTransaction, + }, + }), + ).to.not.be.rejected; + + expect(response.txHash).to.be.a("string"); + expect(response.txHash).not.empty; + }); + }); +}); diff --git a/packages/core-sdk/test/integration/permissionReadOnly.test.ts b/packages/core-sdk/test/integration/permissionReadOnly.test.ts new file mode 100644 index 00000000..40841d68 --- /dev/null +++ b/packages/core-sdk/test/integration/permissionReadOnly.test.ts @@ -0,0 +1,81 @@ +import { expect } from "chai"; +import { + StoryClient, + StoryReadOnlyConfig, + ReadOnlyClient, + ListTransactionRequest, + ResourceType, + Transaction, +} from "../../src"; +import { ListPermissionsRequest, Permission } from "../../src/types/resources/permission"; + +describe("Permission client integration tests", function () { + let client: ReadOnlyClient; + + before(async function () { + const config: StoryReadOnlyConfig = {}; + client = StoryClient.newReadOnlyClient(config); + }); + + describe("List Permissions", async function () { + it("should return array of permissions", async function () { + const req = { + options: { + limit: 10, + offset: 0, + }, + } as ListPermissionsRequest; + + const response = await client.permission.list(req); + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectPermissionFields(response.data[0]); + }); + + it("should return a list of permissions successfully without options", async function () { + const response = await client.permission.list(); + + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectPermissionFields(response.data[0]); + }); + + it("should return a list of permissions if the options are invalid", async function () { + const options = { + options: {}, + } as ListPermissionsRequest; + const response = await client.permission.list(options); + + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectPermissionFields(response.data[0]); + }); + }); + + describe("Get Permission", async function () { + it("should return permission from request permission id", async function () { + const response = await client.permission.get({ + permissionId: + (process.env.TEST_PERMISSION_ID as string) || + "0x06cb17d43f16ad5cc3cd7757296fa87ce7ac741d-0x6c88f438cbfd9866dcd067ffe18b951f19b968da-0x0baa92f82d8992ff152047f29084079c263be7f7-0xa2b4192f", + }); + + expect(response).to.have.property("data"); + expectPermissionFields(response.data); + }); + }); + + function expectPermissionFields(permission: Permission) { + expect(permission).to.have.property("id"); + expect(permission).to.have.property("ipAccount"); + expect(permission).to.have.property("permission"); + expect(permission).to.have.property("signer"); + expect(permission).to.have.property("to"); + expect(permission).to.have.property("func"); + expect(permission).to.have.property("blockTimestamp"); + expect(permission).to.have.property("blockNumber"); + } +}); diff --git a/packages/core-sdk/test/integration/platform.test.ts b/packages/core-sdk/test/integration/platform.test.ts index 8aef2fc9..5aca9ff3 100644 --- a/packages/core-sdk/test/integration/platform.test.ts +++ b/packages/core-sdk/test/integration/platform.test.ts @@ -5,7 +5,7 @@ import { goerli } from "viem/chains"; import { Hex, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; -describe("Platform client integration tests", () => { +describe.skip("Platform client integration tests", () => { let client: Client; before(() => { global.FileReader = createFileReaderMock( diff --git a/packages/core-sdk/test/unit/resources/accessControlReadOnly.test.ts b/packages/core-sdk/test/unit/resources/accessControlReadOnly.test.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/core-sdk/test/unit/resources/ipAccountReadOnly.test.ts b/packages/core-sdk/test/unit/resources/ipAccountReadOnly.test.ts deleted file mode 100644 index e68069b2..00000000 --- a/packages/core-sdk/test/unit/resources/ipAccountReadOnly.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { expect } from "chai"; -import { AxiosInstance } from "axios"; -import { createMock } from "../testUtils"; -import * as sinon from "sinon"; -import { IPAccountReadOnlyClient } from "../../../src"; -import chai from "chai"; -import chaiAsPromised from "chai-as-promised"; -import { PublicClient } from "viem"; - -chai.use(chaiAsPromised); - -// describe("Test IpAccountReadOnlyClient", function () { -// let ipAccountClient: IPAccountReadOnlyClient; -// let axiosMock: AxiosInstance; -// let rpcMock: PublicClient; - -// beforeEach(function () { -// axiosMock = createMock(); -// rpcMock = createMock(); -// ipAccountClient = new IPAccountReadOnlyClient(axiosMock, rpcMock); -// }); - -// afterEach(function () { -// sinon.restore(); -// }); - -// describe("Test ipAccountClient.get", function () { -// it("should return Account when the franchise id is valid", async function () { -// const expectedAccount = { -// id: "1", -// name: "The Empire Strikes Back", -// ipOrgId: "0xB32BdE3fBfddAd30a8d824178F00F0adB43DF2e7", -// owner: "0x4f9693ac46f2c7e2f48dd14d8fe1ab44192cd57d", -// metadataUrl: "https://arweave.net/R7-xPDAMqOhUSw3CM_UwXI7zdpQkzCCCUq3smzxyAaU", -// createdAt: "2023-11-14T00:29:13Z", -// txHash: "0x00a1a14e0193144e1d7024428ee242c44e5cacdbd7458c629d17c6366f6c5cb6", -// }; -// axiosMock.get = sinon.stub().returns({ -// data: { -// ipAccount: expectedAccount, -// }, -// }); - -// const response = await ipAccountClient.get({ -// ipAccountId: "7", -// }); -// expect(response.ipAccount).to.deep.equal(expectedAccount); -// }); - -// it("should throw error", async function () { -// axiosMock.get = sinon.stub().rejects(new Error("http 500")); -// await expect( -// ipAccountClient.get({ -// ipAccountId: "7", -// }), -// ).to.be.rejectedWith("http 500"); -// }); - -// it("should throw error if Account id is invalid", async function () { -// axiosMock.get = sinon.stub().rejects(new Error("http 500")); -// await expect( -// ipAccountClient.get({ -// ipAccountId: "fake ip Account id", -// }), -// ).to.be.rejectedWith("fake ip Account id"); -// }); -// }); - -// describe("Test ipAccountClient.list", async function () { -// const ipAccountMock = { -// id: "1", -// name: "The Empire Strikes Back", -// ipOrgId: "0xB32BdE3fBfddAd30a8d824178F00F0adB43DF2e7", -// owner: "0x4f9693ac46f2c7e2f48dd14d8fe1ab44192cd57d", -// metadataUrl: "https://arweave.net/R7-xPDAMqOhUSw3CM_UwXI7zdpQkzCCCUq3smzxyAaU", -// createdAt: "2023-11-14T00:29:13Z", -// txHash: "0x00a1a14e0193144e1d7024428ee242c44e5cacdbd7458c629d17c6366f6c5cb6", -// }; - -// const mockResponse = sinon.stub().returns({ -// data: { -// ipAccounts: [ipAccountMock], -// }, -// }); - -// it("should return ipAccounts on a successful query", async function () { -// axiosMock.post = mockResponse; -// const response = await ipAccountClient.list({ -// ipOrgId: "7", -// }); - -// expect(response.ipAccounts[0]).to.deep.equal(ipAccountMock); -// }); - -// it("should return ipAccounts without the request object", async function () { -// axiosMock.post = mockResponse; -// const response = await ipAccountClient.list(); - -// expect(response.ipAccounts[0]).to.deep.equal(ipAccountMock); -// }); - -// it("should throw error", async function () { -// axiosMock.post = sinon.stub().rejects(new Error("HTTP 500")); -// await expect( -// ipAccountClient.list({ -// ipOrgId: "abc", -// }), -// ).to.be.rejectedWith("HTTP 500"); -// }); -// }); -// }); diff --git a/packages/core-sdk/test/unit/resources/ipAccount.test.ts b/packages/core-sdk/test/unit/resources/ipAsset.test.ts similarity index 97% rename from packages/core-sdk/test/unit/resources/ipAccount.test.ts rename to packages/core-sdk/test/unit/resources/ipAsset.test.ts index 323cc797..0342c78b 100644 --- a/packages/core-sdk/test/unit/resources/ipAccount.test.ts +++ b/packages/core-sdk/test/unit/resources/ipAsset.test.ts @@ -2,15 +2,15 @@ import { expect } from "chai"; import { AxiosInstance } from "axios"; import { createMock } from "../testUtils"; import * as sinon from "sinon"; -import { IPAccountClient, AddressZero } from "../../../src"; +import { IPAssetClient, AddressZero } from "../../../src"; import chai from "chai"; import chaiAsPromised from "chai-as-promised"; import { PublicClient, WalletClient, Account } from "viem"; chai.use(chaiAsPromised); -describe("Test IpAccountClient", function () { - let ipAccountClient: IPAccountClient; +describe("Test IpAssetClient", function () { + let ipAccountClient: IPAssetClient; let axiosMock: AxiosInstance; let rpcMock: PublicClient; let walletMock: WalletClient; @@ -22,7 +22,7 @@ describe("Test IpAccountClient", function () { const accountMock = createMock(); accountMock.address = "0x73fcb515cee99e4991465ef586cfe2b072ebb512"; walletMock.account = accountMock; - ipAccountClient = new IPAccountClient(axiosMock, rpcMock, walletMock); + ipAccountClient = new IPAssetClient(axiosMock, rpcMock, walletMock); }); afterEach(function () { diff --git a/packages/core-sdk/test/unit/resources/ipAssetReadOnly.test.ts b/packages/core-sdk/test/unit/resources/ipAssetReadOnly.test.ts new file mode 100644 index 00000000..0a462b21 --- /dev/null +++ b/packages/core-sdk/test/unit/resources/ipAssetReadOnly.test.ts @@ -0,0 +1,99 @@ +import { expect } from "chai"; +import { AxiosInstance } from "axios"; +import { createMock } from "../testUtils"; +import * as sinon from "sinon"; +import { IPAssetReadOnlyClient } from "../../../src"; +import chai from "chai"; +import chaiAsPromised from "chai-as-promised"; +import { PublicClient } from "viem"; + +chai.use(chaiAsPromised); + +describe("Test IpAssetReadOnlyClient", function () { + let ipAssetClient: IPAssetReadOnlyClient; + let axiosMock: AxiosInstance; + let rpcMock: PublicClient; + + beforeEach(function () { + axiosMock = createMock(); + rpcMock = createMock(); + ipAssetClient = new IPAssetReadOnlyClient(axiosMock, rpcMock); + }); + + afterEach(function () { + sinon.restore(); + }); + + describe("Test ipAssetClient.get", function () { + it("should return Account when the ipId is valid", async function () { + const expectedAccount = { + id: "0x6c4c9e252ed8196a261f7c1c4258f707f5268045", + ipId: "0x6c4c9e252ed8196a261f7c1c4258f707f5268045", + chainId: "11155111", + tokenContract: "0x1daae3197bc469cb97b917aa460a12dd95c6627c", + tokenId: "3", + metadataResolverAddress: "0x6c88f438cbfd9866dcd067ffe18b951f19b968da", + }; + axiosMock.get = sinon.stub().returns({ + data: expectedAccount, + }); + + const response = await ipAssetClient.get({ + ipId: "0x6c4c9e252ed8196a261f7c1c4258f707f5268045", + }); + expect(response).to.deep.equal(expectedAccount); + }); + + it("should throw error", async function () { + axiosMock.get = sinon.stub().rejects(new Error("http 500")); + await expect( + ipAssetClient.get({ + ipId: "0x6c4c9e252ed8196a261f7c1c4258f707f5268045", + }), + ).to.be.rejectedWith("http 500"); + }); + + it("should throw error if Account id is invalid", async function () { + axiosMock.get = sinon.stub().rejects(new Error("http 500")); + await expect( + ipAssetClient.get({ + ipId: "fake ip Account id", + }), + ).to.be.rejectedWith("fake ip Account id"); + }); + }); + + describe("Test ipAssetClient.list", async function () { + const ipAssetMock = { + id: "0x6c4c9e252ed8196a261f7c1c4258f707f5268045", + ipId: "0x6c4c9e252ed8196a261f7c1c4258f707f5268045", + chainId: "11155111", + tokenContract: "0x1daae3197bc469cb97b917aa460a12dd95c6627c", + tokenId: "3", + metadataResolverAddress: "0x6c88f438cbfd9866dcd067ffe18b951f19b968da", + }; + + const mockResponse = sinon.stub().returns({ + data: { data: [ipAssetMock] }, + }); + + it("should return ipAsset on a successful query", async function () { + axiosMock.post = mockResponse; + const response = await ipAssetClient.list(); + + expect(response.data[0]).to.deep.equal(ipAssetMock); + }); + + it("should return ipAsset without the request object", async function () { + axiosMock.post = mockResponse; + const response = await ipAssetClient.list(); + + expect(response.data[0]).to.deep.equal(ipAssetMock); + }); + + it("should throw error", async function () { + axiosMock.post = sinon.stub().rejects(new Error("HTTP 500")); + await expect(ipAssetClient.list()).to.be.rejectedWith("HTTP 500"); + }); + }); +}); diff --git a/packages/core-sdk/test/unit/resources/accessControl.test.ts b/packages/core-sdk/test/unit/resources/permission.test.ts similarity index 85% rename from packages/core-sdk/test/unit/resources/accessControl.test.ts rename to packages/core-sdk/test/unit/resources/permission.test.ts index 29ed8af8..9095121d 100644 --- a/packages/core-sdk/test/unit/resources/accessControl.test.ts +++ b/packages/core-sdk/test/unit/resources/permission.test.ts @@ -2,15 +2,15 @@ import { expect } from "chai"; import { AxiosInstance } from "axios"; import { createMock } from "../testUtils"; import * as sinon from "sinon"; -import { AccessControlClient, AddressZero } from "../../../src"; +import { PermissionClient, AddressZero } from "../../../src"; import chai from "chai"; import chaiAsPromised from "chai-as-promised"; import { PublicClient, WalletClient, Account } from "viem"; chai.use(chaiAsPromised); -describe("Test AccessControl", function () { - let accessControlClient: AccessControlClient; +describe("Test Permission", function () { + let permissionClient: PermissionClient; let axiosMock: AxiosInstance; let rpcMock: PublicClient; let walletMock: WalletClient; @@ -22,25 +22,25 @@ describe("Test AccessControl", function () { const accountMock = createMock(); accountMock.address = "0x73fcb515cee99e4991465ef586cfe2b072ebb512"; walletMock.account = accountMock; - accessControlClient = new AccessControlClient(axiosMock, rpcMock, walletMock); + permissionClient = new PermissionClient(axiosMock, rpcMock, walletMock); }); afterEach(function () { sinon.restore(); }); - describe("Test accessControl.setPermission", async function () { + describe("Test permission.setPermission", async function () { it("should not throw error when setting permission", async function () { const txHash = "0x129f7dd802200f096221dd89d5b086e4bd3ad6eafb378a0c75e3b04fc375f997"; rpcMock.readContract = sinon.stub().resolves(AddressZero); rpcMock.simulateContract = sinon.stub().resolves({ request: null }); walletMock.writeContract = sinon.stub().resolves(txHash); - const res = await accessControlClient.setPermission({ - ipAccount: AddressZero, + const res = await permissionClient.setPermission({ + ipAsset: AddressZero, signer: AddressZero, to: AddressZero, - func: AddressZero, + func: "0x00000000", permission: 0, txOptions: { waitForTransaction: false, @@ -56,11 +56,11 @@ describe("Test AccessControl", function () { rpcMock.simulateContract = sinon.stub().resolves({ request: null }); walletMock.writeContract = sinon.stub().resolves(txHash); - const res = await accessControlClient.setPermission({ - ipAccount: AddressZero, + const res = await permissionClient.setPermission({ + ipAsset: AddressZero, signer: AddressZero, to: AddressZero, - func: AddressZero, + func: "0x00000000", permission: 0, txOptions: { waitForTransaction: false, @@ -95,8 +95,8 @@ describe("Test AccessControl", function () { // ], }); - // const res = await accessControlClient.setPermission({ - // ipAccount: AddressZero, + // const res = await PermissionClient.setPermission({ + // ipAsset: AddressZero, // signer: AddressZero, // to: AddressZero, // func: AddressZero, @@ -113,11 +113,11 @@ describe("Test AccessControl", function () { rpcMock.simulateContract = sinon.stub().resolves({ request: null }); walletMock.writeContract = sinon.stub().rejects(new Error("http 500")); await expect( - accessControlClient.setPermission({ - ipAccount: AddressZero, + permissionClient.setPermission({ + ipAsset: AddressZero, signer: AddressZero, to: AddressZero, - func: AddressZero, + func: "0x00000000", permission: 0, txOptions: { waitForTransaction: false, @@ -133,8 +133,8 @@ describe("Test AccessControl", function () { walletMock.writeContract = sinon.stub().resolves(txHash); await expect( - accessControlClient.setPermission({ - ipAccount: AddressZero, + permissionClient.setPermission({ + ipAsset: AddressZero, signer: AddressZero, to: AddressZero, func: AddressZero, diff --git a/packages/core-sdk/test/unit/resources/permissionReadOnly.test.ts b/packages/core-sdk/test/unit/resources/permissionReadOnly.test.ts new file mode 100644 index 00000000..0aa9cfae --- /dev/null +++ b/packages/core-sdk/test/unit/resources/permissionReadOnly.test.ts @@ -0,0 +1,105 @@ +import { expect } from "chai"; +import { AxiosInstance } from "axios"; +import { createMock } from "../testUtils"; +import * as sinon from "sinon"; +import { PermissionReadOnlyClient } from "../../../src"; +import chai from "chai"; +import chaiAsPromised from "chai-as-promised"; +import { PublicClient } from "viem"; + +chai.use(chaiAsPromised); + +describe("Test PermissionReadOnlyClient", function () { + let permissionClient: PermissionReadOnlyClient; + let axiosMock: AxiosInstance; + let rpcMock: PublicClient; + + beforeEach(function () { + axiosMock = createMock(); + rpcMock = createMock(); + permissionClient = new PermissionReadOnlyClient(axiosMock, rpcMock); + }); + + afterEach(function () { + sinon.restore(); + }); + + describe("Test permissionClient.get", function () { + it("should return permission", async function () { + const expectedPermission = { + id: "0x06cb17d43f16ad5cc3cd7757296fa87ce7ac741d-0x6c88f438cbfd9866dcd067ffe18b951f19b968da-0x0baa92f82d8992ff152047f29084079c263be7f7-0xa2b4192f", + ipAccount: "0x06cb17d43f16ad5cc3cd7757296fa87ce7ac741d", + permission: "1", + signer: "0x0baa92f82d8992ff152047f29084079c263be7f7", + to: "0x6c88f438cbfd9866dcd067ffe18b951f19b968da", + func: "0xa2b4192f", + blockTimestamp: "1706139240", + blockNumber: "5148052", + }; + axiosMock.get = sinon.stub().returns({ + data: expectedPermission, + }); + + const response = await permissionClient.get({ + permissionId: + "0x06cb17d43f16ad5cc3cd7757296fa87ce7ac741d-0x6c88f438cbfd9866dcd067ffe18b951f19b968da-0x0baa92f82d8992ff152047f29084079c263be7f7-0xa2b4192f", + }); + expect(response).to.deep.equal(expectedPermission); + }); + + it("should throw error", async function () { + axiosMock.get = sinon.stub().rejects(new Error("http 500")); + await expect( + permissionClient.get({ + permissionId: + "0x06cb17d43f16ad5cc3cd7757296fa87ce7ac741d-0x6c88f438cbfd9866dcd067ffe18b951f19b968da-0x0baa92f82d8992ff152047f29084079c263be7f7-0xa2b4192f", + }), + ).to.be.rejectedWith("http 500"); + }); + + it("should throw error if permission id is invalid", async function () { + axiosMock.get = sinon.stub().rejects(new Error("http 500")); + await expect( + permissionClient.get({ + permissionId: "fake permission id", + }), + ).to.be.rejectedWith("Failed to get IP account: http 500"); + }); + }); + + describe("Test permissionClient.list", async function () { + const permissionMock = { + id: "0x06cb17d43f16ad5cc3cd7757296fa87ce7ac741d-0x6c88f438cbfd9866dcd067ffe18b951f19b968da-0x0baa92f82d8992ff152047f29084079c263be7f7-0xa2b4192f", + ipAccount: "0x06cb17d43f16ad5cc3cd7757296fa87ce7ac741d", + permission: "1", + signer: "0x0baa92f82d8992ff152047f29084079c263be7f7", + to: "0x6c88f438cbfd9866dcd067ffe18b951f19b968da", + func: "0xa2b4192f", + blockTimestamp: "1706139240", + blockNumber: "5148052", + }; + + const mockResponse = sinon.stub().returns({ + data: { data: [permissionMock] }, + }); + + it("should return permission on a successful query", async function () { + axiosMock.post = mockResponse; + const response = await permissionClient.list(); + + expect(response.data[0]).to.deep.equal(permissionMock); + }); + + it("should return permission without the request object", async function () { + axiosMock.post = mockResponse; + const response = await permissionClient.list(); + + expect(response.data[0]).to.deep.equal(permissionMock); + }); + + it("should throw error", async function () { + axiosMock.post = sinon.stub().rejects(new Error("HTTP 500")); + await expect(permissionClient.list()).to.be.rejectedWith("HTTP 500"); + }); + }); +});