Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] add ipAccountRegistryABI #42

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/core-sdk/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ FRANCHISE_REGISTRY_CONTRACT =
RELATIONSHIP_MODULE_CONTRACT =
COLLECT_MODULE_CONTRACT =
LICENSING_MODULE_CONTRACT =
IP_ACCOUNT_REGISTRY =

# TEST CONFIGs
RPC_PROVIDER_URL =
Expand Down
14 changes: 14 additions & 0 deletions packages/core-sdk/src/abi/accessController.abi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { formatAbi } from "abitype";
import { getAddress } from "viem";

import AccessControllerABI from "./json/AccessController.abi";

export const AccessControllerRaw = AccessControllerABI;
export const AccessControllerReadable = formatAbi(AccessControllerRaw);

export const AccessControllerConfig = {
abi: AccessControllerRaw,
address: getAddress(
process.env.ACCESS_CONTROLLER || process.env.NEXT_PUBLIC_ACCESS_CONTROLLER || "",
),
};
19 changes: 19 additions & 0 deletions packages/core-sdk/src/abi/ipAccountRegistry.abi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { formatAbi } from "abitype";
import { getAddress } from "viem";
import * as dotenv from "dotenv";

import IPAccountRegistryABI from "./json/IIPAccountRegistry.abi";

if (typeof process !== "undefined") {
dotenv.config();
}

export const IPAccountRegistryRaw = IPAccountRegistryABI;
export const IPAccountRegistryReadable = formatAbi(IPAccountRegistryRaw);

export const IPAccountRegistryConfig = {
abi: IPAccountRegistryRaw,
address: getAddress(
process.env.IP_ACCOUNT_REGISTRY || process.env.NEXT_PUBLIC_IP_ACCOUNT_REGISTRY || "",
),
};
37 changes: 37 additions & 0 deletions packages/core-sdk/src/abi/json/IIPAccountRegistry.abi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,41 @@ export default [
stateMutability: "view",
type: "function",
},
{
anonymous: false,
inputs: [
{
indexed: true,
internalType: "address",
name: "account",
type: "address",
},
{
indexed: true,
internalType: "address",
name: "implementation",
type: "address",
},
{
indexed: true,
internalType: "uint256",
name: "chainId",
type: "uint256",
},
{
indexed: false,
internalType: "address",
name: "tokenContract",
type: "address",
},
{
indexed: false,
internalType: "uint256",
name: "tokenId",
type: "uint256",
},
],
name: "IPAccountRegistered",
type: "event",
},
] as const;
14 changes: 14 additions & 0 deletions packages/core-sdk/src/abi/licenseRegistry.abi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { formatAbi } from "abitype";
import { getAddress } from "viem";

import LicenseRegistryABI from "./json/LicenseRegistry.abi";

export const LicenseRegistryRaw = LicenseRegistryABI;
export const LicenseRegistryReadable = formatAbi(LicenseRegistryRaw);

export const LicenseRegistryConfig = {
abi: LicenseRegistryRaw,
address: getAddress(
process.env.LICENSE_REGISTRY || process.env.NEXT_PUBLIC_LICENSE_REGISTRY || "",
),
};
12 changes: 12 additions & 0 deletions packages/core-sdk/src/abi/moduleRegistry.abi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { formatAbi } from "abitype";
import { getAddress } from "viem";

import ModuleRegistryABI from "./json/ModuleRegistry.abi";

export const ModuleRegistryRaw = ModuleRegistryABI;
export const ModuleRegistryReadable = formatAbi(ModuleRegistryRaw);

export const ModuleRegistryConfig = {
abi: ModuleRegistryRaw,
address: getAddress(process.env.MODULE_REGISTRY || process.env.NEXT_PUBLIC_MODULE_REGISTRY || ""),
};
14 changes: 14 additions & 0 deletions packages/core-sdk/src/abi/registrationModule.abi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { formatAbi } from "abitype";
import { getAddress } from "viem";

import RegistrationModuleABI from "./json/RegistrationModule.abi";

export const RegistrationModuleRaw = RegistrationModuleABI;
export const RegistrationModuleReadable = formatAbi(RegistrationModuleRaw);

export const RegistrationModuleConfig = {
abi: RegistrationModuleRaw,
address: getAddress(
process.env.REGISTRATION_MODULE || process.env.NEXT_PUBLIC_REGISTRATION_MODULE || "",
),
};
12 changes: 12 additions & 0 deletions packages/core-sdk/src/abi/taggingModule.abi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { formatAbi } from "abitype";
import { getAddress } from "viem";

import TaggingModuleABI from "./json/TaggingModule.abi";

export const TaggingModuleRaw = TaggingModuleABI;
export const TaggingModuleReadable = formatAbi(TaggingModuleRaw);

export const TaggingModuleConfig = {
abi: TaggingModuleRaw,
address: getAddress(process.env.TAGGING_MODULE || process.env.NEXT_PUBLIC_TAGGING_MODULE || ""),
};
13 changes: 13 additions & 0 deletions packages/core-sdk/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ 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";

