diff --git a/examples/acp_base/README.md b/examples/acp_base/README.md index 11ff924..51fec67 100644 --- a/examples/acp_base/README.md +++ b/examples/acp_base/README.md @@ -15,11 +15,11 @@ Before running the examples, you need to set up your environment variables. Crea # Required for all examples WHITELISTED_WALLET_PRIVATE_KEY=0x... # Your whitelisted wallet private key WHITELISTED_WALLET_ENTITY_ID=... # Your session entity key ID -BUYER_WALLET_ADDRESS=0x... # Buyer's wallet address -SELLER_WALLET_ADDRESS=0x... # Seller's wallet address +BUYER_AGENT_WALLET_ADDRESS=0x... # Buyer's wallet address +SELLER_AGENT_WALLET_ADDRESS=0x... # Seller's wallet address # Required for external evaluation examples -EVALUATOR_WALLET_ADDRESS=0x... # Evaluator's wallet address +EVALUATOR_AGENT_WALLET_ADDRESS=0x... # Evaluator's wallet address ``` ### Getting the Required Values @@ -37,9 +37,9 @@ EVALUATOR_WALLET_ADDRESS=0x... # Evaluator's wallet address ![Session Entity ID](docs/imgs/session-entity-id-location.png) 3. **Wallet Addresses** - - `BUYER_WALLET_ADDRESS`: The wallet address of the agent initiating the job - - `SELLER_WALLET_ADDRESS`: The wallet address of the agent providing the service - - `EVALUATOR_WALLET_ADDRESS`: (For external evaluation) The wallet address of the third-party evaluator + - `BUYER_AGENT_WALLET_ADDRESS`: The wallet address of the agent initiating the job + - `SELLER_AGENT_WALLET_ADDRESS`: The wallet address of the agent providing the service + - `EVALUATOR_AGENT_WALLET_ADDRESS`: (For external evaluation) The wallet address of the third-party evaluator > **Note:** Make sure your wallet has sufficient $BMW tokens for testing on Base Sepolia. If you need tokens, please reach out to Virtuals' DevRel team. diff --git a/examples/acp_base/external_evaluation/.env.example b/examples/acp_base/external_evaluation/.env.example index 863bed8..c549dc3 100644 --- a/examples/acp_base/external_evaluation/.env.example +++ b/examples/acp_base/external_evaluation/.env.example @@ -1,5 +1,5 @@ WHITELISTED_WALLET_PRIVATE_KEY=0x- WHITELISTED_WALLET_ENTITY_ID= -BUYER_WALLET_ADDRESS= -SELLER_WALLET_ADDRESS= -EVALUATOR_WALLET_ADDRESS= +BUYER_AGENT_WALLET_ADDRESS= +SELLER_AGENT_WALLET_ADDRESS= +EVALUATOR_AGENT_WALLET_ADDRESS= diff --git a/examples/acp_base/external_evaluation/buyer.ts b/examples/acp_base/external_evaluation/buyer.ts index 0730ef0..cc9b972 100644 --- a/examples/acp_base/external_evaluation/buyer.ts +++ b/examples/acp_base/external_evaluation/buyer.ts @@ -5,8 +5,8 @@ import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient" import AcpJob from "../../../src/acpJob"; import { baseSepoliaAcpConfig } from "../../../src"; import { - BUYER_WALLET_ADDRESS, - EVALUATOR_WALLET_ADDRESS, + BUYER_AGENT_WALLET_ADDRESS, + EVALUATOR_AGENT_WALLET_ADDRESS, WHITELISTED_WALLET_ENTITY_ID, WHITELISTED_WALLET_PRIVATE_KEY } from "./env"; @@ -16,7 +16,7 @@ async function buyer() { acpContractClient: await AcpContractClient.build( WHITELISTED_WALLET_PRIVATE_KEY, WHITELISTED_WALLET_ENTITY_ID, - BUYER_WALLET_ADDRESS, + BUYER_AGENT_WALLET_ADDRESS, baseSepoliaAcpConfig ), onNewTask: async (job: AcpJob) => { @@ -43,7 +43,7 @@ async function buyer() { const jobId = await chosenJobOffering.initiateJob( chosenJobOffering.requirementSchema || {}, new Date(Date.now() + 1000 * 60 * 60 * 24), - EVALUATOR_WALLET_ADDRESS, + EVALUATOR_AGENT_WALLET_ADDRESS, ); console.log(`Job ${jobId} initiated`); diff --git a/examples/acp_base/external_evaluation/env.ts b/examples/acp_base/external_evaluation/env.ts index c087cee..cbf7105 100644 --- a/examples/acp_base/external_evaluation/env.ts +++ b/examples/acp_base/external_evaluation/env.ts @@ -13,9 +13,9 @@ function getEnvVar(key: string, required = true): T { export const WHITELISTED_WALLET_PRIVATE_KEY = getEnvVar
('WHITELISTED_WALLET_PRIVATE_KEY'); export const WHITELISTED_WALLET_ENTITY_ID = parseInt(getEnvVar('WHITELISTED_WALLET_ENTITY_ID'), 10); -export const BUYER_WALLET_ADDRESS = getEnvVar
('BUYER_WALLET_ADDRESS'); -export const SELLER_WALLET_ADDRESS = getEnvVar
('SELLER_WALLET_ADDRESS'); -export const EVALUATOR_WALLET_ADDRESS = getEnvVar
('EVALUATOR_WALLET_ADDRESS'); +export const BUYER_AGENT_WALLET_ADDRESS = getEnvVar
('BUYER_AGENT_WALLET_ADDRESS'); +export const SELLER_AGENT_WALLET_ADDRESS = getEnvVar
('SELLER_AGENT_WALLET_ADDRESS'); +export const EVALUATOR_AGENT_WALLET_ADDRESS = getEnvVar
('EVALUATOR_AGENT_WALLET_ADDRESS'); if (isNaN(WHITELISTED_WALLET_ENTITY_ID)) { throw new Error('WHITELISTED_WALLET_ENTITY_ID must be a valid number in the .env file'); diff --git a/examples/acp_base/external_evaluation/evaluator.ts b/examples/acp_base/external_evaluation/evaluator.ts index 7db0986..2656a14 100644 --- a/examples/acp_base/external_evaluation/evaluator.ts +++ b/examples/acp_base/external_evaluation/evaluator.ts @@ -5,7 +5,7 @@ import AcpContractClient from "../../../src/acpContractClient"; import AcpJob from "../../../src/acpJob"; import { baseSepoliaAcpConfig } from "../../../src"; import { - EVALUATOR_WALLET_ADDRESS, + EVALUATOR_AGENT_WALLET_ADDRESS, WHITELISTED_WALLET_ENTITY_ID, WHITELISTED_WALLET_PRIVATE_KEY } from "./env"; @@ -15,7 +15,7 @@ async function evaluator() { acpContractClient: await AcpContractClient.build( WHITELISTED_WALLET_PRIVATE_KEY, WHITELISTED_WALLET_ENTITY_ID, - EVALUATOR_WALLET_ADDRESS, + EVALUATOR_AGENT_WALLET_ADDRESS, baseSepoliaAcpConfig ), onEvaluate: async (job: AcpJob) => { diff --git a/examples/acp_base/external_evaluation/seller.ts b/examples/acp_base/external_evaluation/seller.ts index c951a02..8e0550b 100644 --- a/examples/acp_base/external_evaluation/seller.ts +++ b/examples/acp_base/external_evaluation/seller.ts @@ -5,7 +5,7 @@ import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient" import AcpJob from "../../../src/acpJob"; import { baseSepoliaAcpConfig } from "../../../src"; import { - SELLER_WALLET_ADDRESS, + SELLER_AGENT_WALLET_ADDRESS, WHITELISTED_WALLET_ENTITY_ID, WHITELISTED_WALLET_PRIVATE_KEY } from "./env"; @@ -15,7 +15,7 @@ async function seller() { acpContractClient: await AcpContractClient.build( WHITELISTED_WALLET_PRIVATE_KEY, WHITELISTED_WALLET_ENTITY_ID, - SELLER_WALLET_ADDRESS, + SELLER_AGENT_WALLET_ADDRESS, baseSepoliaAcpConfig ), onNewTask: async (job: AcpJob) => { diff --git a/examples/acp_base/self_evaluation/.env.example b/examples/acp_base/self_evaluation/.env.example index 6f4d9a7..2b8a37f 100644 --- a/examples/acp_base/self_evaluation/.env.example +++ b/examples/acp_base/self_evaluation/.env.example @@ -1,4 +1,4 @@ WHITELISTED_WALLET_PRIVATE_KEY=0x- WHITELISTED_WALLET_ENTITY_ID= -BUYER_WALLET_ADDRESS= -SELLER_WALLET_ADDRESS= +BUYER_AGENT_WALLET_ADDRESS= +SELLER_AGENT_WALLET_ADDRESS= diff --git a/examples/acp_base/self_evaluation/buyer.ts b/examples/acp_base/self_evaluation/buyer.ts index 2b8fc32..f40c748 100644 --- a/examples/acp_base/self_evaluation/buyer.ts +++ b/examples/acp_base/self_evaluation/buyer.ts @@ -5,7 +5,7 @@ import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient" import AcpJob from "../../../src/acpJob"; import { baseSepoliaAcpConfig } from "../../../src"; import { - BUYER_WALLET_ADDRESS, + BUYER_AGENT_WALLET_ADDRESS, WHITELISTED_WALLET_ENTITY_ID, WHITELISTED_WALLET_PRIVATE_KEY } from "./env"; @@ -15,7 +15,7 @@ async function buyer() { acpContractClient: await AcpContractClient.build( WHITELISTED_WALLET_PRIVATE_KEY, WHITELISTED_WALLET_ENTITY_ID, - BUYER_WALLET_ADDRESS, + BUYER_AGENT_WALLET_ADDRESS, baseSepoliaAcpConfig ), onNewTask: async (job: AcpJob) => { diff --git a/examples/acp_base/self_evaluation/env.ts b/examples/acp_base/self_evaluation/env.ts index c9875a4..40c1096 100644 --- a/examples/acp_base/self_evaluation/env.ts +++ b/examples/acp_base/self_evaluation/env.ts @@ -13,8 +13,8 @@ function getEnvVar(key: string, required = true): T { export const WHITELISTED_WALLET_PRIVATE_KEY = getEnvVar
('WHITELISTED_WALLET_PRIVATE_KEY'); export const WHITELISTED_WALLET_ENTITY_ID = parseInt(getEnvVar('WHITELISTED_WALLET_ENTITY_ID'), 10); -export const BUYER_WALLET_ADDRESS = getEnvVar
('BUYER_WALLET_ADDRESS'); -export const SELLER_WALLET_ADDRESS = getEnvVar
('SELLER_WALLET_ADDRESS'); +export const BUYER_AGENT_WALLET_ADDRESS = getEnvVar
('BUYER_AGENT_WALLET_ADDRESS'); +export const SELLER_AGENT_WALLET_ADDRESS = getEnvVar
('SELLER_AGENT_WALLET_ADDRESS'); if (isNaN(WHITELISTED_WALLET_ENTITY_ID)) { throw new Error('WHITELISTED_WALLET_ENTITY_ID must be a valid number in the .env file'); diff --git a/examples/acp_base/self_evaluation/seller.ts b/examples/acp_base/self_evaluation/seller.ts index c951a02..8e0550b 100644 --- a/examples/acp_base/self_evaluation/seller.ts +++ b/examples/acp_base/self_evaluation/seller.ts @@ -5,7 +5,7 @@ import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient" import AcpJob from "../../../src/acpJob"; import { baseSepoliaAcpConfig } from "../../../src"; import { - SELLER_WALLET_ADDRESS, + SELLER_AGENT_WALLET_ADDRESS, WHITELISTED_WALLET_ENTITY_ID, WHITELISTED_WALLET_PRIVATE_KEY } from "./env"; @@ -15,7 +15,7 @@ async function seller() { acpContractClient: await AcpContractClient.build( WHITELISTED_WALLET_PRIVATE_KEY, WHITELISTED_WALLET_ENTITY_ID, - SELLER_WALLET_ADDRESS, + SELLER_AGENT_WALLET_ADDRESS, baseSepoliaAcpConfig ), onNewTask: async (job: AcpJob) => { diff --git a/examples/game_sdk/.env.example b/examples/game_sdk/.env.example new file mode 100644 index 0000000..9fbd4c0 --- /dev/null +++ b/examples/game_sdk/.env.example @@ -0,0 +1,7 @@ +WHITELISTED_WALLET_PRIVATE_KEY=0x- +WHITELISTED_WALLET_ENTITY_ID= +BUYER_AGENT_WALLET_ADDRESS= +SELLER_AGENT_WALLET_ADDRESS= +BUYER_GAME_TWITTER_ACCESS_TOKEN=apx- +SELLER_GAME_TWITTER_ACCESS_TOKEN=apx- +GAME_API_KEY=apt- diff --git a/examples/game_sdk/acpPlugin.ts b/examples/game_sdk/acpPlugin.ts new file mode 100644 index 0000000..245cf4f --- /dev/null +++ b/examples/game_sdk/acpPlugin.ts @@ -0,0 +1,395 @@ +// TODO: Point the imports to acp-node after publishing + +import { + GameWorker, + GameFunction, + ExecutableGameFunctionResponse, + ExecutableGameFunctionStatus, +} from "@virtuals-protocol/game"; +import AcpClient from "../../src/acpClient"; +import { AcpJobPhases } from "../../src/acpContractClient"; +import { IInventory } from "./interface"; +import { TwitterApi } from "@virtuals-protocol/game-twitter-node"; +import { Address } from "viem"; + +interface ITweetHistory { + tweetId: string; + content: string; + jobId: number; + phase: AcpJobPhases; +} + +interface ITweetResponse { + tweetId: string; + content: string; +} + +interface IAcpPluginOptions { + acpClient: AcpClient; + twitterClient?: TwitterApi; + cluster?: string; + jobExpiryDurationMins?: number; +} + +class AcpPlugin { + // . + private twitterClient?: TwitterApi; + private tweetHistory: Map = new Map(); + + constructor(options: IAcpPluginOptions) { + // . + // . + this.twitterClient = options.twitterClient; + // . + // this.id = "acp_worker"; + // this.name = "ACP Worker"; + // . + } + + /** + * Helper method to handle tweet posting and history management + * @param jobId - The job ID associated with the tweet + * @param content - The tweet content + * @param phase - The current job phase + * @param replyToTweetId - Optional tweet ID to reply to + * @returns Promise + */ + private async handleTweet( + jobId: number, + content: string, + phase: AcpJobPhases, + replyToTweetId?: string + ): Promise { + if (!this.twitterClient) { + throw new Error("Twitter client not initialized"); + } + + try { + let tweet; + if (replyToTweetId) { + tweet = await this.twitterClient.v2.reply(replyToTweetId, content); + } else { + tweet = await this.twitterClient.v2.post(content); + } + + const tweetData: ITweetHistory = { + tweetId: tweet.data.id, + content, + jobId, + phase, + }; + + // Update local tweet history + const jobTweets = this.tweetHistory.get(jobId) || []; + this.tweetHistory.set(jobId, [...jobTweets, tweetData]); + + // TODO: When API server is ready, implement proper tweet history storage + // await this.acpClient.addTweet(jobId, tweet.data.id, content); + + return { + tweetId: tweet.data.id, + content, + }; + } catch (error: unknown) { + console.error("Error handling tweet:", error); + throw new Error(`Failed to handle tweet: ${error instanceof Error ? error.message : String(error)}`); + } + } + + /** + * Get tweet history for a specific job + * @param jobId - The job ID to get tweet history for + * @returns ITweetHistory[] + */ + private getJobTweetHistory(jobId: number): ITweetHistory[] { + return this.tweetHistory.get(jobId) || []; + } + + /** + * Get the latest tweet for a specific job + * @param jobId - The job ID to get the latest tweet for + * @returns ITweetHistory | undefined + */ + private getLatestJobTweet(jobId: number): ITweetHistory | undefined { + const tweets = this.getJobTweetHistory(jobId); + return tweets[tweets.length - 1]; + } + + get initiateJob() { + return new GameFunction({ + name: "initiate_job", + description: + "Creates a purchase request for items from another agent's catalog. Only for use when YOU are the buyer. The seller must accept your request before you can proceed with payment.\n\nHint: Use this when you need to acquire items from other agents - it's the only way to make purchases in the ecosystem. You CANNOT propose sales or initiate jobs to sell your own products.", + args: [ + { + name: "sellerWalletAddress", + type: "string", + description: "The seller's agent wallet address you want to buy from", + }, + { + name: "price", + type: "string", + description: "Offered price for service", + }, + { + name: "reasoning", + type: "string", + description: "Why you are making this purchase request", + }, + { + name: "serviceRequirements", + type: "string", + description: + "Detailed specifications for service-based items, only needed if the seller's catalog specifies service requirements. For marketing materials, provide a clear image generation prompt describing the exact visual elements, composition, and style. Come up with your own creative prompt that matches your needs - don't copy the example (e.g. '3 lemons cut in half arranged around a tall glass filled with golden lemonade, soft natural lighting, white background'). Can be left empty for items that don't require specifications.", + }, + { + name: "tweetContent", + type: "string", + description: + "Tweet content that will be posted about this job. Must include the seller's Twitter handle (with @ symbol) to notify them", + }, + { + name: "requireEvaluator", + type: "boolean", + description: + "Decide if your job request is complex enough to spend money for evaluator agent to assess the relevancy of the output. For simple job request like generate image, insights, facts does not require evaluation. For complex and high level job like generating a promotion video, a marketing narrative, a trading signal should require evaluator to assess result relevancy.", + }, + { + name: "evaluatorKeyword", + type: "string", + description: "Keyword to search for a evaluator.", + }, + ] as const, + executable: async (args, _) => { + try { + // . + if (this.twitterClient) { + await this.handleTweet( + jobId, + args.tweetContent, + AcpJobPhases.REQUEST + ); + } + + return new ExecutableGameFunctionResponse( + ExecutableGameFunctionStatus.Done, + JSON.stringify({ + jobId: jobId, + sellerWalletAddress: args.sellerWalletAddress, + price: price, + serviceRequirements: args.serviceRequirements, + timestamp: Date.now(), + }) + ); + } catch (e) { + console.error(e); + + return new ExecutableGameFunctionResponse( + ExecutableGameFunctionStatus.Failed, + `System error while initiating job - try again after a short delay. ${e}` + ); + } + }, + }); + } + + get respondJob() { + return new GameFunction({ + name: "respond_to_job", + description: + "Accepts or rejects an incoming 'request' job. Only for use when YOU are the seller. After accepting, you must wait for buyer's payment before delivery. Use if you want to cancel a request/job.\n\nHint: For all incoming jobs, you must respond (accept/reject) before being able to progress the job in any way.", + args: [ + { + name: "jobId", + type: "string", + description: "The job ID you are responding to", + }, + { + name: "decision", + type: "string", + description: "Your response: 'ACCEPT' or 'REJECT'", + }, + { + name: "reasoning", + type: "string", + description: "Why you made this decision", + }, + + { + name: "tweetContent", + type: "string", + description: + "Tweet content that will be posted about this job as a reply to the previous tweet (do not use @ symbol)", + }, + ] as const, + executable: async (args, _) => { + try { + // . + if (this.twitterClient) { + const latestTweet = this.getLatestJobTweet(+args.jobId); + if (latestTweet) { + await this.handleTweet( + +args.jobId, + args.tweetContent, + AcpJobPhases.NEGOTIATION, + latestTweet.tweetId + ); + } + } + + return new ExecutableGameFunctionResponse( + ExecutableGameFunctionStatus.Done, + JSON.stringify({ + jobId: args.jobId, + decision: args.decision, + timestamp: Date.now(), + }) + ); + } catch (e) { + console.error(e); + + return new ExecutableGameFunctionResponse( + ExecutableGameFunctionStatus.Failed, + `System error while responding to job - try again after a short delay. ${e}` + ); + } + }, + }); + } + + get payJob() { + return new GameFunction({ + name: "pay_job", + description: + "Processes payment for an accepted purchase request. Only for use when YOU are the buyer. you can only make payment when job phase is 'pending_payment'. After payment is verified, you must wait for the seller to deliver.\n\nHint: This is your next step after a seller accepts your purchase request - you can't get the items without paying first.", + args: [ + { + name: "jobId", + type: "number", + description: "The job ID you are paying for", + }, + { + name: "amount", + type: "number", + description: "The total amount to pay", + }, + { + name: "reasoning", + type: "string", + description: "Why you are making this payment", + }, + { + name: "tweetContent", + type: "string", + description: + "Tweet content that will be posted about this job as a reply to the previous tweet (do not use @ symbol)", + }, + ] as const, + executable: async (args, _) => { + try{ + // . + if (this.twitterClient) { + const latestTweet = this.getLatestJobTweet(+args.jobId); + if (latestTweet) { + await this.handleTweet( + +args.jobId, + args.tweetContent, + AcpJobPhases.TRANSACTION, + latestTweet.tweetId + ); + } + } + + return new ExecutableGameFunctionResponse( + ExecutableGameFunctionStatus.Done, + `Payment successfully processed! Here are the details:\n${JSON.stringify( + { + jobId: args.jobId, + amountPaid: args.amount, + timestamp: Date.now(), + } + )}` + ); + } catch (e) { + console.error(e); + + return new ExecutableGameFunctionResponse( + ExecutableGameFunctionStatus.Failed, + `System error while processing payment - try again after a short delay. ${e}` + ); + } + }, + }); + } + + get deliverJob() { + return new GameFunction({ + name: "deliver_job", + description: + "Completes a sale by delivering items to the buyer. Only for use when YOU are the seller and payment is verified. After delivery, the job is completed and payment is released to your wallet.\n\nHint: This is how you fulfill your sales and get paid - use it as soon as you see payment is verified.", + args: [ + { + name: "jobId", + type: "string", + description: "The job ID you are delivering for", + }, + { + name: "deliverableType", + type: "string", + description: "Type of the deliverable", + }, + { + name: "deliverable", + type: "string", + description: "The deliverable item", + }, + { + name: "reasoning", + type: "string", + description: "Why you are making this delivery", + }, + { + name: "tweetContent", + type: "string", + description: + "Tweet content that will be posted about this job as a reply to the previous tweet (do not use @ symbol)", + }, + ] as const, + executable: async (args, _) => { + try { + // . + if (this.twitterClient) { + const latestTweet = this.getLatestJobTweet(+args.jobId); + if (latestTweet) { + await this.handleTweet( + +args.jobId, + args.tweetContent, + AcpJobPhases.COMPLETED, + latestTweet.tweetId + ); + } + } + + return new ExecutableGameFunctionResponse( + ExecutableGameFunctionStatus.Done, + JSON.stringify({ + status: "success", + jobId: args.jobId, + deliverable: args.deliverable, + timestamp: Date.now(), + }) + ); + } catch (e) { + console.error(e); + + return new ExecutableGameFunctionResponse( + ExecutableGameFunctionStatus.Failed, + `System error while delivering items - try again after a short delay. ${e}` + ); + } + }, + }); + } +} + +export default AcpPlugin; diff --git a/examples/game_sdk/env.ts b/examples/game_sdk/env.ts new file mode 100644 index 0000000..cec8d8b --- /dev/null +++ b/examples/game_sdk/env.ts @@ -0,0 +1,24 @@ +import dotenv from "dotenv"; +import { Address } from "viem"; + +dotenv.config({ path: __dirname + '/.env' }); + +function getEnvVar(key: string, required = true): T { + const value = process.env[key]; + if (required && (value === undefined || value === '')) { + throw new Error(`${key} is not defined or is empty in the .env file`); + } + return value as T; +} + +export const WHITELISTED_WALLET_PRIVATE_KEY = getEnvVar
('WHITELISTED_WALLET_PRIVATE_KEY'); +export const WHITELISTED_WALLET_ENTITY_ID = parseInt(getEnvVar('WHITELISTED_WALLET_ENTITY_ID'), 10); +export const BUYER_AGENT_WALLET_ADDRESS = getEnvVar
('BUYER_AGENT_WALLET_ADDRESS'); +export const SELLER_AGENT_WALLET_ADDRESS = getEnvVar
('SELLER_AGENT_WALLET_ADDRESS'); +export const BUYER_GAME_TWITTER_ACCESS_TOKEN = getEnvVar('BUYER_GAME_TWITTER_ACCESS_TOKEN'); +export const SELLER_GAME_TWITTER_ACCESS_TOKEN = getEnvVar('SELLER_GAME_TWITTER_ACCESS_TOKEN'); +export const GAME_API_KEY = getEnvVar('GAME_API_KEY'); + +if (isNaN(WHITELISTED_WALLET_ENTITY_ID)) { + throw new Error('WHITELISTED_WALLET_ENTITY_ID must be a valid number in the .env file'); +} diff --git a/helpers/.env.example b/helpers/.env.example index 0b4f3fa..966b471 100644 --- a/helpers/.env.example +++ b/helpers/.env.example @@ -1,3 +1,3 @@ -WHITELISTED_WALLET_PRIVATE_KEY= -WHITELISTED_WALLET_ENTITY_ID= -BUYER_WALLET_ADDRESS= +WHITELISTED_WALLET_PRIVATE_KEY=0x- +WHITELISTED_WALLET_ENTITY_ID= +BUYER_AGENT_WALLET_ADDRESS= diff --git a/helpers/acpHelperFunctions.ts b/helpers/acpHelperFunctions.ts index 42a82b2..4993ecb 100644 --- a/helpers/acpHelperFunctions.ts +++ b/helpers/acpHelperFunctions.ts @@ -1,4 +1,3 @@ -import * as path from 'path'; import AcpClient from "../src/acpClient"; import AcpContractClient from "../src/acpContractClient"; import { baseSepoliaAcpConfig } from "../src/configs"; @@ -16,7 +15,7 @@ async function testHelperFunctions() { acpContractClient: await AcpContractClient.build( process.env.WHITELISTED_WALLET_PRIVATE_KEY as `0x${string}`, Number(process.env.WHITELISTED_WALLET_ENTITY_ID), - process.env.BUYER_WALLET_ADDRESS as Address, + process.env.BUYER_AGENT_WALLET_ADDRESS as Address, baseSepoliaAcpConfig ) }); @@ -24,31 +23,31 @@ async function testHelperFunctions() { // Get active jobs const activeJobs = await acpClient.getActiveJobs(1, 10); console.log("\n🔵 Active Jobs:"); - console.log(activeJobs.data.length > 0 ? activeJobs.data : "No active jobs found."); + console.log(activeJobs.length > 0 ? activeJobs : "No active jobs found."); // Get completed jobs const completedJobs = await acpClient.getCompletedJobs(1, 10); console.log("\n✅ Completed Jobs:"); - console.log(completedJobs.data.length > 0 ? completedJobs.data : "No completed jobs found."); + console.log(completedJobs.length > 0 ? completedJobs : "No completed jobs found."); // Get cancelled jobs const cancelledJobs = await acpClient.getCancelledJobs(1, 10); console.log("\n❌ Cancelled Jobs:"); - console.log(cancelledJobs.data.length > 0 ? cancelledJobs.data : "No cancelled jobs found."); + console.log(cancelledJobs.length > 0 ? cancelledJobs : "No cancelled jobs found."); - if (completedJobs.data.length > 0) { - const onChainJobId = completedJobs.data[0].onChainJobId; + if (completedJobs.length > 0) { + const onChainJobId = completedJobs[0].id; if (onChainJobId) { - const job = await acpClient.getJobByOnChainJobId(onChainJobId); + const job = await acpClient.getJobById(onChainJobId); console.log(`\n📄 Job Details (Job ID: ${onChainJobId}):`); - console.log(job.data); + console.log(job); - const memos = completedJobs.data[0].memos; + const memos = completedJobs[0].memos; if (memos && memos.length > 0) { - const memoId = memos[0].memoId; + const memoId = memos[0].id; const memo = await acpClient.getMemoById(onChainJobId, memoId); console.log(`\n📝 Memo Details (Job ID: ${onChainJobId}, Memo ID: ${memoId}):`); - console.log(memo.data); + console.log(memo); } else { console.log("\n⚠️ No memos found for the completed job."); } @@ -59,7 +58,12 @@ async function testHelperFunctions() { } // Run the test -testHelperFunctions().catch(error => { - console.error("Error in helper functions test:", error); - process.exit(1); -}); \ No newline at end of file +testHelperFunctions() + .then(() => { + console.log("\n✨ Test completed successfully"); + process.exit(0); + }) + .catch(error => { + console.error("Error in helper functions test:", error); + process.exit(1); + });