Skip to content

Commit 57cd750

Browse files
committed
feat: nego feature
1 parent bee0b4c commit 57cd750

5 files changed

Lines changed: 116 additions & 9 deletions

File tree

src/acpClient.ts

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import { Address, parseEther } from "viem";
22
import { io } from "socket.io-client";
3-
import AcpContractClient, { AcpJobPhases, MemoType } from "./acpContractClient";
3+
import AcpContractClient, {
4+
AcpJobPhases,
5+
AcpNegoStatus,
6+
MemoType,
7+
} from "./acpContractClient";
48
import { AcpAgent } from "../interfaces";
59
import AcpJob from "./acpJob";
610
import AcpMemo from "./acpMemo";
711
import AcpJobOffering from "./acpJobOffering";
12+
import AcpMessage from "./acpMessage";
813

914
export interface IDeliverable {
1015
type: string;
@@ -29,6 +34,7 @@ interface IAcpJob {
2934
data: {
3035
onChainJobId: number;
3136
phase: AcpJobPhases;
37+
negoStatus: AcpNegoStatus;
3238
description: string;
3339
buyerAddress: `0x${string}`;
3440
sellerAddress: `0x${string}`;
@@ -57,12 +63,15 @@ interface IAcpClientOptions {
5763
acpContractClient: AcpContractClient;
5864
onNewTask?: (job: AcpJob) => void;
5965
onEvaluate?: (job: AcpJob) => void;
66+
onNewMsg?: (msg: AcpMessage, job: AcpJob) => void;
6067
}
6168

62-
enum SocketEvents {
69+
export enum SocketEvents {
6370
ROOM_JOINED = "roomJoined",
6471
ON_EVALUATE = "onEvaluate",
6572
ON_NEW_TASK = "onNewTask",
73+
ON_NEW_MSG = "onNewMsg",
74+
ON_CREATE_MSG = "onCreateMsg",
6675
}
6776
export class EvaluateResult {
6877
isApproved: boolean;
@@ -76,15 +85,16 @@ export class EvaluateResult {
7685

7786
class AcpClient {
7887
private acpUrl;
88+
private acpJob: AcpJob | null = null;
7989
public acpContractClient: AcpContractClient;
8090
private onNewTask?: (job: AcpJob) => void;
8191
private onEvaluate?: (job: AcpJob) => void;
82-
92+
private onNewMsg?: (msg: AcpMessage, job: AcpJob) => void;
8393
constructor(options: IAcpClientOptions) {
8494
this.acpContractClient = options.acpContractClient;
8595
this.onNewTask = options.onNewTask;
8696
this.onEvaluate = options.onEvaluate || this.defaultOnEvaluate;
87-
97+
this.onNewMsg = options.onNewMsg;
8898
this.acpUrl = this.acpContractClient.config.acpUrl;
8999
this.init();
90100
}
@@ -129,9 +139,12 @@ class AcpClient {
129139
memo.nextPhase
130140
);
131141
}),
132-
data.phase
142+
data.phase,
143+
data.negoStatus
133144
);
134145

146+
this.acpJob = job;
147+
135148
this.onEvaluate(job);
136149
}
137150
}
@@ -156,14 +169,35 @@ class AcpClient {
156169
memo.nextPhase
157170
);
158171
}),
159-
data.phase
172+
data.phase,
173+
data.negoStatus
160174
);
161175

176+
this.acpJob = job;
177+
162178
this.onNewTask(job);
163179
}
164180
}
165181
);
166182