if (typeof process !== "undefined") {
dotenv.config();
Expand All @@ -23,6 +25,7 @@ export class StoryClient {
private readonly rpcClient: PublicClient;
private readonly wallet?: WalletClient;

private _ipAccount: IPAccountClient | IPAccountReadOnlyClient | null = null;
private _transaction: TransactionClient | TransactionReadOnlyClient | null = null;
private _platform: PlatformClient | null = null;

Expand Down Expand Up @@ -80,6 +83,16 @@ export class StoryClient {
return new StoryClient(config, false) as Client;
}

public get ipAccount(): IPAccountClient | IPAccountReadOnlyClient {
if (this._ipAccount === null) {
this._ipAccount = this.isReadOnly
? new IPAccountReadOnlyClient(this.httpClient, this.rpcClient)
: new IPAccountClient(this.httpClient, this.rpcClient, this.wallet!);
}

return this._ipAccount;
}

/**
* Getter for the transaction client. The client is lazily created when
* this method is called.
Expand Down
5 changes: 5 additions & 0 deletions packages/core-sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ 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 type { StoryConfig, StoryReadOnlyConfig } from "./types/config";
export type { Client, ReadOnlyClient } from "./types/client";
export type { Hex, TypedData } from "./types/common";
Expand Down
53 changes: 53 additions & 0 deletions packages/core-sdk/src/resources/accessControl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
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<setPermissionsResponse> {
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");
}
}
}
15 changes: 15 additions & 0 deletions packages/core-sdk/src/resources/accessControlReadOnly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
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;
}
}
139 changes: 139 additions & 0 deletions packages/core-sdk/src/resources/ipAccount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import { AxiosInstance } from "axios";
import { PublicClient, WalletClient, getAddress } from "viem";

// import { handleError } from "../utils/errors";
import { IPAccountReadOnlyClient } from "./ipAccountReadOnly";
import { handleError } from "../utils/errors";
import { IPAccountRegistryConfig } from "../abi/ipAccountRegistry.abi";
import {
RegisterDerivativeIpRequest,
RegisterDerivativeIpResponse,
RegisterRootIpRequest,
RegisterRootIpResponse,
addPolicyRequest,
addPolicyResponse,
// addPolicyToIpRequest,
// addPolicyToIpResponse,
} from "../types/resources/ipAccount";
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 {
private readonly wallet: WalletClient;

constructor(httpClient: AxiosInstance, rpcClient: PublicClient, wallet: WalletClient) {
super(httpClient, rpcClient);
this.wallet = wallet;
}

/**
* Register a root IP on Story Protocol based on the specified input asset data.
*
* @param request - the request object that contains all data needed to register a root IP.
* @returns the response object that contains results from the IP creation.
*/
public async registerRootIp(request: RegisterRootIpRequest): Promise<RegisterRootIpResponse> {
try {
const { request: call } = await this.rpcClient.simulateContract({
...RegistrationModuleConfig,
functionName: "registerRootIp",
args: [
parseToBigInt(request.policyId),
getAddress(request.tokenContractAddress), // 0x Address
parseToBigInt(request.tokenId),
],
});

const txHash = await this.wallet.writeContract(call);
if (request.txOptions?.waitForTransaction) {
const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, {
...IPAccountRegistryConfig,
eventName: "IPAccountRegistered",
});
return { txHash: txHash, ipAccountId: targetLog?.args.account.toString() };
} else {
return { txHash: txHash };
}
} catch (error) {
handleError(error, "Failed to register root IP");
}
}

/**
* Register a derivative IP on Story Protocol based on the specified input asset data.
*
* @param request - the request object that contains all data needed to register a derivative IP.
* @returns the response object that contains results from the IP creation.
*/
public async registerDerivativeIp(
request: RegisterDerivativeIpRequest,
): Promise<RegisterDerivativeIpResponse> {
try {
const { request: call } = await this.rpcClient.simulateContract({
...RegistrationModuleConfig,
functionName: "registerDerivativeIp",
args: [
parseToBigInt(request.licenseId),
getAddress(request.tokenContractAddress), // 0x Address
parseToBigInt(request.tokenId),
request.ipName,
request.ipDescription,
getAddress(request.hash), // Byte32
],
});

const txHash = await this.wallet.writeContract(call);
if (request.txOptions?.waitForTransaction) {
const targetLog = await waitTxAndFilterLog(this.rpcClient, txHash, {
...IPAccountRegistryConfig,
eventName: "IPAccountRegistered",
});
return { txHash: txHash, ipAccountId: targetLog?.args.account.toString() };
} else {
return { txHash: txHash };
}
} catch (error) {
handleError(error, "Failed to register derivative IP");
}
}

// TODO: move to License resource
public async createPolicy(request: addPolicyRequest): Promise<addPolicyResponse> {
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");
}
}

// TODO: move to License resource
// public async addPolicyToIp(request: addPolicyToIpRequest): Promise<addPolicyToIpResponse> {
// // TODO: use getIpAccount to get the ipId
// }
}
Loading
Loading