Skip to main content
Glama
voteTool.ts4.82 kB
/// <reference types="vitest/importMeta" /> import { StructuredTool } from "langchain/tools"; import { z } from "zod"; import { OraichainAgentKit } from "@oraichain/agent-kit"; import { makeSignBytes } from "@cosmjs/proto-signing"; /** * A tool for voting on governance proposals on the Oraichain network. * This tool creates and signs a transaction that allows users to cast their vote on active proposals. * * @remarks * The tool uses the Cosmos SDK governance module's MsgVote message type. * The fee for the transaction is automatically calculated by the chain. * * @example * ```typescript * const input = { * voterAddress: "orai1...", * proposalId: "1", * option: "VOTE_OPTION_YES", * publicKey: "base64EncodedPublicKey" * }; * const result = await voteTool.invoke(input); * ``` */ export class VoteTool extends StructuredTool { name = "vote"; description = `Vote on a governance proposal on Oraichain. Inputs: voterAddress: string - The address of the voter proposalId: string - The ID of the proposal to vote on option: string - The voting option (VOTE_OPTION_YES, VOTE_OPTION_NO, VOTE_OPTION_NO_WITH_VETO, VOTE_OPTION_ABSTAIN) publicKey: string - The voter's public key for signing `; schema = z.object({ voterAddress: z.string().describe("The address of the voter"), proposalId: z.string().describe("The ID of the proposal to vote on"), option: z.string().describe("The voting option"), publicKey: z.string().describe("The voter's public key for signing"), }); constructor(private readonly oraichainKit: OraichainAgentKit) { super(); } protected async _call(input: z.infer<typeof this.schema>): Promise<string> { try { const signDoc = await this.oraichainKit.buildSignDoc( input.voterAddress, input.publicKey, [ { typeUrl: "/cosmos.gov.v1beta1.MsgVote", value: { voter: input.voterAddress, proposalId: input.proposalId, option: input.option, }, }, ], "auto", "" ); return JSON.stringify({ status: "success", data: { signDoc: Buffer.from(makeSignBytes(signDoc)).toString("base64"), }, }); } catch (error: any) { return JSON.stringify({ status: "error", message: error.message, code: error.code || "UNKNOWN_ERROR", }); } } } if (import.meta.vitest) { const { describe, it, expect, vi } = import.meta.vitest; vi.mock("@cosmjs/proto-signing", () => ({ makeSignBytes: vi.fn().mockReturnValue(new Uint8Array([1, 2, 3])), })); describe("VoteTool", () => { const mockBuildSignDoc = vi.fn(); const mockOraichainKit = { buildSignDoc: mockBuildSignDoc, } as unknown as OraichainAgentKit; const tool = new VoteTool(mockOraichainKit); it("should successfully create a vote transaction", async () => { const input = { voterAddress: "orai1...", proposalId: "1", option: "VOTE_OPTION_YES", publicKey: "base64PublicKey", }; const mockSignDoc = { /* mock sign doc structure */ }; mockBuildSignDoc.mockResolvedValueOnce(mockSignDoc); const result = await tool.invoke(input); const parsedResult = JSON.parse(result); expect(parsedResult.status).toBe("success"); expect(parsedResult.data.signDoc).toBe("AQID"); // base64 of [1,2,3] expect(mockBuildSignDoc).toHaveBeenCalledWith( input.voterAddress, input.publicKey, [ { typeUrl: "/cosmos.gov.v1beta1.MsgVote", value: { voter: input.voterAddress, proposalId: input.proposalId, option: input.option, }, }, ], "auto", "" ); }); it("should handle invalid input", async () => { const input = { // Missing required fields voterAddress: "orai1...", }; try { await tool.invoke(input); } catch (error) { expect(error.message).toContain( "Received tool input did not match expected schema" ); } }); it("should handle buildSignDoc errors", async () => { const input = { voterAddress: "orai1...", proposalId: "1", option: "VOTE_OPTION_YES", publicKey: "base64PublicKey", }; const errorMessage = "Failed to build sign doc"; mockBuildSignDoc.mockRejectedValueOnce(new Error(errorMessage)); const result = await tool.invoke(input); const parsedResult = JSON.parse(result); expect(parsedResult.status).toBe("error"); expect(parsedResult.message).toBe(errorMessage); }); }); }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/oraichain/orai-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server