From 6455c43218f63547332991d819fb2940f0ea10cb Mon Sep 17 00:00:00 2001 From: Allen Chuang Date: Mon, 29 Jan 2024 16:12:00 -0800 Subject: [PATCH 1/6] initial commit for license and policy resources --- packages/core-sdk/src/client.ts | 25 +++ packages/core-sdk/src/resources/license.ts | 146 ++++++++++++++++++ .../core-sdk/src/resources/licenseReadOnly.ts | 56 +++++++ packages/core-sdk/src/resources/policy.ts | 110 +++++++++++++ .../core-sdk/src/resources/policyReadOnly.ts | 56 +++++++ packages/core-sdk/src/types/client.ts | 8 + .../core-sdk/src/types/resources/ipAsset.ts | 27 ---- .../core-sdk/src/types/resources/license.ts | 67 ++++++++ .../core-sdk/src/types/resources/policy.ts | 67 ++++++++ .../test/integration/licenseReadOnly.test.ts | 77 +++++++++ .../test/integration/policyReadOnly.test.ts | 76 +++++++++ .../unit/resources/licenseReadOnly.test.ts | 0 .../unit/resources/policyReadOnly.test.ts | 0 13 files changed, 688 insertions(+), 27 deletions(-) create mode 100644 packages/core-sdk/src/resources/license.ts create mode 100644 packages/core-sdk/src/resources/licenseReadOnly.ts create mode 100644 packages/core-sdk/src/resources/policy.ts create mode 100644 packages/core-sdk/src/resources/policyReadOnly.ts create mode 100644 packages/core-sdk/src/types/resources/license.ts create mode 100644 packages/core-sdk/src/types/resources/policy.ts create mode 100644 packages/core-sdk/test/integration/licenseReadOnly.test.ts create mode 100644 packages/core-sdk/test/integration/policyReadOnly.test.ts create mode 100644 packages/core-sdk/test/unit/resources/licenseReadOnly.test.ts create mode 100644 packages/core-sdk/test/unit/resources/policyReadOnly.test.ts diff --git a/packages/core-sdk/src/client.ts b/packages/core-sdk/src/client.ts index ae025e4d..eb7b8f7d 100644 --- a/packages/core-sdk/src/client.ts +++ b/packages/core-sdk/src/client.ts @@ -16,6 +16,10 @@ import { IPAssetClient } from "./resources/ipAsset"; import { IPAssetReadOnlyClient } from "./resources/ipAssetReadOnly"; import { PermissionClient } from "./resources/permission"; import { PermissionReadOnlyClient } from "./resources/permissionReadOnly"; +import { LicenseReadOnlyClient } from "./resources/licenseReadOnly"; +import { PolicyReadOnlyClient } from "./resources/policyReadOnly"; +import { LicenseClient } from "./resources/license"; +import { PolicyClient } from "./resources/policy"; if (typeof process !== "undefined") { dotenv.config(); @@ -32,6 +36,8 @@ export class StoryClient { private _ipAccount: IPAssetClient | IPAssetReadOnlyClient | null = null; private _permission: PermissionClient | PermissionReadOnlyClient | null = null; + private _license: LicenseClient | LicenseReadOnlyClient | null = null; + private _policy: PolicyClient | PolicyReadOnlyClient | null = null; private _transaction: TransactionClient | TransactionReadOnlyClient | null = null; private _platform: PlatformClient | null = null; private _module: ModuleReadOnlyClient | null = null; @@ -111,6 +117,25 @@ export class StoryClient { return this._permission; } + public get license(): LicenseClient | LicenseReadOnlyClient { + if (this._license === null) { + this._license = this.isReadOnly + ? new LicenseReadOnlyClient(this.httpClient, this.rpcClient) + : new LicenseClient(this.httpClient, this.rpcClient, this.wallet!); + } + + return this._license; + } + public get policy(): PolicyClient | PolicyReadOnlyClient { + if (this._policy === null) { + this._policy = this.isReadOnly + ? new PolicyReadOnlyClient(this.httpClient, this.rpcClient) + : new PolicyClient(this.httpClient, this.rpcClient, this.wallet!); + } + + return this._policy; + } + /** * Getter for the transaction client. The client is lazily created when * this method is called. diff --git a/packages/core-sdk/src/resources/license.ts b/packages/core-sdk/src/resources/license.ts new file mode 100644 index 00000000..119965cd --- /dev/null +++ b/packages/core-sdk/src/resources/license.ts @@ -0,0 +1,146 @@ +import { AxiosInstance } from "axios"; +import { PublicClient, WalletClient, encodeFunctionData, getAddress } from "viem"; + +import { handleError } from "../utils/errors"; +import { parseToBigInt, waitTxAndFilterLog } from "../utils/utils"; +import { LicenseReadOnlyClient } from "./licenseReadOnly"; +import { IPAccountImplMerged } from "../abi/ipAccountImpl.abi"; +import { LicenseRegistryConfig, LicenseRegistryRaw } from "../abi/licenseRegistry.abi"; +import { + linkIpToParentRequest, + linkIpToParentResponse, + // mintLicenseRequest, + // mintLicenseResponse, + // transferRequest, + // transferResponse, +} from "../types/resources/license"; + +export class LicenseClient extends LicenseReadOnlyClient { + private readonly wallet: WalletClient; + + constructor(httpClient: AxiosInstance, rpcClient: PublicClient, wallet: WalletClient) { + super(httpClient, rpcClient); + this.wallet = wallet; + } + + // public async mintLicense(request: mintLicenseRequest): Promise { + // try { + // const IPAccountConfig = { + // abi: IPAccountImplMerged, + // address: getAddress(request.licensorIp), + // }; + + // const licenseRegistry = getAddress( + // process.env.LICENSE_REGISTRY || process.env.NEXT_PUBLIC_LICENSE_REGISTRY || "", + // ); + + // const { request: call } = await this.rpcClient.simulateContract({ + // ...IPAccountConfig, + // functionName: "execute", + // args: [ + // licenseRegistry, + // 0, + // encodeFunctionData({ + // abi: LicenseRegistryRaw, + // functionName: "mintLicense", + // args: [ + // request.policyId, + // request.licensorIp, + // request.mintAmount, + // request.receiverAddress, + // // TODO: + // ], + // }), + // ], + // account: this.wallet.account, + // }); + // const txHash = await this.wallet.writeContract(call); + // // if (request.txOptions?.waitForTransaction) { + // // const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, { + // // ...LicenseRegistryConfig, + // // eventName: "LicenseMinted", + // // }); + // // return { txHash: txHash, licenseId: targetLog?.args.account.toString() }; + // // } else { + // return { txHash: txHash }; + // // } + // } catch (error) { + // handleError(error, "Failed to mint license"); + // } + // } + + public async linkIpToParent(request: linkIpToParentRequest): Promise { + try { + const IPAccountConfig = { + abi: IPAccountImplMerged, + address: getAddress(request.childIpId), + }; + + const licenseRegistry = getAddress( + process.env.LICENSE_REGISTRY || process.env.NEXT_PUBLIC_LICENSE_REGISTRY || "", + ); + + const { request: call } = await this.rpcClient.simulateContract({ + ...IPAccountConfig, + functionName: "execute", + args: [ + licenseRegistry, + 0, + encodeFunctionData({ + abi: LicenseRegistryRaw, + functionName: "linkIpToParent", + args: [ + parseToBigInt(request.licenseId), + getAddress(request.childIpId), + getAddress(request.holderAddress), + ], + }), + ], + account: this.wallet.account, + }); + const txHash = await this.wallet.writeContract(call); + // if (request.txOptions?.waitForTransaction) { + // const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, { + // ...LicenseRegistryConfig, + // eventName: "LicenseMinted", + // }); + // return { txHash: txHash, licenseId: targetLog?.args.account.toString() }; + // } else { + return { txHash: txHash }; + // } + } catch (error) { + handleError(error, "Failed to mint license"); + } + } + + // public async transfer(request: transferRequest): Promise { + // try { + // const { request: call } = await this.rpcClient.simulateContract({ + // ...LicenseRegistryConfig, + // functionName: "transfer", + // args: [ + // // TODO: format args + // request.operator, + // request.fromAddress, + // request.toAddress, + // request.id, + // request.value, + // ], + // account: this.wallet.account, + // }); + + // const txHash = await this.wallet.writeContract(call); + // // if (request.txOptions?.waitForTransaction) { + // // const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, { + // // ...LicenseRegistryConfig, + // // eventName: "LicenseBurnt", + // // }); + // // return { txHash: txHash, ipAccountId: targetLog?.args.account.toString() }; + // // } else { + // return { txHash: txHash }; + // // } + // } catch (error) { + // handleError(error, "Failed to register root IP"); + // } + // } +} diff --git a/packages/core-sdk/src/resources/licenseReadOnly.ts b/packages/core-sdk/src/resources/licenseReadOnly.ts new file mode 100644 index 00000000..be172f8e --- /dev/null +++ b/packages/core-sdk/src/resources/licenseReadOnly.ts @@ -0,0 +1,56 @@ +import { AxiosInstance } from "axios"; +import { PublicClient } from "viem"; + +import { + GetLicenseRequest, + GetLicenseResponse, + ListLicensesRequest, + ListLicensesResponse, +} from "../types/resources/license"; +import { handleError } from "../utils/errors"; +import { isIntegerString } from "../utils/utils"; + +/** + * LicenseReadOnlyClient allows you to view and search Licenses on Story Protocol. + */ +export class LicenseReadOnlyClient { + protected readonly httpClient: AxiosInstance; + protected readonly rpcClient: PublicClient; + + constructor(httpClient: AxiosInstance, rpcClient: PublicClient) { + this.httpClient = httpClient; + this.rpcClient = rpcClient; + } + + /** + * Get a License based on the specified License ID. + * + * @param request - the request object for getting an License. + * @returns the response object the contains the fetched License. + */ + public async get(request: GetLicenseRequest): Promise { + try { + if (!isIntegerString(request.licenseId)) { + throw new Error(`Invalid license id. Must be an integer. But get: ${request.licenseId}`); + } + const response = await this.httpClient.get(`/licenses/${request.licenseId}`); + return response.data as GetLicenseResponse; + } catch (error: unknown) { + handleError(error, "Failed to get License"); + } + } + + /** + * List Licenses + * + * @returns the response object that contains results from listing query. + */ + public async list(request?: ListLicensesRequest): Promise { + try { + const response = await this.httpClient.post(`/licenses`, request || {}); + return response.data as ListLicensesResponse; + } catch (error) { + handleError(error, "Failed to list Licenses."); + } + } +} diff --git a/packages/core-sdk/src/resources/policy.ts b/packages/core-sdk/src/resources/policy.ts new file mode 100644 index 00000000..a245ba03 --- /dev/null +++ b/packages/core-sdk/src/resources/policy.ts @@ -0,0 +1,110 @@ +import { AxiosInstance } from "axios"; +import { PublicClient, WalletClient, encodeFunctionData, getAddress } from "viem"; + +import { handleError } from "../utils/errors"; +import { LicenseRegistryConfig, LicenseRegistryRaw } from "../abi/licenseRegistry.abi"; +import { + parseToBigInt, + // waitTxAndFilterLog +} from "../utils/utils"; +import { PolicyReadOnlyClient } from "./policyReadOnly"; +import { + addPolicyRequest, + addPolicyResponse, + addPolicyToIpRequest, + addPolicyToIpResponse, +} from "../types/resources/policy"; +import { IPAccountImplMerged } from "../abi/ipAccountImpl.abi"; + +export class PolicyClient extends PolicyReadOnlyClient { + private readonly wallet: WalletClient; + + constructor(httpClient: AxiosInstance, rpcClient: PublicClient, wallet: WalletClient) { + super(httpClient, rpcClient); + this.wallet = wallet; + } + + /** + * Create a policy on Story Protocol based on the specified params. + * + * @param request - the request object that contains all data needed to register a policy. + * @returns the response object that contains results from the policy creation. + */ + 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)), + }, + ], + }); + + const txHash = await this.wallet.writeContract(call); + + // if (request.txOptions?.waitForTransaction) { + // const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, { + // ...LicenseRegistryConfig, + // // TODO: need PolicyCreated ABI + // eventName: "PolicyCreated", + // }); + // 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 { + try { + const IPAccountConfig = { + abi: IPAccountImplMerged, + address: getAddress(request.ipId), + }; + const licenseRegistry = getAddress( + process.env.LICENSE_REGISTRY || process.env.NEXT_PUBLIC_LICENSE_REGISTRY || "", + ); + const { request: call } = await this.rpcClient.simulateContract({ + ...IPAccountConfig, + functionName: "execute", + args: [ + licenseRegistry, + 0, + encodeFunctionData({ + abi: LicenseRegistryRaw, + functionName: "addPolicyToIp", + args: [ + getAddress(request.ipId), // 0x Address + parseToBigInt(request.policyId), + ], + }), + ], + 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 add policy to IP"); + } + // TODO: use getIpAccount to get the ipId + } +} diff --git a/packages/core-sdk/src/resources/policyReadOnly.ts b/packages/core-sdk/src/resources/policyReadOnly.ts new file mode 100644 index 00000000..a776a44d --- /dev/null +++ b/packages/core-sdk/src/resources/policyReadOnly.ts @@ -0,0 +1,56 @@ +import { AxiosInstance } from "axios"; +import { PublicClient } from "viem"; + +import { + GetPolicyRequest, + GetPolicyResponse, + ListPoliciesRequest, + ListPoliciesResponse, +} from "../types/resources/policy"; +import { handleError } from "../utils/errors"; +import { isIntegerString } from "../utils/utils"; + +/** + * PolicyReadOnlyClient allows you to view and search policy on Story Protocol. + */ +export class PolicyReadOnlyClient { + protected readonly httpClient: AxiosInstance; + protected readonly rpcClient: PublicClient; + + constructor(httpClient: AxiosInstance, rpcClient: PublicClient) { + this.httpClient = httpClient; + this.rpcClient = rpcClient; + } + + /** + * Get a Policy based on the specified Policy ID. + * + * @param request - the request object for getting an Policy. + * @returns the response object the contains the fetched Policy. + */ + public async get(request: GetPolicyRequest): Promise { + try { + if (!isIntegerString(request.policyId)) { + throw new Error(`Invalid Policy id. Must be an integer. But get: ${request.policyId}`); + } + const response = await this.httpClient.get(`/policies/${request.policyId}`); + return response.data as GetPolicyResponse; + } catch (error: unknown) { + handleError(error, "Failed to get Policy"); + } + } + + /** + * List Policies + * + * @returns the response object that contains results from listing query. + */ + public async list(request?: ListPoliciesRequest): Promise { + try { + const response = await this.httpClient.post(`/policies`, request || {}); + return response.data as ListPoliciesResponse; + } catch (error) { + handleError(error, "Failed to list policy."); + } + } +} diff --git a/packages/core-sdk/src/types/client.ts b/packages/core-sdk/src/types/client.ts index bb3a9f2a..7eba8173 100644 --- a/packages/core-sdk/src/types/client.ts +++ b/packages/core-sdk/src/types/client.ts @@ -7,10 +7,16 @@ import { PermissionReadOnlyClient } from "../resources/permissionReadOnly"; import { TransactionClient } from "../resources/transaction"; import { TransactionReadOnlyClient } from "../resources/transactionReadOnly"; import { PlatformClient } from "../utils/platform"; +import { LicenseClient } from "../resources/license"; +import { LicenseReadOnlyClient } from "../resources/licenseReadOnly"; +import { PolicyClient } from "../resources/policy"; +import { PolicyReadOnlyClient } from "../resources/policyReadOnly"; export interface ReadOnlyClient { ipAsset: IPAssetReadOnlyClient; permission: PermissionReadOnlyClient; + license: LicenseReadOnlyClient; + policy: PolicyReadOnlyClient; transaction: TransactionReadOnlyClient; module: ModuleReadOnlyClient; } @@ -18,6 +24,8 @@ export interface ReadOnlyClient { export interface Client { ipAsset: IPAssetClient; permission: PermissionClient; + license: LicenseClient; + policy: PolicyClient; transaction: TransactionClient; platform: PlatformClient; tagging: TaggingClient; diff --git a/packages/core-sdk/src/types/resources/ipAsset.ts b/packages/core-sdk/src/types/resources/ipAsset.ts index c5909b01..dfe20236 100644 --- a/packages/core-sdk/src/types/resources/ipAsset.ts +++ b/packages/core-sdk/src/types/resources/ipAsset.ts @@ -143,30 +143,3 @@ export type RegisterDerivativeIpResponse = { txHash: string; ipAccountId?: string; }; - -// LicenseRegistry -export type addPolicyRequest = { - frameworkId: string; - mintingParamValues: string[]; - activationParamValues: string[]; - needsActivation: boolean; - linkParentParamValues: string[]; - // ipId: string; - // policyId: string; - txOptions?: TxOptions; -}; - -export type addPolicyToIpRequest = { - ipId: string; - policyId: string; -}; - -export type addPolicyResponse = { - txHash: string; - policyId?: number; - isNew?: boolean; -}; - -export type addPolicyToIpResponse = { - indexOnIpId: number; -}; diff --git a/packages/core-sdk/src/types/resources/license.ts b/packages/core-sdk/src/types/resources/license.ts new file mode 100644 index 00000000..1845dc1d --- /dev/null +++ b/packages/core-sdk/src/types/resources/license.ts @@ -0,0 +1,67 @@ +import { QueryOptions, TxOptions } from "../options"; + +export type License = { + id: string; + amount: string; + creator: string; + licenseId: string; + receiver: string; + licenseData: Record; +}; + +export type GetLicenseRequest = { + licenseId: string; +}; +export type GetLicenseResponse = { + data: License; +}; +export type ListLicensesRequest = { + options?: QueryOptions; +}; +export type ListLicensesResponse = { + data: License[]; +}; + +export type mintLicenseRequest = { + policyId: string; + licensorIp: string; + mintAmount: string; + receiverAddress: string; + txOptions?: TxOptions; +}; + +export type mintLicenseResponse = { + txHash: string; + // licenseId?: number; + // isNew?: boolean; +}; + +export type linkIpToParentRequest = { + licenseId: string; + childIpId: string; + holderAddress: string; + txOptions?: TxOptions; +}; + +export type linkIpToParentResponse = { + txHash: string; + // licenseId?: number; + // isNew?: boolean; +}; + +export type transferRequest = { + // address indexed _operator, + // address indexed _from, + // address indexed _to, + // uint256 _id, + // uint256 _value + operator: string; + fromAddress: string; + toAddress: string; + id: string; + value: string; +}; + +export type transferResponse = { + txHash?: string; +}; diff --git a/packages/core-sdk/src/types/resources/policy.ts b/packages/core-sdk/src/types/resources/policy.ts new file mode 100644 index 00000000..f7ae1eb2 --- /dev/null +++ b/packages/core-sdk/src/types/resources/policy.ts @@ -0,0 +1,67 @@ +import { QueryOptions, TxOptions } from "../options"; + +export type Term = { + key: string; + value: string; +}; + +export type Policy = { + // id: string; + // creator: string; + // frameworkId: string; + // terms: Term[]; + // url: string; + policyId: string; + creator: string; + frameworkId: string; + blockNumber: string; + blockTimestamp: string; + + // "policyId": "1", + // "creator": "0xb6288e57bf7406b35ab4f70fd1135e907107e386", + // "frameworkId": "1", + // "blockNumber": "5148052", + // blockTimestamp: "1706139240"; +}; + +export type GetPolicyRequest = { + policyId: string; +}; +export type GetPolicyResponse = { + data: Policy; +}; +export type ListPoliciesRequest = { + options?: QueryOptions; +}; +export type ListPoliciesResponse = { + data: Policy[]; +}; + +// LicenseRegistry +export type addPolicyRequest = { + frameworkId: string; + mintingParamValues: string[]; + activationParamValues: string[]; + needsActivation: boolean; + linkParentParamValues: string[]; + // ipId: string; + // policyId: string; + txOptions?: TxOptions; +}; + +export type addPolicyResponse = { + txHash: string; + policyId?: number; + isNew?: boolean; +}; + +export type addPolicyToIpRequest = { + ipId: string; + policyId: string; + txOptions?: TxOptions; +}; + +export type addPolicyToIpResponse = { + // indexOnIpId: number; + txHash: string; +}; diff --git a/packages/core-sdk/test/integration/licenseReadOnly.test.ts b/packages/core-sdk/test/integration/licenseReadOnly.test.ts new file mode 100644 index 00000000..b2bbb58f --- /dev/null +++ b/packages/core-sdk/test/integration/licenseReadOnly.test.ts @@ -0,0 +1,77 @@ +import { expect } from "chai"; +import { + StoryClient, + StoryReadOnlyConfig, + ReadOnlyClient, + ListTransactionRequest, + ResourceType, + Transaction, +} from "../../src"; +import { ListLicensesRequest, License } from "../../src/types/resources/license"; + +describe("License client integration tests", function () { + let client: ReadOnlyClient; + + before(async function () { + const config: StoryReadOnlyConfig = {}; + client = StoryClient.newReadOnlyClient(config); + }); + + describe("List Licenses", async function () { + it("should return array of Licenses", async function () { + const req = { + options: { + limit: 10, + offset: 0, + }, + } as ListLicensesRequest; + + const response = await client.license.list(req); + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectLicenseFields(response.data[0]); + }); + + it("should return a list of Licenses successfully without options", async function () { + const response = await client.license.list(); + + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectLicenseFields(response.data[0]); + }); + + it("should return a list of Licenses if the options are invalid", async function () { + const options = { + options: {}, + } as ListLicensesRequest; + const response = await client.license.list(options); + + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectLicenseFields(response.data[0]); + }); + }); + + describe("Get License", async function () { + it("should return License from request License id", async function () { + const response = await client.license.get({ + licenseId: "1", + }); + + expect(response).to.have.property("data"); + expectLicenseFields(response.data); + }); + }); + + function expectLicenseFields(License: License) { + expect(License).to.have.property("id"); + expect(License).to.have.property("amount"); + expect(License).to.have.property("creator"); + expect(License).to.have.property("licenseId"); + expect(License).to.have.property("receiver"); + expect(License).to.have.property("licenseData"); + } +}); diff --git a/packages/core-sdk/test/integration/policyReadOnly.test.ts b/packages/core-sdk/test/integration/policyReadOnly.test.ts new file mode 100644 index 00000000..d20c8549 --- /dev/null +++ b/packages/core-sdk/test/integration/policyReadOnly.test.ts @@ -0,0 +1,76 @@ +import { expect } from "chai"; +import { + StoryClient, + StoryReadOnlyConfig, + ReadOnlyClient, + ListTransactionRequest, + ResourceType, + Transaction, +} from "../../src"; +import { ListPoliciesRequest, Policy } from "../../src/types/resources/policy"; + +describe("Policy client integration tests", function () { + let client: ReadOnlyClient; + + before(async function () { + const config: StoryReadOnlyConfig = {}; + client = StoryClient.newReadOnlyClient(config); + }); + + describe("List Policies", async function () { + it("should return array of Policies", async function () { + const req = { + options: { + limit: 10, + offset: 0, + }, + } as ListPoliciesRequest; + + const response = await client.policy.list(req); + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectPolicyFields(response.data[0]); + }); + + it("should return a list of Policies successfully without options", async function () { + const response = await client.policy.list(); + + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectPolicyFields(response.data[0]); + }); + + it("should return a list of Policies if the options are invalid", async function () { + const options = { + options: {}, + } as ListPoliciesRequest; + const response = await client.policy.list(options); + + expect(response).to.have.property("data"); + expect(response.data).to.be.an("array"); + expect(response.data.length).to.gt(0); + expectPolicyFields(response.data[0]); + }); + }); + + describe("Get Policy", async function () { + it("should return Policy from request Policy id", async function () { + const response = await client.policy.get({ + policyId: "1", + }); + + expect(response).to.have.property("data"); + expectPolicyFields(response.data); + }); + }); + + function expectPolicyFields(Policy: Policy) { + expect(Policy).to.have.property("policyId"); + expect(Policy).to.have.property("creator"); + expect(Policy).to.have.property("frameworkId"); + expect(Policy).to.have.property("blockNumber"); + expect(Policy).to.have.property("blockTimestamp"); + } +}); diff --git a/packages/core-sdk/test/unit/resources/licenseReadOnly.test.ts b/packages/core-sdk/test/unit/resources/licenseReadOnly.test.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/core-sdk/test/unit/resources/policyReadOnly.test.ts b/packages/core-sdk/test/unit/resources/policyReadOnly.test.ts new file mode 100644 index 00000000..e69de29b From 7b34663abf9f0cbca46483ebd96cee4f1550ed7a Mon Sep 17 00:00:00 2001 From: Allen Chuang Date: Mon, 29 Jan 2024 16:30:08 -0800 Subject: [PATCH 2/6] add readOnly unit test --- packages/core-sdk/src/client.ts | 1 + packages/core-sdk/src/index.ts | 4 + .../unit/resources/licenseReadOnly.test.ts | 99 +++++++++++++++++++ .../unit/resources/permissionReadOnly.test.ts | 2 +- .../unit/resources/policyReadOnly.test.ts | 97 ++++++++++++++++++ 5 files changed, 202 insertions(+), 1 deletion(-) diff --git a/packages/core-sdk/src/client.ts b/packages/core-sdk/src/client.ts index eb7b8f7d..a1d3db23 100644 --- a/packages/core-sdk/src/client.ts +++ b/packages/core-sdk/src/client.ts @@ -126,6 +126,7 @@ export class StoryClient { return this._license; } + public get policy(): PolicyClient | PolicyReadOnlyClient { if (this._policy === null) { this._policy = this.isReadOnly diff --git a/packages/core-sdk/src/index.ts b/packages/core-sdk/src/index.ts index 8929509b..0346a4e6 100644 --- a/packages/core-sdk/src/index.ts +++ b/packages/core-sdk/src/index.ts @@ -11,6 +11,10 @@ export { IPAssetClient } from "./resources/ipAsset"; export { IPAssetReadOnlyClient } from "./resources/ipAssetReadOnly"; export { PermissionClient } from "./resources/permission"; export { PermissionReadOnlyClient } from "./resources/permissionReadOnly"; +export { LicenseClient } from "./resources/license"; +export { LicenseReadOnlyClient } from "./resources/licenseReadOnly"; +export { PolicyClient } from "./resources/policy"; +export { PolicyReadOnlyClient } from "./resources/policyReadOnly"; export type { StoryConfig, StoryReadOnlyConfig } from "./types/config"; export type { Client, ReadOnlyClient } from "./types/client"; diff --git a/packages/core-sdk/test/unit/resources/licenseReadOnly.test.ts b/packages/core-sdk/test/unit/resources/licenseReadOnly.test.ts index e69de29b..4fecda52 100644 --- a/packages/core-sdk/test/unit/resources/licenseReadOnly.test.ts +++ b/packages/core-sdk/test/unit/resources/licenseReadOnly.test.ts @@ -0,0 +1,99 @@ +import { expect } from "chai"; +import { AxiosInstance } from "axios"; +import { createMock } from "../testUtils"; +import * as sinon from "sinon"; +import { LicenseReadOnlyClient } from "../../../src"; +import chai from "chai"; +import chaiAsPromised from "chai-as-promised"; +import { PublicClient } from "viem"; + +chai.use(chaiAsPromised); + +describe("Test LicenseReadOnlyClient", function () { + let licenseClient: LicenseReadOnlyClient; + let axiosMock: AxiosInstance; + let rpcMock: PublicClient; + + beforeEach(function () { + axiosMock = createMock(); + rpcMock = createMock(); + licenseClient = new LicenseReadOnlyClient(axiosMock, rpcMock); + }); + + afterEach(function () { + sinon.restore(); + }); + + describe("Test licenseClient.get", function () { + it("should return License", async function () { + const expectedLicense = { + id: "1", + amount: "2", + creator: "0xb6288e57bf7406b35ab4f70fd1135e907107e386", + licenseId: "1", + receiver: "0xb6288e57bf7406b35ab4f70fd1135e907107e386", + licenseData: {}, + }; + axiosMock.get = sinon.stub().returns({ + data: expectedLicense, + }); + + const response = await licenseClient.get({ + licenseId: "1", + }); + expect(response).to.deep.equal(expectedLicense); + }); + + it("should throw error", async function () { + axiosMock.get = sinon.stub().rejects(new Error("http 500")); + await expect( + licenseClient.get({ + licenseId: "1", + }), + ).to.be.rejectedWith("http 500"); + }); + + it("should throw error if License id is invalid", async function () { + axiosMock.get = sinon.stub().rejects(new Error("http 500")); + await expect( + licenseClient.get({ + licenseId: "fake License id", + }), + ).to.be.rejectedWith("Failed to get License: http 500"); + }); + }); + + describe("Test licenseClient.list", async function () { + const LicenseMock = { + id: "1", + amount: "2", + creator: "0xb6288e57bf7406b35ab4f70fd1135e907107e386", + licenseId: "1", + receiver: "0xb6288e57bf7406b35ab4f70fd1135e907107e386", + licenseData: {}, + }; + + const mockResponse = sinon.stub().returns({ + data: { data: [LicenseMock] }, + }); + + it("should return License on a successful query", async function () { + axiosMock.post = mockResponse; + const response = await licenseClient.list(); + + expect(response.data[0]).to.deep.equal(LicenseMock); + }); + + it("should return License without the request object", async function () { + axiosMock.post = mockResponse; + const response = await licenseClient.list(); + + expect(response.data[0]).to.deep.equal(LicenseMock); + }); + + it("should throw error", async function () { + axiosMock.post = sinon.stub().rejects(new Error("HTTP 500")); + await expect(licenseClient.list()).to.be.rejectedWith("HTTP 500"); + }); + }); +}); diff --git a/packages/core-sdk/test/unit/resources/permissionReadOnly.test.ts b/packages/core-sdk/test/unit/resources/permissionReadOnly.test.ts index 0aa9cfae..09929be3 100644 --- a/packages/core-sdk/test/unit/resources/permissionReadOnly.test.ts +++ b/packages/core-sdk/test/unit/resources/permissionReadOnly.test.ts @@ -63,7 +63,7 @@ describe("Test PermissionReadOnlyClient", function () { permissionClient.get({ permissionId: "fake permission id", }), - ).to.be.rejectedWith("Failed to get IP account: http 500"); + ).to.be.rejectedWith("Failed to get permission: http 500"); }); }); diff --git a/packages/core-sdk/test/unit/resources/policyReadOnly.test.ts b/packages/core-sdk/test/unit/resources/policyReadOnly.test.ts index e69de29b..641a58ab 100644 --- a/packages/core-sdk/test/unit/resources/policyReadOnly.test.ts +++ b/packages/core-sdk/test/unit/resources/policyReadOnly.test.ts @@ -0,0 +1,97 @@ +import { expect } from "chai"; +import { AxiosInstance } from "axios"; +import { createMock } from "../testUtils"; +import * as sinon from "sinon"; +import { PolicyReadOnlyClient } from "../../../src"; +import chai from "chai"; +import chaiAsPromised from "chai-as-promised"; +import { PublicClient } from "viem"; + +chai.use(chaiAsPromised); + +describe("Test PolicyReadOnlyClient", function () { + let policyClient: PolicyReadOnlyClient; + let axiosMock: AxiosInstance; + let rpcMock: PublicClient; + + beforeEach(function () { + axiosMock = createMock(); + rpcMock = createMock(); + policyClient = new PolicyReadOnlyClient(axiosMock, rpcMock); + }); + + afterEach(function () { + sinon.restore(); + }); + + describe("Test policyClient.get", function () { + it("should return Policy", async function () { + const expectedPolicy = { + policyId: "1", + creator: "0xb6288e57bf7406b35ab4f70fd1135e907107e386", + frameworkId: "1", + blockNumber: "5148052", + blockTimestamp: "1706139240", + }; + axiosMock.get = sinon.stub().returns({ + data: expectedPolicy, + }); + + const response = await policyClient.get({ + policyId: "1", + }); + expect(response).to.deep.equal(expectedPolicy); + }); + + it("should throw error", async function () { + axiosMock.get = sinon.stub().rejects(new Error("http 500")); + await expect( + policyClient.get({ + policyId: "1", + }), + ).to.be.rejectedWith("http 500"); + }); + + it("should throw error if Policy id is invalid", async function () { + axiosMock.get = sinon.stub().rejects(new Error("http 500")); + await expect( + policyClient.get({ + policyId: "fake Policy id", + }), + ).to.be.rejectedWith("Failed to get Policy: http 500"); + }); + }); + + describe("Test policyClient.list", async function () { + const PolicyMock = { + policyId: "1", + creator: "0xb6288e57bf7406b35ab4f70fd1135e907107e386", + frameworkId: "1", + blockNumber: "5148052", + blockTimestamp: "1706139240", + }; + + const mockResponse = sinon.stub().returns({ + data: { data: [PolicyMock] }, + }); + + it("should return Policy on a successful query", async function () { + axiosMock.post = mockResponse; + const response = await policyClient.list(); + + expect(response.data[0]).to.deep.equal(PolicyMock); + }); + + it("should return Policy without the request object", async function () { + axiosMock.post = mockResponse; + const response = await policyClient.list(); + + expect(response.data[0]).to.deep.equal(PolicyMock); + }); + + it("should throw error", async function () { + axiosMock.post = sinon.stub().rejects(new Error("HTTP 500")); + await expect(policyClient.list()).to.be.rejectedWith("HTTP 500"); + }); + }); +}); From f3e3e1ce7e07362e13f28c9c91920edc5f8d15a1 Mon Sep 17 00:00:00 2001 From: Allen Chuang Date: Mon, 29 Jan 2024 16:45:15 -0800 Subject: [PATCH 3/6] add client tests --- .../core-sdk/src/abi/taggingModule.abi.ts | 5 ++ packages/core-sdk/src/client.ts | 8 ++-- packages/core-sdk/src/types/client.ts | 2 + packages/core-sdk/test/unit/client.test.ts | 8 ++++ .../core-sdk/test/unit/clientReadOnly.test.ts | 48 +++++++++++++++++++ 5 files changed, 67 insertions(+), 4 deletions(-) diff --git a/packages/core-sdk/src/abi/taggingModule.abi.ts b/packages/core-sdk/src/abi/taggingModule.abi.ts index c3274839..ebbdac4d 100644 --- a/packages/core-sdk/src/abi/taggingModule.abi.ts +++ b/packages/core-sdk/src/abi/taggingModule.abi.ts @@ -1,8 +1,13 @@ import { formatAbi } from "abitype"; import { getAddress } from "viem"; +import * as dotenv from "dotenv"; import TaggingModuleABI from "./json/TaggingModule.abi"; +if (typeof process !== "undefined") { + dotenv.config(); +} + export const TaggingModuleRaw = TaggingModuleABI; export const TaggingModuleReadable = formatAbi(TaggingModuleRaw); diff --git a/packages/core-sdk/src/client.ts b/packages/core-sdk/src/client.ts index a1d3db23..94dce6d7 100644 --- a/packages/core-sdk/src/client.ts +++ b/packages/core-sdk/src/client.ts @@ -34,7 +34,7 @@ export class StoryClient { private readonly rpcClient: PublicClient; private readonly wallet?: WalletClient; - private _ipAccount: IPAssetClient | IPAssetReadOnlyClient | null = null; + private _ipAsset: IPAssetClient | IPAssetReadOnlyClient | null = null; private _permission: PermissionClient | PermissionReadOnlyClient | null = null; private _license: LicenseClient | LicenseReadOnlyClient | null = null; private _policy: PolicyClient | PolicyReadOnlyClient | null = null; @@ -98,13 +98,13 @@ export class StoryClient { } public get ipAsset(): IPAssetClient | IPAssetReadOnlyClient { - if (this._ipAccount === null) { - this._ipAccount = this.isReadOnly + if (this._ipAsset === null) { + this._ipAsset = this.isReadOnly ? new IPAssetReadOnlyClient(this.httpClient, this.rpcClient) : new IPAssetClient(this.httpClient, this.rpcClient, this.wallet!); } - return this._ipAccount; + return this._ipAsset; } public get permission(): PermissionClient | PermissionReadOnlyClient { diff --git a/packages/core-sdk/src/types/client.ts b/packages/core-sdk/src/types/client.ts index 7eba8173..6d048b64 100644 --- a/packages/core-sdk/src/types/client.ts +++ b/packages/core-sdk/src/types/client.ts @@ -11,6 +11,7 @@ import { LicenseClient } from "../resources/license"; import { LicenseReadOnlyClient } from "../resources/licenseReadOnly"; import { PolicyClient } from "../resources/policy"; import { PolicyReadOnlyClient } from "../resources/policyReadOnly"; +import { TaggingReadOnlyClient } from "../resources/taggingReadOnly"; export interface ReadOnlyClient { ipAsset: IPAssetReadOnlyClient; @@ -18,6 +19,7 @@ export interface ReadOnlyClient { license: LicenseReadOnlyClient; policy: PolicyReadOnlyClient; transaction: TransactionReadOnlyClient; + tagging: TaggingReadOnlyClient; module: ModuleReadOnlyClient; } diff --git a/packages/core-sdk/test/unit/client.test.ts b/packages/core-sdk/test/unit/client.test.ts index 3e96b670..0986c5ce 100644 --- a/packages/core-sdk/test/unit/client.test.ts +++ b/packages/core-sdk/test/unit/client.test.ts @@ -43,6 +43,14 @@ describe("Test StoryClient", function () { expect(transaction1).to.be.equal(transaction2); }); }); + + describe("Test platform getter", function () { + it("should return the same platform client when every time it's called", function () { + const platform1 = client.platform; + const platform2 = client.platform; + expect(platform1).to.be.equal(platform2); + }); + }); }); // describe("Test ipOrg getter w/o creating a client", function () { diff --git a/packages/core-sdk/test/unit/clientReadOnly.test.ts b/packages/core-sdk/test/unit/clientReadOnly.test.ts index 244283c1..ce9c555a 100644 --- a/packages/core-sdk/test/unit/clientReadOnly.test.ts +++ b/packages/core-sdk/test/unit/clientReadOnly.test.ts @@ -32,6 +32,54 @@ describe("Test StoryReadOnlyClient", function () { client = StoryClient.newReadOnlyClient({}); }); + describe("Test ipAsset getter", function () { + it("should return the same ipAsset client when every time it's called", function () { + const ipAsset1 = client.ipAsset; + const ipAsset2 = client.ipAsset; + expect(ipAsset1).to.be.equal(ipAsset2); + }); + }); + + describe("Test permission getter", function () { + it("should return the same permission client when every time it's called", function () { + const permission1 = client.permission; + const permission2 = client.permission; + expect(permission1).to.be.equal(permission2); + }); + }); + + describe("Test license getter", function () { + it("should return the same license client when every time it's called", function () { + const license1 = client.license; + const license2 = client.license; + expect(license1).to.be.equal(license2); + }); + }); + + describe("Test policy getter", function () { + it("should return the same policy client when every time it's called", function () { + const policy1 = client.policy; + const policy2 = client.policy; + expect(policy1).to.be.equal(policy2); + }); + }); + + describe("Test tagging getter", function () { + it("should return the same tagging client when every time it's called", function () { + const tagging1 = client.tagging; + const tagging2 = client.tagging; + expect(tagging1).to.be.equal(tagging2); + }); + }); + + describe("Test module getter", function () { + it("should return the same module client when every time it's called", function () { + const module1 = client.module; + const module2 = client.module; + expect(module1).to.be.equal(module2); + }); + }); + describe("Test transactions getter", function () { it("should return the same transaction client when every time it's called", function () { const transaction1 = client.transaction; From 00f36950cee4da78fbb7987e818dd272841ea4c9 Mon Sep 17 00:00:00 2001 From: Allen Chuang Date: Tue, 30 Jan 2024 13:28:33 -0800 Subject: [PATCH 4/6] add new address --- packages/core-sdk/test/integration/permission.test.ts | 5 ++++- packages/core-sdk/test/integration/taggingReadOnly.test.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/core-sdk/test/integration/permission.test.ts b/packages/core-sdk/test/integration/permission.test.ts index 606517f9..672233ac 100644 --- a/packages/core-sdk/test/integration/permission.test.ts +++ b/packages/core-sdk/test/integration/permission.test.ts @@ -28,7 +28,10 @@ describe("Permission Functions", () => { client.permission.setPermission({ ipAsset: "0x0F710802c59255110874c58d9051e545f6e75D96", signer: "0x9A3A5EdDDFEe1E3A1BBef6Fdf0850B10D4979405", - to: "0x32f0471E404096B978248d0ECE3A8998D87a4b67", + to: + (process.env.LICENSE_REGISTRY as string) || + (process.env.NEXT_PUBLIC_LICENSE_REGISTRY as string) || + "0x4B8d88967Fd4f2FFF1c85c74DA20cCcF62Cb6e47", func: "0x00000000", permission: 1, txOptions: { diff --git a/packages/core-sdk/test/integration/taggingReadOnly.test.ts b/packages/core-sdk/test/integration/taggingReadOnly.test.ts index cca45b09..e5dd8303 100644 --- a/packages/core-sdk/test/integration/taggingReadOnly.test.ts +++ b/packages/core-sdk/test/integration/taggingReadOnly.test.ts @@ -31,7 +31,7 @@ describe("Tagging Indexer Functions", () => { it("should be able to get a tag by it's tag id", async () => { const getTagRequest: GetTagRequest = { - id: "0xabcc2421f927c128b9f5a94b612f4541c8e624b6-testTag", + id: "0xeae93c26ec1b50xc4-testTag", }; const response = await client.tagging.get(getTagRequest); From f6bfb649b648c3bb4cf16e42176548c517d681e4 Mon Sep 17 00:00:00 2001 From: Allen Chuang Date: Wed, 31 Jan 2024 12:05:10 -0800 Subject: [PATCH 5/6] remove unused imports --- packages/core-sdk/src/resources/license.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core-sdk/src/resources/license.ts b/packages/core-sdk/src/resources/license.ts index 119965cd..d227f47f 100644 --- a/packages/core-sdk/src/resources/license.ts +++ b/packages/core-sdk/src/resources/license.ts @@ -2,10 +2,10 @@ import { AxiosInstance } from "axios"; import { PublicClient, WalletClient, encodeFunctionData, getAddress } from "viem"; import { handleError } from "../utils/errors"; -import { parseToBigInt, waitTxAndFilterLog } from "../utils/utils"; +import { parseToBigInt } from "../utils/utils"; import { LicenseReadOnlyClient } from "./licenseReadOnly"; import { IPAccountImplMerged } from "../abi/ipAccountImpl.abi"; -import { LicenseRegistryConfig, LicenseRegistryRaw } from "../abi/licenseRegistry.abi"; +import { LicenseRegistryRaw } from "../abi/licenseRegistry.abi"; import { linkIpToParentRequest, linkIpToParentResponse, From 947a5e59941a971b4f53a5e720e3cf948d2cd808 Mon Sep 17 00:00:00 2001 From: Allen Chuang Date: Thu, 1 Feb 2024 01:43:08 -0800 Subject: [PATCH 6/6] fix policy and license fns and update fn signature --- packages/core-sdk/src/resources/license.ts | 93 +++++++++---------- packages/core-sdk/src/resources/policy.ts | 24 ++--- .../core-sdk/src/types/resources/license.ts | 7 +- 3 files changed, 61 insertions(+), 63 deletions(-) diff --git a/packages/core-sdk/src/resources/license.ts b/packages/core-sdk/src/resources/license.ts index d227f47f..ef92815c 100644 --- a/packages/core-sdk/src/resources/license.ts +++ b/packages/core-sdk/src/resources/license.ts @@ -2,15 +2,15 @@ import { AxiosInstance } from "axios"; import { PublicClient, WalletClient, encodeFunctionData, getAddress } from "viem"; import { handleError } from "../utils/errors"; -import { parseToBigInt } from "../utils/utils"; +import { parseToBigInt, waitTxAndFilterLog } from "../utils/utils"; import { LicenseReadOnlyClient } from "./licenseReadOnly"; import { IPAccountImplMerged } from "../abi/ipAccountImpl.abi"; -import { LicenseRegistryRaw } from "../abi/licenseRegistry.abi"; +import { LicenseRegistryConfig, LicenseRegistryRaw } from "../abi/licenseRegistry.abi"; import { linkIpToParentRequest, linkIpToParentResponse, - // mintLicenseRequest, - // mintLicenseResponse, + mintLicenseRequest, + mintLicenseResponse, // transferRequest, // transferResponse, } from "../types/resources/license"; @@ -23,51 +23,50 @@ export class LicenseClient extends LicenseReadOnlyClient { this.wallet = wallet; } - // public async mintLicense(request: mintLicenseRequest): Promise { - // try { - // const IPAccountConfig = { - // abi: IPAccountImplMerged, - // address: getAddress(request.licensorIp), - // }; + public async mintLicense(request: mintLicenseRequest): Promise { + try { + const IPAccountConfig = { + abi: IPAccountImplMerged, + // TODO: find out which ipId to use to call the execute fn + address: getAddress(request.licensorIps[0]), + }; - // const licenseRegistry = getAddress( - // process.env.LICENSE_REGISTRY || process.env.NEXT_PUBLIC_LICENSE_REGISTRY || "", - // ); + const licenseRegistry = getAddress( + process.env.LICENSE_REGISTRY || process.env.NEXT_PUBLIC_LICENSE_REGISTRY || "", + ); - // const { request: call } = await this.rpcClient.simulateContract({ - // ...IPAccountConfig, - // functionName: "execute", - // args: [ - // licenseRegistry, - // 0, - // encodeFunctionData({ - // abi: LicenseRegistryRaw, - // functionName: "mintLicense", - // args: [ - // request.policyId, - // request.licensorIp, - // request.mintAmount, - // request.receiverAddress, - // // TODO: - // ], - // }), - // ], - // account: this.wallet.account, - // }); - // const txHash = await this.wallet.writeContract(call); - // // if (request.txOptions?.waitForTransaction) { - // // const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, { - // // ...LicenseRegistryConfig, - // // eventName: "LicenseMinted", - // // }); - // // return { txHash: txHash, licenseId: targetLog?.args.account.toString() }; - // // } else { - // return { txHash: txHash }; - // // } - // } catch (error) { - // handleError(error, "Failed to mint license"); - // } - // } + const { request: call } = await this.rpcClient.simulateContract({ + ...IPAccountConfig, + functionName: "execute", + args: [ + licenseRegistry, + 0, + encodeFunctionData({ + abi: LicenseRegistryRaw, + functionName: "mintLicense", + args: [ + { policyId: parseToBigInt(request.policyId), licensorIpIds: request.licensorIps }, + parseToBigInt(request.mintAmount), + getAddress(request.receiverAddress), + ], + }), + ], + account: this.wallet.account, + }); + const txHash = await this.wallet.writeContract(call); + if (request.txOptions?.waitForTransaction) { + const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, { + ...LicenseRegistryConfig, + eventName: "LicenseMinted", + }); + return { txHash: txHash, licenseId: targetLog?.args?.licenseId.toString() }; + } else { + return { txHash: txHash }; + } + } catch (error) { + handleError(error, "Failed to mint license"); + } + } public async linkIpToParent(request: linkIpToParentRequest): Promise { try { diff --git a/packages/core-sdk/src/resources/policy.ts b/packages/core-sdk/src/resources/policy.ts index a245ba03..da760af9 100644 --- a/packages/core-sdk/src/resources/policy.ts +++ b/packages/core-sdk/src/resources/policy.ts @@ -3,10 +3,7 @@ import { PublicClient, WalletClient, encodeFunctionData, getAddress } from "viem import { handleError } from "../utils/errors"; import { LicenseRegistryConfig, LicenseRegistryRaw } from "../abi/licenseRegistry.abi"; -import { - parseToBigInt, - // waitTxAndFilterLog -} from "../utils/utils"; +import { parseToBigInt, waitTxAndFilterLog } from "../utils/utils"; import { PolicyReadOnlyClient } from "./policyReadOnly"; import { addPolicyRequest, @@ -93,18 +90,17 @@ export class PolicyClient extends PolicyReadOnlyClient { 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 }; + if (request.txOptions?.waitForTransaction) { + await waitTxAndFilterLog(this.rpcClient, txHash, { + ...LicenseRegistryConfig, + eventName: "PolicyAddedToIpId", + }); + return { txHash: txHash }; + } else { + return { txHash: txHash }; + } } catch (error) { handleError(error, "Failed to add policy to IP"); } - // TODO: use getIpAccount to get the ipId } } diff --git a/packages/core-sdk/src/types/resources/license.ts b/packages/core-sdk/src/types/resources/license.ts index 1845dc1d..c0462b57 100644 --- a/packages/core-sdk/src/types/resources/license.ts +++ b/packages/core-sdk/src/types/resources/license.ts @@ -1,3 +1,5 @@ +import { Address } from "viem"; + import { QueryOptions, TxOptions } from "../options"; export type License = { @@ -24,7 +26,8 @@ export type ListLicensesResponse = { export type mintLicenseRequest = { policyId: string; - licensorIp: string; + licensorIps: Address[]; + mintAmount: string; receiverAddress: string; txOptions?: TxOptions; @@ -32,7 +35,7 @@ export type mintLicenseRequest = { export type mintLicenseResponse = { txHash: string; - // licenseId?: number; + licenseId?: string; // isNew?: boolean; };