183+
socket.on(SocketEvents.ON_NEW_MSG, (data, callback) => {
184+
callback(true);
185+
186+
if (this.onNewMsg && this.acpJob) {
187+
this.acpJob.negoStatus = AcpNegoStatus.PENDING;
188+
189+
const msg = new AcpMessage(
190+
data.id,
191+
data.messages ?? [],
192+
socket,
193+
this.acpJob,
194+
this.acpContractClient.walletAddress
195+
);
196+
197+
this.onNewMsg(msg, this.acpJob);
198+
}
199+
});
200+
167201
const cleanup = async () => {
168202
if (socket) {
169203
socket.disconnect();

src/acpContractClient.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ export enum AcpJobPhases {
2626
REJECTED = 5,
2727
}
2828

29+
export enum AcpNegoStatus {
30+
PENDING = "PENDING",
31+
AGREED = "AGREED",
32+
DISAGREED = "DISAGREED",
33+
NOT_STARTED = "NOT_STARTED",
34+
}
35+
2936
class AcpContractClient {
3037
private _sessionKeyClient: ModularAccountV2Client | undefined;
3138

src/acpJob.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import AcpClient from "./acpClient";
2-
import { AcpJobPhases } from "./acpContractClient";
2+
import { AcpJobPhases, AcpNegoStatus } from "./acpContractClient";
33
import AcpMemo from "./acpMemo";
44

55
class AcpJob {
@@ -8,7 +8,8 @@ class AcpJob {
88
public id: number,
99
public providerAddress: string,
1010
public memos: AcpMemo[],
11-
public phase: AcpJobPhases
11+
public phase: AcpJobPhases,
12+
public negoStatus: AcpNegoStatus
1213
) {}
1314

1415
async pay(amount: number, reason?: string) {

src/acpMessage.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { Socket } from "socket.io-client";
2+
import { SocketEvents } from "./acpClient";
3+
import AcpJob from "./acpJob";
4+
import { AcpJobPhases, AcpNegoStatus } from "./acpContractClient";
5+
import { Address } from "viem";
6+
7+
interface Message {
8+
id: number;
9+
sender: Address;
10+
recipient: Address;
11+
content: string;
12+
timestamp: number;
13+
}
14+
15+
class AcpMessage {
16+
constructor(
17+
public id: number,
18+
public messages: Message[],
19+
public socket: Socket,
20+
public acpJob: AcpJob | null,
21+
public walletAddress: Address
22+
) {}
23+
24+
initOrReply(message: string) {
25+
if (!this.acpJob) {
26+
throw new Error("Cannot initiate or reply conversation without job");
27+
}
28+
29+
if (this.acpJob.negoStatus !== AcpNegoStatus.PENDING) {
30+
throw new Error(
31+
"Cannot initiate or reply conversation in non-negotiation phase"
32+
);
33+
}
34+
35+
if (
36+
this.messages.length > 0 &&
37+
this.messages[this.messages.length - 1].sender === this.walletAddress
38+
) {
39+
throw new Error("Cannot reply to own message");
40+
}
41+
42+
this.socket.timeout(5000).emit(
43+
SocketEvents.ON_CREATE_MSG,
44+
{
45+
jobId: this.acpJob.id,
46+
content: message,
47+
sender: this.walletAddress,
48+
recipient:
49+
this.messages.length > 0
50+
? this.messages[this.messages.length - 1].sender
51+
: this.acpJob.providerAddress,
52+
},
53+
(err: any, response: any) => {
54+
if (err || !response) {
55+
console.log(`Message not received`, err);
56+
} else {
57+
console.log(`Message received`);
58+
}
59+
}
60+
);
61+
}
62+
}
63+
64+
export default AcpMessage;

src/configs.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ const baseSepoliaAcpConfig: AcpContractConfig = {
1212
chain: baseSepolia,
1313
contractAddress: "0x2422c1c43451Eb69Ff49dfD39c4Dc8C5230fA1e6",
1414
virtualsTokenAddress: "0xbfAB80ccc15DF6fb7185f9498d6039317331846a",
15-
acpUrl: "https://acpx-staging.virtuals.io",
15+
acpUrl: "http://localhost:1337",
16+
// acpUrl: "https://acpx-staging.virtuals.io",
1617
};
1718

1819
const baseAcpConfig: AcpContractConfig = {

0 commit comments

Comments
 (0)