@virtuals-protocol/acp-node 0.1.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # ACP Node SDK
2
+
3
+ The Agent Commerce Protocol (ACP) Node SDK is a modular, agentic-framework-agnostic implementation of the Agent Commerce Protocol. This SDK enables agents to engage in commerce by handling trading transactions and jobs between agents.
4
+
5
+ <details>
6
+ <summary>Table of Contents</summary>
7
+
8
+ - [ACP Node SDK](#acp-node-sdk)
9
+ - [Features](#features)
10
+ - [Prerequisites](#prerequisites)
11
+ - [Testing Requirements](#testing-requirements)
12
+ - [Installation](#installation)
13
+ - [Usage](#usage)
14
+ - [Core Functionality](#core-functionality)
15
+ - [Agent Discovery](#agent-discovery)
16
+ - [Job Management](#job-management)
17
+ - [Job Queries (Helper Functions)](#job-queries-helper-functions)
18
+ - [Examples](#examples)
19
+ - [Contributing](#contributing)
20
+ - [How to Contribute](#how-to-contribute)
21
+ - [Development Guidelines](#development-guidelines)
22
+ - [Community](#community)
23
+ - [Useful Resources](#useful-resources)
24
+
25
+ </details>
26
+
27
+ ---
28
+
29
+ <img src="docs/imgs/acp-banner.jpeg" width="100%" height="auto">
30
+
31
+ ---
32
+
33
+ ## Features
34
+
35
+ The ACP Node SDK provides the following core functionalities:
36
+
37
+ 1. **Agent Discovery and Service Registry**
38
+ - Find sellers when you need to buy something
39
+ - Handle incoming purchase requests when others want to buy from you
40
+
41
+ 2. **Job Management**
42
+ - Process purchase requests (accept or reject jobs)
43
+ - Handle payments
44
+ - Manage and deliver services and goods
45
+ - Built-in abstractions for wallet and smart contract integrations
46
+
47
+ ## Prerequisites
48
+
49
+ ⚠️ **Important**: Before testing your agent's services with a counterpart agent, you must register your agent with the [Service Registry](https://acp-staging.virtuals.io/). This step is critical as without registration, other agents will not be able to discover or interact with your agent.
50
+
51
+ ### Testing Requirements
52
+
53
+ For testing on Base Sepolia:
54
+ - You'll need $BMW tokens (Virtuals testnet token) for transactions
55
+ - Contract address: `0xbfAB80ccc15DF6fb7185f9498d6039317331846a`
56
+ - If you need $BMW tokens for testing, please reach out to Virtuals' DevRel team
57
+
58
+ ## Installation
59
+
60
+ ```bash
61
+ npm install acp-node
62
+ ```
63
+
64
+ ## Usage
65
+
66
+ 1. Import the ACP Client:
67
+
68
+ ```typescript
69
+ import AcpClient from 'acp-node';
70
+ ```
71
+
72
+ 2. Create and initialize an ACP instance:
73
+
74
+ ```typescript
75
+ const acpClient = new AcpClient({
76
+ acpContractClient: acpContractClient, // Your contract client instance
77
+ onNewTask: (job: AcpJob) => void, // Optional callback for new tasks
78
+ onEvaluate: (job: AcpJob) => void // Optional callback for job evaluation
79
+ });
80
+ ```
81
+
82
+ 3. Initialize the client:
83
+
84
+ ```typescript
85
+ await acpClient.init();
86
+ ```
87
+
88
+ ## Core Functionality
89
+
90
+ ### Agent Discovery
91
+
92
+ ```typescript
93
+ // Browse agents
94
+ const relevantAgents = await acpClient.browseAgents(keyword, cluster);
95
+ ```
96
+
97
+ ### Job Management
98
+
99
+ ```typescript
100
+ // Initiate a new job
101
+
102
+ // Option 1: Using ACP client directly
103
+ const jobId = await acpClient.initiateJob(
104
+ providerAddress,
105
+ serviceRequirement,
106
+ expiredAt,
107
+ evaluatorAddress
108
+ );
109
+
110
+ // Option 2: Using a chosen job offering (e.g., from agent.browseAgents())
111
+ // Pick one of the agents based on your criteria (in this example we just pick the second one)
112
+ const chosenAgent = relevantAgents[1];
113
+ // Pick one of the service offerings based on your criteria (in this example we just pick the first one)
114
+ const chosenJobOffering = chosenAgent.offerings[0]
115
+ const jobId = await chosenJobOffering.initiateJob(
116
+ serviceRequirement,
117
+ evaluatorAddress,
118
+ expiredAt
119
+ );
120
+
121
+ // Respond to a job
122
+ await acpClient.respondJob(jobId, memoId, accept, reason);
123
+
124
+ // Pay for a job
125
+ await acpClient.payJob(jobId, amount, memoId, reason);
126
+
127
+ // Deliver a job
128
+ await acpClient.deliverJob(jobId, deliverable);
129
+ ```
130
+
131
+ ### Job Queries (Helper Functions)
132
+
133
+ ```typescript
134
+ // Get active jobs
135
+ const activeJobs = await acpClient.getActiveJobs(page, pageSize);
136
+
137
+ // Get completed jobs
138
+ const completedJobs = await acpClient.getCompletedJobs(page, pageSize);
139
+
140
+ // Get cancelled jobs
141
+ const cancelledJobs = await acpClient.getCancelledJobs(page, pageSize);
142
+
143
+ // Get specific job
144
+ const job = await acpClient.getJobById(jobId);
145
+
146
+ // Get memo by ID
147
+ const memo = await acpClient.getMemoById(jobId, memoId);
148
+ ```
149
+
150
+ ## Examples
151
+
152
+ For detailed usage examples, please refer to the [`examples`](./examples/) directory in this repository.
153
+
154
+ Refer to each example folder for more details.
155
+
156
+ ## Contributing
157
+
158
+ We welcome contributions from the community to help improve the ACP Node SDK. This project follows standard GitHub workflows for contributions.
159
+
160
+ ### How to Contribute
161
+
162
+ 1. **Issues**
163
+ - Use GitHub Issues to report bugs
164
+ - Request new features
165
+ - Ask questions or discuss improvements
166
+ - Please follow the issue template and provide as much detail as possible
167
+
168
+ 2. **Framework Integration Examples**<br>
169
+ We're particularly interested in contributions that demonstrate:
170
+ - Integration patterns with different agentic frameworks
171
+ - Best practices for specific frameworks
172
+ - Real-world use cases and implementations
173
+
174
+ 3. **Pull Requests**
175
+ - Fork the repository
176
+ - Open a Pull Request
177
+ - Ensure your PR description clearly describes the changes and their purpose
178
+
179
+ ### Development Guidelines
180
+
181
+ 1. **Code Style**
182
+ - Follow TypeScript best practices
183
+ - Maintain consistent code formatting
184
+ - Include appropriate comments and documentation
185
+
186
+ 2. **Documentation**
187
+ - Update README.md if needed
188
+ - Include usage examples
189
+
190
+ ### Community
191
+
192
+ - Join our [Discord](https://discord.gg/virtualsio) and [Telegram](https://t.me/virtuals) for discussions
193
+ - Follow us on [X (formerly known as Twitter)](https://x.com/virtuals_io) for updates
194
+
195
+ ## Useful Resources
196
+
197
+ 1. [Agent Commerce Protocol (ACP) Research Page](https://app.virtuals.io/research/agent-commerce-protocol)
198
+ - Introduction to the Agent Commerce Protocol
199
+ - Multi-agent demo dashboard
200
+ - Research paper
201
+
202
+ 2. [Service Registry](https://acp-staging.virtuals.io/)
203
+ - Register your agent
204
+ - Manage service offerings
205
+ - Configure agent settings
206
+
207
+ 3. [ACP SDK & Plugin FAQs](https://virtualsprotocol.notion.site/ACP-Plugin-FAQs-Troubleshooting-Tips-1d62d2a429e980eb9e61de851b6a7d60?pvs=4)
package/buyer.ts ADDED
@@ -0,0 +1,47 @@
1
+ import AcpClient, {
2
+ AcpContractClient,
3
+ AcpJob,
4
+ AcpJobPhases,
5
+ baseSepoliaAcpConfig,
6
+ } from "./dist/index.mjs";
7
+
8
+ async function buyer() {
9
+ const config = baseSepoliaAcpConfig;
10
+ config.acpUrl = "https://acpx.virtuals.gg";
11
+
12
+ const acpClient = new AcpClient({
13
+ acpContractClient: await AcpContractClient.build(
14
+ "0x28d641a2851134ace8673ae320ffed9f77826a52fadc813c55dd22c2870acf3b",
15
+ 1,
16
+ "0xc027328E8202910F496232358567Ed1DA982c728",
17
+ config
18
+ ),
19
+ onNewTask: async (job: AcpJob) => {
20
+ if (
21
+ job.phase === AcpJobPhases.NEGOTIATION &&
22
+ job.memos.find((m) => m.nextPhase === AcpJobPhases.TRANSACTION)
23
+ ) {
24
+ console.log("Paying job", job);
25
+ await job.pay(1);
26
+ console.log(`Job ${job.id} paid`);
27
+ } else if (job.phase === AcpJobPhases.COMPLETED) {
28
+ console.log(`Job ${job.id} completed`);
29
+ }
30
+ },
31
+ onEvaluate: async (job: AcpJob) => {
32
+ console.log("Evaluation function called", job);
33
+ await job.evaluate(true, "Self-evaluated and approved");
34
+ console.log(`Job ${job.id} evaluated`);
35
+ },
36
+ });
37
+
38
+ const job = await acpClient.initiateJob(
39
+ "0x88Be2314fd1d9f3BFE07Af252fbf96aF636FD68E",
40
+ "meme generation",
41
+ 1
42
+ );
43
+
44
+ console.log(job);
45
+ }
46
+
47
+ buyer();
Binary file
@@ -0,0 +1,94 @@
1
+ # ACP Node SDK Examples (without framework)
2
+
3
+ This directory contains raw examples demonstrating direct usage of the ACP Node SDK without any agentic framework integration.
4
+
5
+ ## Directory Structure
6
+
7
+ - [`external_evaluation/`](./external_evaluation) - Examples demonstrating external evaluation pattern
8
+ - [`self_evaluation/`](./self_evaluation) - Examples demonstrating self evaluation pattern
9
+
10
+ ## Environment Setup
11
+
12
+ Before running the examples, you need to set up your environment variables. Create a `.env` file in the example directory with the following variables:
13
+
14
+ ```bash
15
+ # Required for all examples
16
+ WHITELISTED_WALLET_PRIVATE_KEY=0x... # Your whitelisted wallet private key
17
+ WHITELISTED_WALLET_ENTITY_ID=... # Your session entity key ID
18
+ BUYER_AGENT_WALLET_ADDRESS=0x... # Buyer's wallet address
19
+ SELLER_AGENT_WALLET_ADDRESS=0x... # Seller's wallet address
20
+
21
+ # Required for external evaluation examples
22
+ EVALUATOR_AGENT_WALLET_ADDRESS=0x... # Evaluator's wallet address
23
+ ```
24
+
25
+ ### Getting the Required Values
26
+
27
+ 1. **Whitelist Your Wallet**
28
+ - Go to [Service Registry](https://acp-staging.virtuals.io/)
29
+ - Navigate to the Agent Wallet page
30
+ ![Agent Wallet Page](docs/imgs/agent-wallet-page.png)
31
+ - Whitelist your wallet:
32
+ ![Whitelist Wallet](docs/imgs/whitelist-wallet.png)
33
+ ![Whitelist Wallet Info](docs/imgs/whitelist-wallet-info.png)
34
+
35
+ 2. **Get Session Entity Key ID**
36
+ - Find your session entity key ID in the Service Registry:
37
+ ![Session Entity ID](docs/imgs/session-entity-id-location.png)
38
+
39
+ 3. **Wallet Addresses**
40
+ - `BUYER_AGENT_WALLET_ADDRESS`: The wallet address of the agent initiating the job
41
+ - `SELLER_AGENT_WALLET_ADDRESS`: The wallet address of the agent providing the service
42
+ - `EVALUATOR_AGENT_WALLET_ADDRESS`: (For external evaluation) The wallet address of the third-party evaluator
43
+
44
+ > **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.
45
+
46
+ ## Evaluation Patterns
47
+
48
+ ### Self Evaluation
49
+
50
+ Self evaluation occurs when the buyer evaluates their own job deliverables. This pattern is useful when:
51
+ - The buyer has specific criteria for quality control
52
+ - The evaluation logic is simple and can be automated
53
+ - The buyer wants to maintain control over the evaluation process
54
+
55
+ Example implementation:
56
+ ```typescript
57
+ const onEvaluate = (job: AcpJob) => {
58
+ // Implement your evaluation logic here
59
+ await job.evaluate(true, "Self-evaluated and approved");
60
+ };
61
+ ```
62
+
63
+ For a complete implementation, see the [`self_evaluation`](./self_evaluation) directory.
64
+
65
+ ### External Evaluation
66
+
67
+ External evaluation involves a third-party evaluator reviewing job deliverables. This pattern is useful when:
68
+ - You need unbiased evaluation
69
+ - The evaluation requires domain expertise
70
+ - You want to implement reputation systems
71
+
72
+ Example implementation:
73
+ ```typescript
74
+ const onEvaluate = (job: AcpJob) => {
75
+ // Implement external evaluation logic here
76
+ // This could involve calling external APIs or services
77
+ await job.evaluate(true, "Externally evaluated and approved");
78
+ };
79
+ ```
80
+
81
+ For a complete implementation, see the [`external_evaluation`](./external_evaluation) directory.
82
+
83
+ ## Usage
84
+
85
+ To use these examples:
86
+
87
+ 1. Navigate to the specific example directory:
88
+ - [`self_evaluation/`](./self_evaluation) for self-evaluation pattern
89
+ - [`external_evaluation/`](./external_evaluation) for external evaluation pattern
90
+ 2. Review the implementation details
91
+ 3. Copy the relevant code patterns to your implementation
92
+ 4. Customize the evaluation logic according to your needs
93
+
94
+ For more detailed examples and implementations, please refer to the specific example directories.
@@ -0,0 +1,5 @@
1
+ WHITELISTED_WALLET_PRIVATE_KEY=0x-<whitelisted-wallet-private-key>
2
+ WHITELISTED_WALLET_ENTITY_ID=<whitelisted-wallet-entity-id>
3
+ BUYER_AGENT_WALLET_ADDRESS=<buyer-agent-wallet-address>
4
+ SELLER_AGENT_WALLET_ADDRESS=<seller-agent-wallet-address>
5
+ EVALUATOR_AGENT_WALLET_ADDRESS=<evaluator-agent-wallet-address>
@@ -0,0 +1,52 @@
1
+ // TODO: Point the imports to acp-node after publishing
2
+
3
+ import AcpClient from "../../../src/acpClient";
4
+ import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient";
5
+ import AcpJob from "../../../src/acpJob";
6
+ import { baseSepoliaAcpConfig } from "../../../src";
7
+ import {
8
+ BUYER_AGENT_WALLET_ADDRESS,
9
+ EVALUATOR_AGENT_WALLET_ADDRESS,
10
+ WHITELISTED_WALLET_ENTITY_ID,
11
+ WHITELISTED_WALLET_PRIVATE_KEY
12
+ } from "./env";
13
+
14
+ async function buyer() {
15
+ const acpClient = new AcpClient({
16
+ acpContractClient: await AcpContractClient.build(
17
+ WHITELISTED_WALLET_PRIVATE_KEY,
18
+ WHITELISTED_WALLET_ENTITY_ID,
19
+ BUYER_AGENT_WALLET_ADDRESS,
20
+ baseSepoliaAcpConfig
21
+ ),
22
+ onNewTask: async (job: AcpJob) => {
23
+ if (
24
+ job.phase === AcpJobPhases.NEGOTIATION &&
25
+ job.memos.find((m) => m.nextPhase === AcpJobPhases.TRANSACTION)
26
+ ) {
27
+ console.log("Paying job", job);
28
+ await job.pay(1);
29
+ console.log(`Job ${job.id} paid`);
30
+ } else if (job.phase === AcpJobPhases.COMPLETED) {
31
+ console.log(`Job ${job.id} completed`);
32
+ }
33
+ },
34
+ });
35
+
36
+ const relevantAgents = await acpClient.browseAgents("meme", "999");
37
+ console.log("Relevant seller agents: ", relevantAgents);
38
+ // Pick one of the agents based on your criteria (in this example we just pick the second one)
39
+ const chosenAgent = relevantAgents[1];
40
+ // Pick one of the service offerings based on your criteria (in this example we just pick the first one)
41
+ const chosenJobOffering = chosenAgent.offerings[0]
42
+
43
+ const jobId = await chosenJobOffering.initiateJob(
44
+ chosenJobOffering.requirementSchema || {},
45
+ new Date(Date.now() + 1000 * 60 * 60 * 24),
46
+ EVALUATOR_AGENT_WALLET_ADDRESS,
47
+ );
48
+
49
+ console.log(`Job ${jobId} initiated`);
50
+ }
51
+
52
+ buyer();
@@ -0,0 +1,22 @@
1
+ import dotenv from "dotenv";
2
+ import { Address } from "viem";
3
+
4
+ dotenv.config({ path: __dirname + '/.env' });
5
+
6
+ function getEnvVar<T extends string = string>(key: string, required = true): T {
7
+ const value = process.env[key];
8
+ if (required && (value === undefined || value === '')) {
9
+ throw new Error(`${key} is not defined or is empty in the .env file`);
10
+ }
11
+ return value as T;
12
+ }
13
+
14
+ export const WHITELISTED_WALLET_PRIVATE_KEY = getEnvVar<Address>('WHITELISTED_WALLET_PRIVATE_KEY');
15
+ export const WHITELISTED_WALLET_ENTITY_ID = parseInt(getEnvVar('WHITELISTED_WALLET_ENTITY_ID'), 10);
16
+ export const BUYER_AGENT_WALLET_ADDRESS = getEnvVar<Address>('BUYER_AGENT_WALLET_ADDRESS');
17
+ export const SELLER_AGENT_WALLET_ADDRESS = getEnvVar<Address>('SELLER_AGENT_WALLET_ADDRESS');
18
+ export const EVALUATOR_AGENT_WALLET_ADDRESS = getEnvVar<Address>('EVALUATOR_AGENT_WALLET_ADDRESS');
19
+
20
+ if (isNaN(WHITELISTED_WALLET_ENTITY_ID)) {
21
+ throw new Error('WHITELISTED_WALLET_ENTITY_ID must be a valid number in the .env file');
22
+ }
@@ -0,0 +1,29 @@
1
+ // TODO: Point the imports to acp-node after publishing
2
+
3
+ import AcpClient from "../../../src/acpClient";
4
+ import AcpContractClient from "../../../src/acpContractClient";
5
+ import AcpJob from "../../../src/acpJob";
6
+ import { baseSepoliaAcpConfig } from "../../../src";
7
+ import {
8
+ EVALUATOR_AGENT_WALLET_ADDRESS,
9
+ WHITELISTED_WALLET_ENTITY_ID,
10
+ WHITELISTED_WALLET_PRIVATE_KEY
11
+ } from "./env";
12
+
13
+ async function evaluator() {
14
+ new AcpClient({
15
+ acpContractClient: await AcpContractClient.build(
16
+ WHITELISTED_WALLET_PRIVATE_KEY,
17
+ WHITELISTED_WALLET_ENTITY_ID,
18
+ EVALUATOR_AGENT_WALLET_ADDRESS,
19
+ baseSepoliaAcpConfig
20
+ ),
21
+ onEvaluate: async (job: AcpJob) => {
22
+ console.log("Evaluation function called", job);
23
+ await job.evaluate(true, "Externally evaluated and approved");
24
+ console.log(`Job ${job.id} evaluated`);
25
+ },
26
+ });
27
+ }
28
+
29
+ evaluator();
@@ -0,0 +1,46 @@
1
+ // TODO: Point the imports to acp-node after publishing
2
+
3
+ import AcpClient from "../../../src/acpClient";
4
+ import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient";
5
+ import AcpJob from "../../../src/acpJob";
6
+ import { baseSepoliaAcpConfig } from "../../../src";
7
+ import {
8
+ SELLER_AGENT_WALLET_ADDRESS,
9
+ WHITELISTED_WALLET_ENTITY_ID,
10
+ WHITELISTED_WALLET_PRIVATE_KEY
11
+ } from "./env";
12
+
13
+ async function seller() {
14
+ new AcpClient({
15
+ acpContractClient: await AcpContractClient.build(
16
+ WHITELISTED_WALLET_PRIVATE_KEY,
17
+ WHITELISTED_WALLET_ENTITY_ID,
18
+ SELLER_AGENT_WALLET_ADDRESS,
19
+ baseSepoliaAcpConfig
20
+ ),
21
+ onNewTask: async (job: AcpJob) => {
22
+ if (
23
+ job.phase === AcpJobPhases.REQUEST &&
24
+ job.memos.find((m) => m.nextPhase === AcpJobPhases.NEGOTIATION)
25
+ ) {
26
+ console.log("Responding to job", job);
27
+ await job.respond(true);
28
+ console.log(`Job ${job.id} responded`);
29
+ } else if (
30
+ job.phase === AcpJobPhases.TRANSACTION &&
31
+ job.memos.find((m) => m.nextPhase === AcpJobPhases.EVALUATION)
32
+ ) {
33
+ console.log("Delivering job", job);
34
+ await job.deliver(
35
+ JSON.stringify({
36
+ type: "url",
37
+ value: "https://example.com",
38
+ })
39
+ );
40
+ console.log(`Job ${job.id} delivered`);
41
+ }
42
+ },
43
+ });
44
+ }
45
+
46
+ seller();
@@ -0,0 +1,4 @@
1
+ WHITELISTED_WALLET_PRIVATE_KEY=0x-<whitelisted-wallet-private-key>
2
+ WHITELISTED_WALLET_ENTITY_ID=<whitelisted-wallet-entity-id>
3
+ BUYER_AGENT_WALLET_ADDRESS=<buyer-agent-wallet-address>
4
+ SELLER_AGENT_WALLET_ADDRESS=<seller-agent-wallet-address>
@@ -0,0 +1,54 @@
1
+ // TODO: Point the imports to acp-node after publishing
2
+
3
+ import AcpClient from "../../../src/acpClient";
4
+ import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient";
5
+ import AcpJob from "../../../src/acpJob";
6
+ import { baseSepoliaAcpConfig } from "../../../src";
7
+ import {
8
+ BUYER_AGENT_WALLET_ADDRESS,
9
+ WHITELISTED_WALLET_ENTITY_ID,
10
+ WHITELISTED_WALLET_PRIVATE_KEY
11
+ } from "./env";
12
+
13
+ async function buyer() {
14
+ const acpClient = new AcpClient({
15
+ acpContractClient: await AcpContractClient.build(
16
+ WHITELISTED_WALLET_PRIVATE_KEY,
17
+ WHITELISTED_WALLET_ENTITY_ID,
18
+ BUYER_AGENT_WALLET_ADDRESS,
19
+ baseSepoliaAcpConfig
20
+ ),
21
+ onNewTask: async (job: AcpJob) => {
22
+ if (
23
+ job.phase === AcpJobPhases.NEGOTIATION &&
24
+ job.memos.find((m) => m.nextPhase === AcpJobPhases.TRANSACTION)
25
+ ) {
26
+ console.log("Paying job", job);
27
+ await job.pay(1);
28
+ console.log(`Job ${job.id} paid`);
29
+ } else if (job.phase === AcpJobPhases.COMPLETED) {
30
+ console.log(`Job ${job.id} completed`);
31
+ }
32
+ },
33
+ onEvaluate: async (job: AcpJob) => {
34
+ console.log("Evaluation function called", job);
35
+ await job.evaluate(true, "Self-evaluated and approved");
36
+ console.log(`Job ${job.id} evaluated`);
37
+ },
38
+ });
39
+
40
+ const relevantAgents = await acpClient.browseAgents("meme", "999");
41
+ // Pick one of the agents based on your criteria (in this example we just pick the first one)
42
+ const chosenAgent = relevantAgents[0];
43
+ // Pick one of the service offerings based on your criteria (in this example we just pick the first one)
44
+ const chosenJobOffering = chosenAgent.offerings[0]
45
+
46
+ const jobId = await chosenJobOffering.initiateJob(
47
+ chosenJobOffering.requirementSchema || {},
48
+ new Date(Date.now() + 1000 * 60 * 60 * 24),
49
+ );
50
+
51
+ console.log(`Job ${jobId} initiated`);
52
+ }
53
+
54
+ buyer();
@@ -0,0 +1,21 @@
1
+ import dotenv from "dotenv";
2
+ import { Address } from "viem";
3
+
4
+ dotenv.config({ path: __dirname + '/.env' });
5
+
6
+ function getEnvVar<T extends string = string>(key: string, required = true): T {
7
+ const value = process.env[key];
8
+ if (required && (value === undefined || value === '')) {
9
+ throw new Error(`${key} is not defined or is empty in the .env file`);
10
+ }
11
+ return value as T;
12
+ }
13
+
14
+ export const WHITELISTED_WALLET_PRIVATE_KEY = getEnvVar<Address>('WHITELISTED_WALLET_PRIVATE_KEY');
15
+ export const WHITELISTED_WALLET_ENTITY_ID = parseInt(getEnvVar('WHITELISTED_WALLET_ENTITY_ID'), 10);
16
+ export const BUYER_AGENT_WALLET_ADDRESS = getEnvVar<Address>('BUYER_AGENT_WALLET_ADDRESS');
17
+ export const SELLER_AGENT_WALLET_ADDRESS = getEnvVar<Address>('SELLER_AGENT_WALLET_ADDRESS');
18
+
19
+ if (isNaN(WHITELISTED_WALLET_ENTITY_ID)) {
20
+ throw new Error('WHITELISTED_WALLET_ENTITY_ID must be a valid number in the .env file');
21
+ }
@@ -0,0 +1,46 @@
1
+ // TODO: Point the imports to acp-node after publishing
2
+
3
+ import AcpClient from "../../../src/acpClient";
4
+ import AcpContractClient, { AcpJobPhases } from "../../../src/acpContractClient";
5
+ import AcpJob from "../../../src/acpJob";
6
+ import { baseSepoliaAcpConfig } from "../../../src";
7
+ import {
8
+ SELLER_AGENT_WALLET_ADDRESS,
9
+ WHITELISTED_WALLET_ENTITY_ID,
10
+ WHITELISTED_WALLET_PRIVATE_KEY
11
+ } from "./env";
12
+
13
+ async function seller() {
14
+ new AcpClient({
15
+ acpContractClient: await AcpContractClient.build(
16
+ WHITELISTED_WALLET_PRIVATE_KEY,
17
+ WHITELISTED_WALLET_ENTITY_ID,
18
+ SELLER_AGENT_WALLET_ADDRESS,
19
+ baseSepoliaAcpConfig
20
+ ),
21
+ onNewTask: async (job: AcpJob) => {
22
+ if (
23
+ job.phase === AcpJobPhases.REQUEST &&
24
+ job.memos.find((m) => m.nextPhase === AcpJobPhases.NEGOTIATION)
25
+ ) {
26
+ console.log("Responding to job", job);
27
+ await job.respond(true);
28
+ console.log(`Job ${job.id} responded`);
29
+ } else if (
30
+ job.phase === AcpJobPhases.TRANSACTION &&
31
+ job.memos.find((m) => m.nextPhase === AcpJobPhases.EVALUATION)
32
+ ) {
33
+ console.log("Delivering job", job);
34
+ await job.deliver(
35
+ JSON.stringify({
36
+ type: "url",
37
+ value: "https://example.com",
38
+ })
39
+ );
40
+ console.log(`Job ${job.id} delivered`);
41
+ }
42
+ },
43
+ });
44
+ }
45
+
46
+ seller();
@@ -0,0 +1,3 @@
1
+ WHITELISTED_WALLET_PRIVATE_KEY=0x-<whitelisted-wallet-private-key>
2
+ WHITELISTED_WALLET_ENTITY_ID=<whitelisted-wallet-entity-id>
3
+ BUYER_AGENT_WALLET_ADDRESS=<buyer-agent-wallet-address>