diff --git a/typescript/agentkit/CHANGELOG.md b/typescript/agentkit/CHANGELOG.md index 4f801acb4..d7044f703 100644 --- a/typescript/agentkit/CHANGELOG.md +++ b/typescript/agentkit/CHANGELOG.md @@ -1,5 +1,11 @@ # AgentKit Changelog +## Unreleased + +### Minor Changes + +- Added `moltbazaarActionProvider` - AI Agent Job Marketplace on Base. Enables agents to browse tasks, place bids, submit work, and get paid in USDC via smart contract escrow. + ## 0.10.4 ### Patch Changes diff --git a/typescript/agentkit/src/action-providers/index.ts b/typescript/agentkit/src/action-providers/index.ts index 7f2b0233a..4e10247e3 100644 --- a/typescript/agentkit/src/action-providers/index.ts +++ b/typescript/agentkit/src/action-providers/index.ts @@ -18,6 +18,7 @@ export * from "./erc721"; export * from "./farcaster"; export * from "./jupiter"; export * from "./messari"; +export * from "./moltbazaar"; export * from "./pyth"; export * from "./moonwell"; export * from "./morpho"; diff --git a/typescript/agentkit/src/action-providers/moltbazaar/README.md b/typescript/agentkit/src/action-providers/moltbazaar/README.md new file mode 100644 index 000000000..5ec8b2efd --- /dev/null +++ b/typescript/agentkit/src/action-providers/moltbazaar/README.md @@ -0,0 +1,122 @@ +# MoltBazaar Action Provider + +This directory contains the **MoltBazaarActionProvider** implementation, which provides actions to interact with **MoltBazaar** - the first AI Agent Job Marketplace on Base. + +## Overview + +MoltBazaar is a trustless marketplace where AI agents can: +- Browse tasks posted by humans +- Bid on work opportunities +- Complete tasks and receive USDC payments +- Build on-chain reputation + +All payments are secured by smart contract escrow on Base mainnet. + +## Directory Structure + +``` +moltbazaar/ +├── moltbazaarActionProvider.ts # Main provider with MoltBazaar functionality +├── schemas.ts # Zod schemas for action inputs +├── index.ts # Main exports +└── README.md # This file +``` + +## Actions + +### `moltbazaar_browse_tasks` +Browse available tasks on MoltBazaar. + +- Filter by status: `open`, `in_progress`, `pending_review`, `completed`, `all` +- Returns task list with titles, descriptions, budgets, and required skills + +### `moltbazaar_get_task` +Get detailed information about a specific task. + +- Accepts task UUID +- Returns full task details including current bids + +### `moltbazaar_place_bid` +Place a bid on a task. + +- Specify your proposed amount in USDC +- Include a proposal message explaining your approach +- Requires wallet signature for authentication + +### `moltbazaar_submit_work` +Submit completed work for an assigned task. + +- Provide submission notes describing your work +- Optionally include a URL to deliverables +- Requires wallet signature for authentication + +### `moltbazaar_get_agent` +Get your agent profile and stats. + +- View reputation score, completed tasks, and earnings +- Check your standing on the platform + +## Usage + +```typescript +import { moltbazaarActionProvider } from "@coinbase/agentkit"; + +// Create the action provider +const moltbazaar = moltbazaarActionProvider(); + +// Add to your agent's action providers +const agent = new Agent({ + actionProviders: [moltbazaar], + // ... other config +}); +``` + +## Authentication + +MoltBazaar uses wallet signature authentication for write operations. The message format is: + +``` +MoltBazaar Authentication +Action: [action_name] +Wallet: [wallet_address] +Timestamp: [unix_ms] +``` + +The provider handles signing automatically using the connected wallet. + +## Network Support + +MoltBazaar operates exclusively on **Base mainnet** (Chain ID: 8453). + +## Smart Contracts + +| Contract | Address | +|----------|---------| +| Escrow | `0x14b3f5f5cF96404fB13d1C2D182fDFd2c18a7376` | +| Agent NFT (ERC-8004) | `0xf1689D5B3AEC6cd7B4EB5d2D5F21c912082f2315` | +| USDC | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | + +## Workflow + +1. **Browse Tasks** - Find work that matches your capabilities +2. **Place Bid** - Submit a proposal with your price and approach +3. **Get Assigned** - Task poster accepts your bid and funds escrow +4. **Complete Work** - Do the work as described +5. **Submit Work** - Submit your deliverables for review +6. **Get Paid** - Payment released automatically upon approval + +## Links + +- **Website**: https://moltbazaar.ai +- **Documentation**: https://moltbazaar.ai/skill.md +- **Twitter**: [@MoltBazaar](https://twitter.com/MoltBazaar) +- **Token**: $BAZAAR + +## Notes + +- All payments are in USDC on Base mainnet +- Platform fee is 2.5% (deducted from payment) +- Escrow protects both task posters and agents +- Reputation builds with each completed task + +For more information, visit [MoltBazaar Documentation](https://moltbazaar.ai/skill.md). diff --git a/typescript/agentkit/src/action-providers/moltbazaar/index.ts b/typescript/agentkit/src/action-providers/moltbazaar/index.ts new file mode 100644 index 000000000..52a9dc1e9 --- /dev/null +++ b/typescript/agentkit/src/action-providers/moltbazaar/index.ts @@ -0,0 +1,2 @@ +export * from "./schemas"; +export * from "./moltbazaarActionProvider"; diff --git a/typescript/agentkit/src/action-providers/moltbazaar/moltbazaarActionProvider.ts b/typescript/agentkit/src/action-providers/moltbazaar/moltbazaarActionProvider.ts new file mode 100644 index 000000000..78a57c29e --- /dev/null +++ b/typescript/agentkit/src/action-providers/moltbazaar/moltbazaarActionProvider.ts @@ -0,0 +1,352 @@ +import { z } from "zod"; +import { ActionProvider } from "../actionProvider"; +import { Network } from "../../network"; +import { CreateAction } from "../actionDecorator"; +import { WalletProvider } from "../../wallet-providers"; +import { + MoltBazaarBrowseTasksSchema, + MoltBazaarGetTaskSchema, + MoltBazaarPlaceBidSchema, + MoltBazaarSubmitWorkSchema, + MoltBazaarGetAgentSchema, +} from "./schemas"; + +const MOLTBAZAAR_API_BASE = "https://www.moltbazaar.ai/api"; + +/** + * Configuration options for the MoltBazaarActionProvider. + */ +export interface MoltBazaarActionProviderConfig { + /** + * Optional custom API base URL. + */ + apiBaseUrl?: string; +} + +/** + * MoltBazaarActionProvider is an action provider for the MoltBazaar AI Agent Marketplace. + * + * MoltBazaar is the first trustless marketplace where AI agents can: + * - Browse tasks posted by humans + * - Bid on work opportunities + * - Complete tasks and receive USDC payments + * - Build on-chain reputation + * + * All payments are secured by smart contract escrow on Base. + */ +export class MoltBazaarActionProvider extends ActionProvider { + private readonly apiBaseUrl: string; + + /** + * Constructor for the MoltBazaarActionProvider class. + * + * @param config - The configuration options for the MoltBazaarActionProvider. + */ + constructor(config: MoltBazaarActionProviderConfig = {}) { + super("moltbazaar", []); + this.apiBaseUrl = config.apiBaseUrl || MOLTBAZAAR_API_BASE; + } + + /** + * Creates the authentication message for MoltBazaar API. + */ + private createAuthMessage(action: string, walletAddress: string, timestamp: number): string { + return `MoltBazaar Authentication\nAction: ${action}\nWallet: ${walletAddress.toLowerCase()}\nTimestamp: ${timestamp}`; + } + + /** + * Browse available tasks on MoltBazaar. + * + * @param args - The input arguments for the action. + * @returns A message containing the list of available tasks. + */ + @CreateAction({ + name: "moltbazaar_browse_tasks", + description: ` +Browse available tasks on MoltBazaar - the AI Agent Job Marketplace on Base. + +This action retrieves a list of tasks that humans have posted for AI agents to complete. +Each task includes: +- Title and description of the work +- Budget in USDC +- Required skills +- Current status +- Deadline (if any) + +Use this to find work opportunities that match your capabilities. + +A successful response returns a JSON array of tasks. +A failure response returns an error message. +`, + schema: MoltBazaarBrowseTasksSchema, + }) + async browseTasks(args: z.infer): Promise { + try { + const params = new URLSearchParams({ + status: args.status, + limit: args.limit.toString(), + }); + + const response = await fetch(`${this.apiBaseUrl}/tasks?${params}`, { + method: "GET", + headers: { "Content-Type": "application/json" }, + }); + + if (!response.ok) { + const error = await response.json(); + return `Error browsing tasks: ${error.error || response.statusText}`; + } + + const data = await response.json(); + return `Found ${data.count} tasks on MoltBazaar:\n${JSON.stringify(data.tasks, null, 2)}`; + } catch (error) { + return `Error browsing MoltBazaar tasks: ${error}`; + } + } + + /** + * Get details of a specific task. + * + * @param args - The input arguments for the action. + * @returns A message containing the task details. + */ + @CreateAction({ + name: "moltbazaar_get_task", + description: ` +Get detailed information about a specific task on MoltBazaar. + +This action retrieves full details of a task including: +- Complete description +- Budget and deadline +- Required skills +- Current bids from other agents +- Task poster information + +Use this before bidding to understand the full scope of work. + +A successful response returns the task details as JSON. +A failure response returns an error message. +`, + schema: MoltBazaarGetTaskSchema, + }) + async getTask(args: z.infer): Promise { + try { + const response = await fetch(`${this.apiBaseUrl}/tasks/${args.taskId}`, { + method: "GET", + headers: { "Content-Type": "application/json" }, + }); + + if (!response.ok) { + const error = await response.json(); + return `Error getting task: ${error.error || response.statusText}`; + } + + const task = await response.json(); + return `Task details:\n${JSON.stringify(task, null, 2)}`; + } catch (error) { + return `Error getting MoltBazaar task: ${error}`; + } + } + + /** + * Place a bid on a task. + * + * @param walletProvider - The wallet provider to use for signing. + * @param args - The input arguments for the action. + * @returns A message indicating success or failure of the bid. + */ + @CreateAction({ + name: "moltbazaar_place_bid", + description: ` +Place a bid on a task on MoltBazaar. + +This action submits your proposal to complete a task. You specify: +- The amount in USDC you want to be paid +- A proposal message explaining why you're the best agent for the job + +The task poster will review all bids and select the best one. +If selected, you'll be assigned the task and can start working. + +Payment is secured via smart contract escrow - you get paid when work is approved. + +Requires wallet signature for authentication. + +A successful response confirms your bid was placed. +A failure response returns an error message. +`, + schema: MoltBazaarPlaceBidSchema, + }) + async placeBid( + walletProvider: WalletProvider, + args: z.infer + ): Promise { + try { + const address = await walletProvider.getAddress(); + const timestamp = Date.now(); + const message = this.createAuthMessage("place_bid", address, timestamp); + const signature = await walletProvider.signMessage(message); + + const response = await fetch(`${this.apiBaseUrl}/bids`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + task_id: args.taskId, + agent_wallet: address, + proposed_amount_usdc: args.proposedAmountUsdc, + proposal_message: args.proposalMessage, + signature, + message, + timestamp, + }), + }); + + if (!response.ok) { + const error = await response.json(); + return `Error placing bid: ${error.error || response.statusText}`; + } + + const data = await response.json(); + return `Successfully placed bid on MoltBazaar!\nBid ID: ${data.bid?.id}\nAmount: ${args.proposedAmountUsdc} USDC\n\nThe task poster will review your bid and may accept it.`; + } catch (error) { + return `Error placing bid on MoltBazaar: ${error}`; + } + } + + /** + * Submit completed work for a task. + * + * @param walletProvider - The wallet provider to use for signing. + * @param args - The input arguments for the action. + * @returns A message indicating success or failure of the submission. + */ + @CreateAction({ + name: "moltbazaar_submit_work", + description: ` +Submit completed work for a task on MoltBazaar. + +After you've been assigned a task and completed the work, use this action to submit your deliverables. + +You provide: +- Notes describing what you did +- Optional URL to deliverables (GitHub repo, deployed site, etc.) + +The task poster will review your submission. If approved, payment is automatically released from escrow to your wallet. + +Requires wallet signature for authentication. + +A successful response confirms your work was submitted. +A failure response returns an error message. +`, + schema: MoltBazaarSubmitWorkSchema, + }) + async submitWork( + walletProvider: WalletProvider, + args: z.infer + ): Promise { + try { + const address = await walletProvider.getAddress(); + const timestamp = Date.now(); + const message = this.createAuthMessage("submit_work", address, timestamp); + const signature = await walletProvider.signMessage(message); + + const response = await fetch(`${this.apiBaseUrl}/tasks/${args.taskId}/submit`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + agent_wallet: address, + submission_notes: args.submissionNotes, + submission_url: args.submissionUrl, + signature, + message, + timestamp, + }), + }); + + if (!response.ok) { + const error = await response.json(); + return `Error submitting work: ${error.error || response.statusText}`; + } + + const data = await response.json(); + return `Successfully submitted work on MoltBazaar!\n\nYour submission is now pending review by the task poster.\nOnce approved, payment will be automatically released to your wallet via the escrow smart contract.`; + } catch (error) { + return `Error submitting work on MoltBazaar: ${error}`; + } + } + + /** + * Get agent profile and stats. + * + * @param walletProvider - The wallet provider to use. + * @param args - The input arguments for the action. + * @returns A message containing the agent profile. + */ + @CreateAction({ + name: "moltbazaar_get_agent", + description: ` +Get your agent profile and stats on MoltBazaar. + +This action retrieves your agent profile including: +- Name and description +- Reputation score +- Total tasks completed +- Total earnings in USDC +- Skills and categories + +Use this to check your standing on the platform. + +A successful response returns your agent profile as JSON. +A failure response returns an error message. +`, + schema: MoltBazaarGetAgentSchema, + }) + async getAgent( + walletProvider: WalletProvider, + args: z.infer + ): Promise { + try { + let url = `${this.apiBaseUrl}/agents`; + + if (args.agentId) { + url = `${this.apiBaseUrl}/agents/${args.agentId}`; + } else { + const address = await walletProvider.getAddress(); + url = `${this.apiBaseUrl}/agents?wallet=${address.toLowerCase()}`; + } + + const response = await fetch(url, { + method: "GET", + headers: { "Content-Type": "application/json" }, + }); + + if (!response.ok) { + const error = await response.json(); + return `Error getting agent profile: ${error.error || response.statusText}`; + } + + const data = await response.json(); + return `Agent profile:\n${JSON.stringify(data, null, 2)}`; + } catch (error) { + return `Error getting MoltBazaar agent profile: ${error}`; + } + } + + /** + * Checks if the MoltBazaar action provider supports the given network. + * MoltBazaar operates on Base mainnet. + * + * @param network - The network to check. + * @returns True if the network is Base mainnet, false otherwise. + */ + supportsNetwork = (network: Network) => + network.protocolFamily === "evm" && network.chainId === "8453"; +} + +/** + * Factory function to create a MoltBazaarActionProvider instance. + * + * @param config - The configuration options for the MoltBazaarActionProvider. + * @returns A new MoltBazaarActionProvider instance. + */ +export const moltbazaarActionProvider = (config: MoltBazaarActionProviderConfig = {}) => + new MoltBazaarActionProvider(config); diff --git a/typescript/agentkit/src/action-providers/moltbazaar/schemas.ts b/typescript/agentkit/src/action-providers/moltbazaar/schemas.ts new file mode 100644 index 000000000..4be3b6ee4 --- /dev/null +++ b/typescript/agentkit/src/action-providers/moltbazaar/schemas.ts @@ -0,0 +1,74 @@ +import { z } from "zod"; + +/** + * Input argument schema for browsing open tasks. + */ +export const MoltBazaarBrowseTasksSchema = z + .object({ + status: z + .enum(["open", "in_progress", "pending_review", "completed", "all"]) + .default("open") + .describe("Filter tasks by status"), + limit: z.number().min(1).max(100).default(50).describe("Maximum number of tasks to return"), + }) + .strip() + .describe("Input schema for browsing available tasks on MoltBazaar"); + +/** + * Input argument schema for getting task details. + */ +export const MoltBazaarGetTaskSchema = z + .object({ + taskId: z.string().uuid().describe("The UUID of the task to retrieve"), + }) + .strip() + .describe("Input schema for getting task details"); + +/** + * Input argument schema for placing a bid on a task. + */ +export const MoltBazaarPlaceBidSchema = z + .object({ + taskId: z.string().uuid().describe("The UUID of the task to bid on"), + proposedAmountUsdc: z + .number() + .positive() + .describe("The amount in USDC you are bidding to complete the task"), + proposalMessage: z + .string() + .min(10) + .max(1000) + .describe("Your proposal message explaining why you should be selected"), + }) + .strip() + .describe("Input schema for placing a bid on a task"); + +/** + * Input argument schema for submitting completed work. + */ +export const MoltBazaarSubmitWorkSchema = z + .object({ + taskId: z.string().uuid().describe("The UUID of the task you completed"), + submissionNotes: z + .string() + .min(10) + .max(2000) + .describe("Notes describing what you did and how to verify the work"), + submissionUrl: z + .string() + .url() + .optional() + .describe("Optional URL to deliverables (GitHub repo, deployed site, etc.)"), + }) + .strip() + .describe("Input schema for submitting completed work"); + +/** + * Input argument schema for checking agent profile. + */ +export const MoltBazaarGetAgentSchema = z + .object({ + agentId: z.string().uuid().optional().describe("The UUID of the agent (optional, uses wallet if not provided)"), + }) + .strip() + .describe("Input schema for getting agent profile and stats");