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

add tagging module with integration tests #48

Merged
merged 9 commits into from
Jan 27, 2024
Merged
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
9 changes: 6 additions & 3 deletions .github/workflows/build-and-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ on:
sha:
required: true
type: string
ENVIRONMENT:
ENVIRONMENT:
required: true
type: string
secrets:
Expand All @@ -16,6 +16,8 @@ on:
required: true
REGISTRATION_MODULE:
required: true
TAGGING_MODULE:
required: true
LICENSE_REGISTRY:
required: true
ACCESS_CONTROLLER:
Expand All @@ -37,7 +39,8 @@ jobs:
# TURBO_TEAM: ${{ vars.TURBO_TEAM }}
NEXT_PUBLIC_API_BASE_URL: ${{ secrets.API_BASE_URL }}
NEXT_PUBLIC_IP_ACCOUNT_REGISTRY: ${{ secrets.IP_ACCOUNT_REGISTRY }}
NEXT_PUBLIC_REGISTRATION_MODULE: ${{ secrets.REGISTRATION_MODULE }}
NEXT_PUBLIC_REGISTRATION_MODULE: ${{ secrets.REGISTRATION_MODULE }}
NEXT_PUBLIC_TAGGING_MODULE: ${{ secrets.TAGGING_MODULE }}
NEXT_PUBLIC_LICENSE_REGISTRY: ${{ secrets.LICENSE_REGISTRY }}
NEXT_PUBLIC_ACCESS_CONTROLLER: ${{ secrets.ACCESS_CONTROLLER }}
RPC_PROVIDER_URL: ${{ secrets.RPC_PROVIDER_URL }}
Expand Down Expand Up @@ -69,4 +72,4 @@ jobs:
run: pnpm test

- name: Build
run: pnpm build
run: pnpm build
19 changes: 10 additions & 9 deletions .github/workflows/internal-pr.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Internal PR
name: Internal PR

on:
push:
Expand All @@ -13,15 +13,16 @@ on:
jobs:
build_and_test:
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
uses: ./.github/workflows/build-and-test.yaml
with:
uses: ./.github/workflows/build-and-test.yaml
with:
sha: ${{ github.event.pull_request.head.sha }}
ENVIRONMENT: 'beta-sepolia'
ENVIRONMENT: 'beta-sepolia'
secrets:
IP_ACCOUNT_REGISTRY: ${{ secrets.IP_ACCOUNT_REGISTRY }}
REGISTRATION_MODULE: ${{ secrets.REGISTRATION_MODULE }}
LICENSE_REGISTRY: ${{ secrets.LICENSE_REGISTRY }}
ACCESS_CONTROLLER: ${{ secrets.ACCESS_CONTROLLER }}
API_BASE_URL: ${{ secrets.API_BASE_URL }}
IP_ACCOUNT_REGISTRY: ${{ secrets.IP_ACCOUNT_REGISTRY }}
REGISTRATION_MODULE: ${{ secrets.REGISTRATION_MODULE }}
TAGGING_MODULE: ${{ secrets.TAGGING_MODULE }}
LICENSE_REGISTRY: ${{ secrets.LICENSE_REGISTRY }}
ACCESS_CONTROLLER: ${{ secrets.ACCESS_CONTROLLER }}
API_BASE_URL: ${{ secrets.API_BASE_URL }}
RPC_PROVIDER_URL: ${{ secrets.RPC_PROVIDER_URL }}
WALLET_PRIVATE_KEY: ${{ secrets.WALLET_PRIVATE_KEY }}
19 changes: 19 additions & 0 deletions packages/core-sdk/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ 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";

