@abbababa/sdk 0.1.1 → 0.3.0
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 +86 -10
- package/dist/buyer.d.ts +26 -11
- package/dist/buyer.d.ts.map +1 -1
- package/dist/buyer.js +48 -15
- package/dist/buyer.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/seller.d.ts +30 -2
- package/dist/seller.d.ts.map +1 -1
- package/dist/seller.js +66 -1
- package/dist/seller.js.map +1 -1
- package/dist/types.d.ts +36 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +21 -1
- package/dist/types.js.map +1 -1
- package/dist/wallet/abi.d.ts +288 -49
- package/dist/wallet/abi.d.ts.map +1 -1
- package/dist/wallet/abi.js +216 -43
- package/dist/wallet/abi.js.map +1 -1
- package/dist/wallet/constants.d.ts +14 -8
- package/dist/wallet/constants.d.ts.map +1 -1
- package/dist/wallet/constants.js +24 -20
- package/dist/wallet/constants.js.map +1 -1
- package/dist/wallet/escrow.d.ts +112 -15
- package/dist/wallet/escrow.d.ts.map +1 -1
- package/dist/wallet/escrow.js +322 -84
- package/dist/wallet/escrow.js.map +1 -1
- package/dist/wallet/index.d.ts +2 -2
- package/dist/wallet/index.d.ts.map +1 -1
- package/dist/wallet/index.js +6 -8
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/session-keys.d.ts +9 -6
- package/dist/wallet/session-keys.d.ts.map +1 -1
- package/dist/wallet/session-keys.js +53 -54
- package/dist/wallet/session-keys.js.map +1 -1
- package/dist/wallet/smart-account.d.ts.map +1 -1
- package/dist/wallet/smart-account.js +4 -3
- package/dist/wallet/smart-account.js.map +1 -1
- package/package.json +2 -1
package/dist/wallet/escrow.d.ts
CHANGED
|
@@ -1,21 +1,39 @@
|
|
|
1
1
|
import { type TokenInfo } from './constants.js';
|
|
2
|
-
import type { EscrowDetails } from '../types.js';
|
|
2
|
+
import type { EscrowDetails, AgentStats } from '../types.js';
|
|
3
|
+
/** Dispute resolution outcome */
|
|
4
|
+
export declare enum DisputeOutcome {
|
|
5
|
+
None = 0,
|
|
6
|
+
BuyerRefund = 1,
|
|
7
|
+
SellerPaid = 2,
|
|
8
|
+
Split = 3
|
|
9
|
+
}
|
|
10
|
+
/** Escrow status codes */
|
|
11
|
+
export declare enum EscrowStatus {
|
|
12
|
+
None = 0,
|
|
13
|
+
Funded = 1,
|
|
14
|
+
Delivered = 2,
|
|
15
|
+
Released = 3,
|
|
16
|
+
Refunded = 4,
|
|
17
|
+
Disputed = 5,
|
|
18
|
+
Resolved = 6,
|
|
19
|
+
Abandoned = 7
|
|
20
|
+
}
|
|
3
21
|
/**
|
|
4
|
-
* Client for interacting with the
|
|
5
|
-
* Supports
|
|
22
|
+
* Client for interacting with the AbbababaEscrowV1 smart contract.
|
|
23
|
+
* Supports UUPS upgradeable escrow with criteriaHash, 3-tier dispute resolution,
|
|
24
|
+
* 24h dispute window, auto-release, and abandonment detection.
|
|
6
25
|
* Uses a ZeroDev Kernel account client for sending UserOperations.
|
|
7
26
|
*/
|
|
8
27
|
export declare class EscrowClient {
|
|
9
28
|
private kernelClient;
|
|
10
29
|
private chainId;
|
|
11
30
|
private escrowAddress;
|
|
12
|
-
private escrowVersion;
|
|
13
31
|
private tokenAddress;
|
|
14
32
|
private tokenDecimals;
|
|
15
33
|
constructor(kernelClient: unknown, token?: TokenInfo, chainId?: number);
|
|
16
34
|
/**
|
|
17
35
|
* Convert a platform transaction ID (CUID string) to a bytes32 escrow ID.
|
|
18
|
-
* Uses keccak256, matching the existing backend pattern
|
|
36
|
+
* Uses keccak256, matching the existing backend pattern.
|
|
19
37
|
*/
|
|
20
38
|
static toEscrowId(transactionId: string): `0x${string}`;
|
|
21
39
|
/**
|
|
@@ -23,23 +41,102 @@ export declare class EscrowClient {
|
|
|
23
41
|
* Must be called before fundEscrow.
|
|
24
42
|
*/
|
|
25
43
|
approveToken(amount: bigint): Promise<string>;
|
|
26
|
-
/** @deprecated Use approveToken() instead. */
|
|
27
|
-
approveUSDC(amount: bigint): Promise<string>;
|
|
28
44
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
|
|
45
|
+
* Generate a criteriaHash from success criteria JSON.
|
|
46
|
+
* The criteriaHash is stored on-chain to enable Tier 1 algorithmic resolution.
|
|
47
|
+
*/
|
|
48
|
+
static toCriteriaHash(criteria: object | string): `0x${string}`;
|
|
49
|
+
/**
|
|
50
|
+
* Fund an escrow. Calls V1 createEscrow with 6 args including deadline and criteriaHash.
|
|
32
51
|
* The contract will safeTransferFrom the token (amount + 1% buyer fee) from the caller.
|
|
52
|
+
*
|
|
53
|
+
* @param transactionId - Platform transaction ID (CUID)
|
|
54
|
+
* @param sellerAddress - Seller's wallet address
|
|
55
|
+
* @param amount - Amount in smallest token units (e.g., USDC with 6 decimals)
|
|
56
|
+
* @param deadline - Unix timestamp for delivery deadline
|
|
57
|
+
* @param criteriaHash - keccak256 hash of success criteria JSON (enables algorithmic dispute resolution)
|
|
58
|
+
*/
|
|
59
|
+
fundEscrow(transactionId: string, sellerAddress: string, amount: bigint, deadline: bigint, criteriaHash?: `0x${string}`): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Submit delivery proof on-chain. Called by the seller after completing work.
|
|
62
|
+
*/
|
|
63
|
+
submitDelivery(transactionId: string, proofHash: `0x${string}`): Promise<string>;
|
|
64
|
+
/**
|
|
65
|
+
* Accept delivery and release funds immediately. Called by the buyer.
|
|
66
|
+
*/
|
|
67
|
+
acceptDelivery(transactionId: string): Promise<string>;
|
|
68
|
+
/**
|
|
69
|
+
* Finalize release after the 24h dispute window has passed without a dispute.
|
|
70
|
+
* Can be called by anyone.
|
|
33
71
|
*/
|
|
34
|
-
|
|
72
|
+
finalizeRelease(transactionId: string): Promise<string>;
|
|
35
73
|
/**
|
|
36
|
-
*
|
|
37
|
-
* Callable by the buyer or an arbitrator.
|
|
74
|
+
* Dispute a delivery within the 24h dispute window. Called by the buyer.
|
|
38
75
|
*/
|
|
39
|
-
|
|
76
|
+
disputeEscrow(transactionId: string): Promise<string>;
|
|
40
77
|
/**
|
|
41
|
-
*
|
|
78
|
+
* Claim funds for an abandoned escrow (deadline + 7 days passed with no delivery).
|
|
79
|
+
* Called by the buyer to reclaim funds.
|
|
80
|
+
*/
|
|
81
|
+
claimAbandoned(transactionId: string): Promise<string>;
|
|
82
|
+
/**
|
|
83
|
+
* Read escrow details from the V1 contract (view function, no gas needed).
|
|
42
84
|
*/
|
|
43
85
|
getEscrow(transactionId: string): Promise<EscrowDetails | null>;
|
|
86
|
+
/**
|
|
87
|
+
* Check if the 24h dispute window is currently active for an escrow.
|
|
88
|
+
*/
|
|
89
|
+
isDisputeWindowActive(transactionId: string): Promise<boolean>;
|
|
90
|
+
/**
|
|
91
|
+
* Check if an escrow can be finalized (dispute window passed, no dispute filed).
|
|
92
|
+
*/
|
|
93
|
+
canFinalize(transactionId: string): Promise<boolean>;
|
|
94
|
+
/**
|
|
95
|
+
* Check if an escrow can be claimed as abandoned (deadline + 7 days passed).
|
|
96
|
+
*/
|
|
97
|
+
canClaimAbandoned(transactionId: string): Promise<boolean>;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Read-only client for the AbbababaScoreV1 on-chain reputation system.
|
|
101
|
+
* No wallet needed — all methods are view functions.
|
|
102
|
+
*/
|
|
103
|
+
export declare class ScoreClient {
|
|
104
|
+
private chainId;
|
|
105
|
+
private scoreAddress;
|
|
106
|
+
constructor(chainId?: number);
|
|
107
|
+
private getPublicClient;
|
|
108
|
+
/**
|
|
109
|
+
* Get an agent's trust score (int256 — can be negative).
|
|
110
|
+
*/
|
|
111
|
+
getScore(agentAddress: string): Promise<bigint>;
|
|
112
|
+
/**
|
|
113
|
+
* Get full agent stats from the reputation contract.
|
|
114
|
+
*/
|
|
115
|
+
getAgentStats(agentAddress: string): Promise<AgentStats>;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Client for interacting with the AbbababaResolverV1 contract.
|
|
119
|
+
* Used for submitting dispute resolutions (requires appropriate role).
|
|
120
|
+
*/
|
|
121
|
+
export declare class ResolverClient {
|
|
122
|
+
private kernelClient;
|
|
123
|
+
private chainId;
|
|
124
|
+
private resolverAddress;
|
|
125
|
+
constructor(kernelClient: unknown, chainId?: number);
|
|
126
|
+
/**
|
|
127
|
+
* Submit Tier 1 algorithmic resolution.
|
|
128
|
+
* Requires ALGORITHM_ROLE on the resolver contract.
|
|
129
|
+
*/
|
|
130
|
+
submitAlgorithmicResolution(transactionId: string, outcome: DisputeOutcome, buyerPercent: number, sellerPercent: number, reason: string): Promise<string>;
|
|
131
|
+
/**
|
|
132
|
+
* Submit Tier 2 peer arbitration result.
|
|
133
|
+
* Requires PEER_ARBITER_ROLE on the resolver contract.
|
|
134
|
+
*/
|
|
135
|
+
submitPeerArbitrationResult(transactionId: string, outcome: DisputeOutcome, buyerPercent: number, sellerPercent: number, reviewers: [string, string, string, string, string]): Promise<string>;
|
|
136
|
+
/**
|
|
137
|
+
* Submit Tier 3 human review result.
|
|
138
|
+
* Requires HUMAN_REVIEWER_ROLE on the resolver contract.
|
|
139
|
+
*/
|
|
140
|
+
submitHumanReview(transactionId: string, outcome: DisputeOutcome, buyerPercent: number, sellerPercent: number, reason: string): Promise<string>;
|
|
44
141
|
}
|
|
45
142
|
//# sourceMappingURL=escrow.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"escrow.d.ts","sourceRoot":"","sources":["../../src/wallet/escrow.ts"],"names":[],"mappings":"AAWA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"escrow.d.ts","sourceRoot":"","sources":["../../src/wallet/escrow.ts"],"names":[],"mappings":"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"}
|
package/dist/wallet/escrow.js
CHANGED
|
@@ -1,58 +1,68 @@
|
|
|
1
1
|
import { encodeFunctionData, keccak256, toBytes, createPublicClient, http, } from 'viem';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { baseSepolia, base } from 'viem/chains';
|
|
3
|
+
import { ABBABABA_ESCROW_ABI, ABBABABA_SCORE_ABI, ABBABABA_RESOLVER_ABI, ERC20_ABI } from './abi.js';
|
|
4
|
+
import { ESCROW_V1_ADDRESSES, SCORE_V1_ADDRESSES, RESOLVER_V1_ADDRESSES, BASE_SEPOLIA_CHAIN_ID, BASE_MAINNET_CHAIN_ID, getToken, } from './constants.js';
|
|
5
|
+
/** Dispute resolution outcome */
|
|
6
|
+
export var DisputeOutcome;
|
|
7
|
+
(function (DisputeOutcome) {
|
|
8
|
+
DisputeOutcome[DisputeOutcome["None"] = 0] = "None";
|
|
9
|
+
DisputeOutcome[DisputeOutcome["BuyerRefund"] = 1] = "BuyerRefund";
|
|
10
|
+
DisputeOutcome[DisputeOutcome["SellerPaid"] = 2] = "SellerPaid";
|
|
11
|
+
DisputeOutcome[DisputeOutcome["Split"] = 3] = "Split";
|
|
12
|
+
})(DisputeOutcome || (DisputeOutcome = {}));
|
|
13
|
+
/** Escrow status codes */
|
|
14
|
+
export var EscrowStatus;
|
|
15
|
+
(function (EscrowStatus) {
|
|
16
|
+
EscrowStatus[EscrowStatus["None"] = 0] = "None";
|
|
17
|
+
EscrowStatus[EscrowStatus["Funded"] = 1] = "Funded";
|
|
18
|
+
EscrowStatus[EscrowStatus["Delivered"] = 2] = "Delivered";
|
|
19
|
+
EscrowStatus[EscrowStatus["Released"] = 3] = "Released";
|
|
20
|
+
EscrowStatus[EscrowStatus["Refunded"] = 4] = "Refunded";
|
|
21
|
+
EscrowStatus[EscrowStatus["Disputed"] = 5] = "Disputed";
|
|
22
|
+
EscrowStatus[EscrowStatus["Resolved"] = 6] = "Resolved";
|
|
23
|
+
EscrowStatus[EscrowStatus["Abandoned"] = 7] = "Abandoned";
|
|
24
|
+
})(EscrowStatus || (EscrowStatus = {}));
|
|
5
25
|
const CHAINS = {
|
|
6
|
-
[POLYGON_AMOY_CHAIN_ID]: polygonAmoy,
|
|
7
|
-
[POLYGON_MAINNET_CHAIN_ID]: polygon,
|
|
8
26
|
[BASE_SEPOLIA_CHAIN_ID]: baseSepolia,
|
|
9
27
|
[BASE_MAINNET_CHAIN_ID]: base,
|
|
10
28
|
};
|
|
29
|
+
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
|
|
30
|
+
const ZERO_BYTES32 = '0x0000000000000000000000000000000000000000000000000000000000000000';
|
|
11
31
|
/**
|
|
12
|
-
* Client for interacting with the
|
|
13
|
-
* Supports
|
|
32
|
+
* Client for interacting with the AbbababaEscrowV1 smart contract.
|
|
33
|
+
* Supports UUPS upgradeable escrow with criteriaHash, 3-tier dispute resolution,
|
|
34
|
+
* 24h dispute window, auto-release, and abandonment detection.
|
|
14
35
|
* Uses a ZeroDev Kernel account client for sending UserOperations.
|
|
15
36
|
*/
|
|
16
37
|
export class EscrowClient {
|
|
17
38
|
kernelClient;
|
|
18
39
|
chainId;
|
|
19
40
|
escrowAddress;
|
|
20
|
-
escrowVersion;
|
|
21
41
|
tokenAddress;
|
|
22
42
|
tokenDecimals;
|
|
23
43
|
constructor(kernelClient, token, chainId = BASE_SEPOLIA_CHAIN_ID) {
|
|
24
44
|
this.kernelClient = kernelClient;
|
|
25
45
|
this.chainId = chainId;
|
|
26
|
-
// Resolve token (default USDC
|
|
46
|
+
// Resolve token (default USDC)
|
|
27
47
|
if (token) {
|
|
28
48
|
this.tokenAddress = token.address;
|
|
29
49
|
this.tokenDecimals = token.decimals;
|
|
30
50
|
}
|
|
31
51
|
else {
|
|
32
|
-
const usdc =
|
|
52
|
+
const usdc = getToken(chainId, 'USDC');
|
|
33
53
|
if (!usdc)
|
|
34
54
|
throw new Error(`No USDC address for chain ${chainId}`);
|
|
35
|
-
this.tokenAddress = usdc;
|
|
36
|
-
this.tokenDecimals =
|
|
37
|
-
}
|
|
38
|
-
// Try V3 first, fall back to V2
|
|
39
|
-
const v3 = ESCROW_ADDRESSES[chainId];
|
|
40
|
-
const v2 = ESCROW_V2_ADDRESSES[chainId];
|
|
41
|
-
if (v3) {
|
|
42
|
-
this.escrowAddress = v3;
|
|
43
|
-
this.escrowVersion = 3;
|
|
44
|
-
}
|
|
45
|
-
else if (v2) {
|
|
46
|
-
this.escrowAddress = v2;
|
|
47
|
-
this.escrowVersion = 2;
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
throw new Error(`No escrow contract for chain ${chainId}`);
|
|
55
|
+
this.tokenAddress = usdc.address;
|
|
56
|
+
this.tokenDecimals = usdc.decimals;
|
|
51
57
|
}
|
|
58
|
+
const v1 = ESCROW_V1_ADDRESSES[chainId];
|
|
59
|
+
if (!v1)
|
|
60
|
+
throw new Error(`No V1 escrow contract for chain ${chainId}`);
|
|
61
|
+
this.escrowAddress = v1;
|
|
52
62
|
}
|
|
53
63
|
/**
|
|
54
64
|
* Convert a platform transaction ID (CUID string) to a bytes32 escrow ID.
|
|
55
|
-
* Uses keccak256, matching the existing backend pattern
|
|
65
|
+
* Uses keccak256, matching the existing backend pattern.
|
|
56
66
|
*/
|
|
57
67
|
static toEscrowId(transactionId) {
|
|
58
68
|
return keccak256(toBytes(transactionId));
|
|
@@ -76,33 +86,31 @@ export class EscrowClient {
|
|
|
76
86
|
});
|
|
77
87
|
return txHash;
|
|
78
88
|
}
|
|
79
|
-
/**
|
|
80
|
-
|
|
81
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Generate a criteriaHash from success criteria JSON.
|
|
91
|
+
* The criteriaHash is stored on-chain to enable Tier 1 algorithmic resolution.
|
|
92
|
+
*/
|
|
93
|
+
static toCriteriaHash(criteria) {
|
|
94
|
+
const json = typeof criteria === 'string' ? criteria : JSON.stringify(criteria);
|
|
95
|
+
return keccak256(toBytes(json));
|
|
82
96
|
}
|
|
83
97
|
/**
|
|
84
|
-
* Fund an escrow. Calls createEscrow
|
|
85
|
-
* V3: passes token address as 4th argument.
|
|
86
|
-
* V2 fallback: USDC only (3 arguments).
|
|
98
|
+
* Fund an escrow. Calls V1 createEscrow with 6 args including deadline and criteriaHash.
|
|
87
99
|
* The contract will safeTransferFrom the token (amount + 1% buyer fee) from the caller.
|
|
100
|
+
*
|
|
101
|
+
* @param transactionId - Platform transaction ID (CUID)
|
|
102
|
+
* @param sellerAddress - Seller's wallet address
|
|
103
|
+
* @param amount - Amount in smallest token units (e.g., USDC with 6 decimals)
|
|
104
|
+
* @param deadline - Unix timestamp for delivery deadline
|
|
105
|
+
* @param criteriaHash - keccak256 hash of success criteria JSON (enables algorithmic dispute resolution)
|
|
88
106
|
*/
|
|
89
|
-
async fundEscrow(transactionId, sellerAddress, amount) {
|
|
107
|
+
async fundEscrow(transactionId, sellerAddress, amount, deadline, criteriaHash = '0x0000000000000000000000000000000000000000000000000000000000000000') {
|
|
90
108
|
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
args: [escrowId, sellerAddress, amount, this.tokenAddress],
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
data = encodeFunctionData({
|
|
101
|
-
abi: SERVICE_ESCROW_V2_ABI,
|
|
102
|
-
functionName: 'createEscrow',
|
|
103
|
-
args: [escrowId, sellerAddress, amount],
|
|
104
|
-
});
|
|
105
|
-
}
|
|
109
|
+
const data = encodeFunctionData({
|
|
110
|
+
abi: ABBABABA_ESCROW_ABI,
|
|
111
|
+
functionName: 'createEscrow',
|
|
112
|
+
args: [escrowId, sellerAddress, amount, this.tokenAddress, deadline, criteriaHash],
|
|
113
|
+
});
|
|
106
114
|
const txHash = await this.kernelClient.sendTransaction({
|
|
107
115
|
to: this.escrowAddress,
|
|
108
116
|
data,
|
|
@@ -110,15 +118,29 @@ export class EscrowClient {
|
|
|
110
118
|
return txHash;
|
|
111
119
|
}
|
|
112
120
|
/**
|
|
113
|
-
*
|
|
114
|
-
* Callable by the buyer or an arbitrator.
|
|
121
|
+
* Submit delivery proof on-chain. Called by the seller after completing work.
|
|
115
122
|
*/
|
|
116
|
-
async
|
|
123
|
+
async submitDelivery(transactionId, proofHash) {
|
|
117
124
|
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
118
|
-
const abi = this.escrowVersion === 3 ? SERVICE_ESCROW_V3_ABI : SERVICE_ESCROW_V2_ABI;
|
|
119
125
|
const data = encodeFunctionData({
|
|
120
|
-
abi,
|
|
121
|
-
functionName: '
|
|
126
|
+
abi: ABBABABA_ESCROW_ABI,
|
|
127
|
+
functionName: 'submitDelivery',
|
|
128
|
+
args: [escrowId, proofHash],
|
|
129
|
+
});
|
|
130
|
+
const txHash = await this.kernelClient.sendTransaction({
|
|
131
|
+
to: this.escrowAddress,
|
|
132
|
+
data,
|
|
133
|
+
});
|
|
134
|
+
return txHash;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Accept delivery and release funds immediately. Called by the buyer.
|
|
138
|
+
*/
|
|
139
|
+
async acceptDelivery(transactionId) {
|
|
140
|
+
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
141
|
+
const data = encodeFunctionData({
|
|
142
|
+
abi: ABBABABA_ESCROW_ABI,
|
|
143
|
+
functionName: 'accept',
|
|
122
144
|
args: [escrowId],
|
|
123
145
|
});
|
|
124
146
|
const txHash = await this.kernelClient.sendTransaction({
|
|
@@ -128,57 +150,273 @@ export class EscrowClient {
|
|
|
128
150
|
return txHash;
|
|
129
151
|
}
|
|
130
152
|
/**
|
|
131
|
-
*
|
|
153
|
+
* Finalize release after the 24h dispute window has passed without a dispute.
|
|
154
|
+
* Can be called by anyone.
|
|
155
|
+
*/
|
|
156
|
+
async finalizeRelease(transactionId) {
|
|
157
|
+
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
158
|
+
const data = encodeFunctionData({
|
|
159
|
+
abi: ABBABABA_ESCROW_ABI,
|
|
160
|
+
functionName: 'finalizeRelease',
|
|
161
|
+
args: [escrowId],
|
|
162
|
+
});
|
|
163
|
+
const txHash = await this.kernelClient.sendTransaction({
|
|
164
|
+
to: this.escrowAddress,
|
|
165
|
+
data,
|
|
166
|
+
});
|
|
167
|
+
return txHash;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Dispute a delivery within the 24h dispute window. Called by the buyer.
|
|
171
|
+
*/
|
|
172
|
+
async disputeEscrow(transactionId) {
|
|
173
|
+
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
174
|
+
const data = encodeFunctionData({
|
|
175
|
+
abi: ABBABABA_ESCROW_ABI,
|
|
176
|
+
functionName: 'dispute',
|
|
177
|
+
args: [escrowId],
|
|
178
|
+
});
|
|
179
|
+
const txHash = await this.kernelClient.sendTransaction({
|
|
180
|
+
to: this.escrowAddress,
|
|
181
|
+
data,
|
|
182
|
+
});
|
|
183
|
+
return txHash;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Claim funds for an abandoned escrow (deadline + 7 days passed with no delivery).
|
|
187
|
+
* Called by the buyer to reclaim funds.
|
|
188
|
+
*/
|
|
189
|
+
async claimAbandoned(transactionId) {
|
|
190
|
+
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
191
|
+
const data = encodeFunctionData({
|
|
192
|
+
abi: ABBABABA_ESCROW_ABI,
|
|
193
|
+
functionName: 'claimAbandoned',
|
|
194
|
+
args: [escrowId],
|
|
195
|
+
});
|
|
196
|
+
const txHash = await this.kernelClient.sendTransaction({
|
|
197
|
+
to: this.escrowAddress,
|
|
198
|
+
data,
|
|
199
|
+
});
|
|
200
|
+
return txHash;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Read escrow details from the V1 contract (view function, no gas needed).
|
|
132
204
|
*/
|
|
133
205
|
async getEscrow(transactionId) {
|
|
134
206
|
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
135
|
-
const viemChain = CHAINS[this.chainId] ??
|
|
207
|
+
const viemChain = CHAINS[this.chainId] ?? baseSepolia;
|
|
136
208
|
const publicClient = createPublicClient({
|
|
137
209
|
chain: viemChain,
|
|
138
210
|
transport: http(),
|
|
139
211
|
});
|
|
140
|
-
if (this.escrowVersion === 3) {
|
|
141
|
-
const result = await publicClient.readContract({
|
|
142
|
-
address: this.escrowAddress,
|
|
143
|
-
abi: SERVICE_ESCROW_V3_ABI,
|
|
144
|
-
functionName: 'getEscrow',
|
|
145
|
-
args: [escrowId],
|
|
146
|
-
});
|
|
147
|
-
const [token, buyer, seller, amount, buyerFee, status, createdAt, expiresAt] = result;
|
|
148
|
-
if (buyer === '0x0000000000000000000000000000000000000000') {
|
|
149
|
-
return null;
|
|
150
|
-
}
|
|
151
|
-
return {
|
|
152
|
-
token,
|
|
153
|
-
buyer,
|
|
154
|
-
seller,
|
|
155
|
-
amount,
|
|
156
|
-
buyerFee,
|
|
157
|
-
status,
|
|
158
|
-
createdAt: Number(createdAt),
|
|
159
|
-
expiresAt: Number(expiresAt),
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
// V2 fallback
|
|
163
212
|
const result = await publicClient.readContract({
|
|
164
213
|
address: this.escrowAddress,
|
|
165
|
-
abi:
|
|
214
|
+
abi: ABBABABA_ESCROW_ABI,
|
|
166
215
|
functionName: 'getEscrow',
|
|
167
216
|
args: [escrowId],
|
|
168
217
|
});
|
|
169
|
-
const [buyer, seller, amount, buyerFee, status, createdAt,
|
|
170
|
-
if (buyer ===
|
|
218
|
+
const [token, buyer, seller, amount, buyerFee, status, createdAt, deadline, deliveredAt, proofHash, criteriaHash] = result;
|
|
219
|
+
if (buyer === ZERO_ADDRESS) {
|
|
171
220
|
return null;
|
|
172
221
|
}
|
|
173
222
|
return {
|
|
223
|
+
token,
|
|
174
224
|
buyer,
|
|
175
225
|
seller,
|
|
176
226
|
amount,
|
|
177
227
|
buyerFee,
|
|
178
228
|
status,
|
|
179
229
|
createdAt: Number(createdAt),
|
|
180
|
-
|
|
230
|
+
deadline: Number(deadline),
|
|
231
|
+
deliveredAt: Number(deliveredAt),
|
|
232
|
+
proofHash: proofHash === ZERO_BYTES32 ? null : proofHash,
|
|
233
|
+
criteriaHash: criteriaHash === ZERO_BYTES32 ? null : criteriaHash,
|
|
181
234
|
};
|
|
182
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* Check if the 24h dispute window is currently active for an escrow.
|
|
238
|
+
*/
|
|
239
|
+
async isDisputeWindowActive(transactionId) {
|
|
240
|
+
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
241
|
+
const viemChain = CHAINS[this.chainId] ?? baseSepolia;
|
|
242
|
+
const publicClient = createPublicClient({
|
|
243
|
+
chain: viemChain,
|
|
244
|
+
transport: http(),
|
|
245
|
+
});
|
|
246
|
+
const result = await publicClient.readContract({
|
|
247
|
+
address: this.escrowAddress,
|
|
248
|
+
abi: ABBABABA_ESCROW_ABI,
|
|
249
|
+
functionName: 'isDisputeWindowActive',
|
|
250
|
+
args: [escrowId],
|
|
251
|
+
});
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Check if an escrow can be finalized (dispute window passed, no dispute filed).
|
|
256
|
+
*/
|
|
257
|
+
async canFinalize(transactionId) {
|
|
258
|
+
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
259
|
+
const viemChain = CHAINS[this.chainId] ?? baseSepolia;
|
|
260
|
+
const publicClient = createPublicClient({
|
|
261
|
+
chain: viemChain,
|
|
262
|
+
transport: http(),
|
|
263
|
+
});
|
|
264
|
+
const result = await publicClient.readContract({
|
|
265
|
+
address: this.escrowAddress,
|
|
266
|
+
abi: ABBABABA_ESCROW_ABI,
|
|
267
|
+
functionName: 'canFinalize',
|
|
268
|
+
args: [escrowId],
|
|
269
|
+
});
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Check if an escrow can be claimed as abandoned (deadline + 7 days passed).
|
|
274
|
+
*/
|
|
275
|
+
async canClaimAbandoned(transactionId) {
|
|
276
|
+
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
277
|
+
const viemChain = CHAINS[this.chainId] ?? baseSepolia;
|
|
278
|
+
const publicClient = createPublicClient({
|
|
279
|
+
chain: viemChain,
|
|
280
|
+
transport: http(),
|
|
281
|
+
});
|
|
282
|
+
const result = await publicClient.readContract({
|
|
283
|
+
address: this.escrowAddress,
|
|
284
|
+
abi: ABBABABA_ESCROW_ABI,
|
|
285
|
+
functionName: 'canClaimAbandoned',
|
|
286
|
+
args: [escrowId],
|
|
287
|
+
});
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Read-only client for the AbbababaScoreV1 on-chain reputation system.
|
|
293
|
+
* No wallet needed — all methods are view functions.
|
|
294
|
+
*/
|
|
295
|
+
export class ScoreClient {
|
|
296
|
+
chainId;
|
|
297
|
+
scoreAddress;
|
|
298
|
+
constructor(chainId = BASE_SEPOLIA_CHAIN_ID) {
|
|
299
|
+
this.chainId = chainId;
|
|
300
|
+
const addr = SCORE_V1_ADDRESSES[chainId];
|
|
301
|
+
if (!addr)
|
|
302
|
+
throw new Error(`No Score contract for chain ${chainId}`);
|
|
303
|
+
this.scoreAddress = addr;
|
|
304
|
+
}
|
|
305
|
+
getPublicClient() {
|
|
306
|
+
const viemChain = CHAINS[this.chainId] ?? baseSepolia;
|
|
307
|
+
return createPublicClient({
|
|
308
|
+
chain: viemChain,
|
|
309
|
+
transport: http(),
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Get an agent's trust score (int256 — can be negative).
|
|
314
|
+
*/
|
|
315
|
+
async getScore(agentAddress) {
|
|
316
|
+
const publicClient = this.getPublicClient();
|
|
317
|
+
const result = await publicClient.readContract({
|
|
318
|
+
address: this.scoreAddress,
|
|
319
|
+
abi: ABBABABA_SCORE_ABI,
|
|
320
|
+
functionName: 'getScore',
|
|
321
|
+
args: [agentAddress],
|
|
322
|
+
});
|
|
323
|
+
return result;
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Get full agent stats from the reputation contract.
|
|
327
|
+
*/
|
|
328
|
+
async getAgentStats(agentAddress) {
|
|
329
|
+
const publicClient = this.getPublicClient();
|
|
330
|
+
const [score, stats] = await Promise.all([
|
|
331
|
+
publicClient.readContract({
|
|
332
|
+
address: this.scoreAddress,
|
|
333
|
+
abi: ABBABABA_SCORE_ABI,
|
|
334
|
+
functionName: 'getScore',
|
|
335
|
+
args: [agentAddress],
|
|
336
|
+
}),
|
|
337
|
+
publicClient.readContract({
|
|
338
|
+
address: this.scoreAddress,
|
|
339
|
+
abi: ABBABABA_SCORE_ABI,
|
|
340
|
+
functionName: 'getStats',
|
|
341
|
+
args: [agentAddress],
|
|
342
|
+
}),
|
|
343
|
+
]);
|
|
344
|
+
const [jobsCompleted, disputesLost, abandonments, lastActiveBlock] = stats;
|
|
345
|
+
return {
|
|
346
|
+
score: score,
|
|
347
|
+
totalJobs: jobsCompleted,
|
|
348
|
+
disputesLost,
|
|
349
|
+
jobsAbandoned: abandonments,
|
|
350
|
+
needsBond: score < 0n,
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Client for interacting with the AbbababaResolverV1 contract.
|
|
356
|
+
* Used for submitting dispute resolutions (requires appropriate role).
|
|
357
|
+
*/
|
|
358
|
+
export class ResolverClient {
|
|
359
|
+
kernelClient;
|
|
360
|
+
chainId;
|
|
361
|
+
resolverAddress;
|
|
362
|
+
constructor(kernelClient, chainId = BASE_SEPOLIA_CHAIN_ID) {
|
|
363
|
+
this.kernelClient = kernelClient;
|
|
364
|
+
this.chainId = chainId;
|
|
365
|
+
const addr = RESOLVER_V1_ADDRESSES[chainId];
|
|
366
|
+
if (!addr)
|
|
367
|
+
throw new Error(`No Resolver contract for chain ${chainId}`);
|
|
368
|
+
this.resolverAddress = addr;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Submit Tier 1 algorithmic resolution.
|
|
372
|
+
* Requires ALGORITHM_ROLE on the resolver contract.
|
|
373
|
+
*/
|
|
374
|
+
async submitAlgorithmicResolution(transactionId, outcome, buyerPercent, sellerPercent, reason) {
|
|
375
|
+
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
376
|
+
const data = encodeFunctionData({
|
|
377
|
+
abi: ABBABABA_RESOLVER_ABI,
|
|
378
|
+
functionName: 'submitAlgorithmicResolution',
|
|
379
|
+
args: [escrowId, outcome, BigInt(buyerPercent), BigInt(sellerPercent), reason],
|
|
380
|
+
});
|
|
381
|
+
const txHash = await this.kernelClient.sendTransaction({
|
|
382
|
+
to: this.resolverAddress,
|
|
383
|
+
data,
|
|
384
|
+
});
|
|
385
|
+
return txHash;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Submit Tier 2 peer arbitration result.
|
|
389
|
+
* Requires PEER_ARBITER_ROLE on the resolver contract.
|
|
390
|
+
*/
|
|
391
|
+
async submitPeerArbitrationResult(transactionId, outcome, buyerPercent, sellerPercent, reviewers) {
|
|
392
|
+
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
393
|
+
const data = encodeFunctionData({
|
|
394
|
+
abi: ABBABABA_RESOLVER_ABI,
|
|
395
|
+
functionName: 'submitPeerArbitrationResult',
|
|
396
|
+
args: [escrowId, outcome, BigInt(buyerPercent), BigInt(sellerPercent), reviewers],
|
|
397
|
+
});
|
|
398
|
+
const txHash = await this.kernelClient.sendTransaction({
|
|
399
|
+
to: this.resolverAddress,
|
|
400
|
+
data,
|
|
401
|
+
});
|
|
402
|
+
return txHash;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Submit Tier 3 human review result.
|
|
406
|
+
* Requires HUMAN_REVIEWER_ROLE on the resolver contract.
|
|
407
|
+
*/
|
|
408
|
+
async submitHumanReview(transactionId, outcome, buyerPercent, sellerPercent, reason) {
|
|
409
|
+
const escrowId = EscrowClient.toEscrowId(transactionId);
|
|
410
|
+
const data = encodeFunctionData({
|
|
411
|
+
abi: ABBABABA_RESOLVER_ABI,
|
|
412
|
+
functionName: 'submitHumanReview',
|
|
413
|
+
args: [escrowId, outcome, BigInt(buyerPercent), BigInt(sellerPercent), reason],
|
|
414
|
+
});
|
|
415
|
+
const txHash = await this.kernelClient.sendTransaction({
|
|
416
|
+
to: this.resolverAddress,
|
|
417
|
+
data,
|
|
418
|
+
});
|
|
419
|
+
return txHash;
|
|
420
|
+
}
|
|
183
421
|
}
|
|
184
422
|
//# sourceMappingURL=escrow.js.map
|