Skip to content

Commit

Permalink
add tagging module with integration tests (#48)
Browse files Browse the repository at this point in the history
* add tagging module
  • Loading branch information
DonFungible authored Jan 27, 2024
1 parent 48d3e28 commit d53145e
Show file tree
Hide file tree
Showing 12 changed files with 478 additions and 12 deletions.
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

0 comments on commit d53145e

Please sign in to comment.