if (typeof process !== "undefined") {
dotenv.config();
Expand All @@ -30,6 +32,7 @@ export class StoryClient {
private _transaction: TransactionClient | TransactionReadOnlyClient | null = null;
private _platform: PlatformClient | null = null;
private _module: ModuleReadOnlyClient | null = null;
private _tagging: TaggingClient | TaggingReadOnlyClient | null = null;

/**
* @param config - the configuration for the SDK client
Expand Down Expand Up @@ -111,6 +114,22 @@ export class StoryClient {
return this._transaction;
}

/**
* Getter for the tagging client. The client is lazily created when
* this method is called.
*
* @returns the TaggingReadOnlyClient or TaggingClient instance
*/
public get tagging(): TaggingClient | TaggingReadOnlyClient {
if (this._tagging === null) {
this._tagging = this.isReadOnly
? new TaggingReadOnlyClient(this.httpClient, this.rpcClient)
: new TaggingClient(this.httpClient, this.rpcClient, this.wallet!);
}

return this._tagging;
}

/**
* Getter for the platform client. The client is lazily created when
* this method is called.
Expand Down
2 changes: 2 additions & 0 deletions packages/core-sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ 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 type { StoryConfig, StoryReadOnlyConfig } from "./types/config";
Expand All @@ -23,6 +24,7 @@ export type {
ListTransactionResponse,
} from "./types/resources/transaction";

export type { Tag, ListTagRequest, ListTagResponse } from "./types/resources/tagging";
export type {
Module,
GetModuleRequest,
Expand Down
53 changes: 53 additions & 0 deletions packages/core-sdk/src/resources/tagging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { AxiosInstance } from "axios";
import { PublicClient, WalletClient } from "viem";

import { handleError } from "../utils/errors";
import { TaggingModuleConfig } from "../abi/taggingModule.abi";
import { TaggingReadOnlyClient } from "./taggingReadOnly";
import {
RemoveTagRequest,
RemoveTagResponse,
SetTagRequest,
SetTagResponse,
} from "../types/resources/tagging";

export class TaggingClient extends TaggingReadOnlyClient {
private readonly wallet: WalletClient;

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

public async setTag(request: SetTagRequest): Promise<SetTagResponse> {
try {
const { request: call } = await this.rpcClient.simulateContract({
...TaggingModuleConfig,
functionName: "setTag",
args: [request.tag, request.ipId],
});

const txHash = await this.wallet.writeContract(call);

return { txHash: txHash };
} catch (error) {
handleError(error, "Failed to set tag");
}
}

public async removeTag(request: RemoveTagRequest): Promise<RemoveTagResponse> {
try {
const { request: call } = await this.rpcClient.simulateContract({
...TaggingModuleConfig,
functionName: "removeTag",
args: [request.tag, request.ipId],
});

const txHash = await this.wallet.writeContract(call);

return { txHash: txHash };
} catch (error) {
handleError(error, "Failed to remove tag");
}
}
}
50 changes: 50 additions & 0 deletions packages/core-sdk/src/resources/taggingReadOnly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { AxiosInstance } from "axios";
import { PublicClient } from "viem";

import { handleError } from "../utils/errors";
import {
GetTagRequest,
GetTagResponse,
ListTagRequest,
ListTagResponse,
} from "../types/resources/tagging";

/**
* TaggingReadOnlyClient allows you to view and search IP Assets on Story Protocol.
*/
export class TaggingReadOnlyClient {
protected readonly httpClient: AxiosInstance;
protected readonly rpcClient: PublicClient;

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

/**
* Get tags.
*
* @returns the response object that contains results from get tag query.
*/
public async get(request: GetTagRequest): Promise<GetTagResponse> {
try {
const response = await this.httpClient.get(`/tags/${request.id}`);
return response.data as GetTagResponse;
} catch (error) {
handleError(error, "Failed to get tags.");
}
}
/**
* List tags.
*
* @returns the response object that contains results from list tags query.
*/
public async list(request?: ListTagRequest): Promise<ListTagResponse> {
try {
const response = await this.httpClient.post(`/tags`, request || {});
return response.data as ListTagResponse;
} catch (error) {
handleError(error, "Failed to list tags.");
}
}
}
2 changes: 2 additions & 0 deletions packages/core-sdk/src/types/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { IPAccountClient } from "../resources/ipAccount";
import { TaggingClient } from "../resources/tagging";
import { ModuleReadOnlyClient } from "../resources/moduleReadOnly";
import { TransactionClient } from "../resources/transaction";
import { TransactionReadOnlyClient } from "../resources/transactionReadOnly";
Expand All @@ -13,4 +14,5 @@ export interface Client {
ipAccount: IPAccountClient;
transaction: TransactionClient;
platform: PlatformClient;
tagging: TaggingClient;
}
43 changes: 43 additions & 0 deletions packages/core-sdk/src/types/resources/tagging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { QueryOptions, TxOptions } from "../options";

export type Tag = {
id: string;
ipId: `0x${string}`;
tag: string;
};

export type ListTagRequest = {
options?: QueryOptions;
};

export type ListTagResponse = {
data: Tag[];
};

export type GetTagRequest = {
id: string;
};

export type GetTagResponse = {
data: Tag;
};

export type SetTagRequest = {
tag: string;
ipId: `0x${string}`;
txOptions?: TxOptions;
};

export type SetTagResponse = {
txHash: string;
};

export type RemoveTagRequest = {
tag: string;
ipId: `0x${string}`;
txOptions?: TxOptions;
};

export type RemoveTagResponse = {
txHash: string;
};
92 changes: 92 additions & 0 deletions packages/core-sdk/test/integration/tagging.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { expect } from "chai";
import { StoryClient, StoryConfig, Client } from "../../src";
import { Hex, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";

describe("Tagging Functions", () => {
let client: Client;
let senderAddress: string;

before(function () {
const config: StoryConfig = {
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 Tag", async function () {
it("should be able to set tag and wait for transaction", async () => {
const response = await expect(
client.tagging.setTag({
tag: "testTag",
ipId: "0xabCc2421F927c128B9F5a94B612F4541C8E624B6",
txOptions: {
waitForTransaction: true,
},
}),
).to.not.be.rejected;

expect(response.txHash).to.be.a("string");
expect(response.txHash).not.empty;
});

it("should be able to call set tag without waiting for transaction", async () => {
const response = await expect(
client.tagging.setTag({
tag: "testTag",
ipId: "0xabCc2421F927c128B9F5a94B612F4541C8E624B6",
txOptions: {
waitForTransaction: false,
},
}),
).to.not.be.rejected;

expect(response.txHash).to.be.a("string");
expect(response.txHash).not.empty;
});

it("should revert setting tag with incorrect ipId type", async () => {
const waitForTransaction: boolean = true;
await expect(
client.tagging.setTag({
tag: "testTag",
//@ts-expect-error
ipId: 0xabcc2421f927c128b9f5a94b612f4541c8e624b6,
txOptions: {
waitForTransaction: waitForTransaction,
},
}),
).to.be.rejected;
});

it("should be able to remove tag", async () => {
// Set tag first, then remove it
const tagString = "bad-tag69";
const ipId = "0xabCc2421F927c128B9F5a94B612F4541C8E624B6";
const waitForTransaction: boolean = true;
await client.tagging.setTag({
tag: tagString,
ipId: ipId,
txOptions: {
waitForTransaction: waitForTransaction,
},
});

const response = await expect(
client.tagging.removeTag({
tag: tagString,
ipId: ipId,
txOptions: {
waitForTransaction: waitForTransaction,
},
}),
).to.not.be.rejected;

expect(response.txHash).to.be.a("string");
expect(response.txHash).not.empty;
});
});
});
Loading
Loading