@agentfromzero/agentpassport-sdk 0.1.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/LICENSE +21 -0
- package/README.md +162 -0
- package/dist/abis.d.ts +1708 -0
- package/dist/abis.js +2221 -0
- package/dist/abis.js.map +1 -0
- package/dist/addresses.d.ts +74 -0
- package/dist/addresses.js +25 -0
- package/dist/addresses.js.map +1 -0
- package/dist/client.d.ts +179 -0
- package/dist/client.js +411 -0
- package/dist/client.js.map +1 -0
- package/dist/gasless.d.ts +55 -0
- package/dist/gasless.js +73 -0
- package/dist/gasless.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +123 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +40 -0
- package/dist/utils.js +80 -0
- package/dist/utils.js.map +1 -0
- package/package.json +38 -0
- package/src/abis.ts +2225 -0
- package/src/addresses.ts +46 -0
- package/src/client.ts +496 -0
- package/src/gasless.ts +102 -0
- package/src/index.ts +10 -0
- package/src/types.ts +127 -0
- package/src/utils.ts +87 -0
package/src/types.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { Address, Hex } from "viem";
|
|
2
|
+
|
|
3
|
+
/** On-chain passport (mirrors `IAgentPassport.Passport`). Volumes are in settlement-token units. */
|
|
4
|
+
export interface Passport {
|
|
5
|
+
jobsSettled: bigint;
|
|
6
|
+
jobsRefunded: bigint;
|
|
7
|
+
jobsDisputed: bigint;
|
|
8
|
+
/** Unix seconds of the first attested job (0 = never hired). */
|
|
9
|
+
firstSeen: bigint;
|
|
10
|
+
/** Unix seconds of the last settlement (0 = never settled). */
|
|
11
|
+
lastSettled: bigint;
|
|
12
|
+
volumeSettled: bigint;
|
|
13
|
+
/** Settlement token; zero address until the first attestation. */
|
|
14
|
+
token: Address;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Hiring policy evaluated on-chain by `AgentPassport.meets` (mirrors `IAgentPassport.Policy`). */
|
|
18
|
+
export interface Policy {
|
|
19
|
+
minJobsSettled: bigint;
|
|
20
|
+
minVolumeSettled: bigint;
|
|
21
|
+
maxJobsDisputed: bigint;
|
|
22
|
+
/** Seconds; 0 disables the recency check. */
|
|
23
|
+
maxAgeOfLastSettlement: bigint;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Loose policy input: every field optional, numbers or bigints or decimal strings. */
|
|
27
|
+
export type PolicyInput = Partial<Record<keyof Policy, bigint | number | string>>;
|
|
28
|
+
|
|
29
|
+
/** Escrow job status (mirrors `IJobEscrow.Status`). */
|
|
30
|
+
export const JobStatus = {
|
|
31
|
+
None: 0,
|
|
32
|
+
Open: 1,
|
|
33
|
+
Delivered: 2,
|
|
34
|
+
Released: 3,
|
|
35
|
+
Refunded: 4,
|
|
36
|
+
Disputed: 5,
|
|
37
|
+
} as const;
|
|
38
|
+
export type JobStatus = (typeof JobStatus)[keyof typeof JobStatus];
|
|
39
|
+
|
|
40
|
+
/** 2 -> "Delivered". */
|
|
41
|
+
export const jobStatusName = (s: JobStatus): keyof typeof JobStatus =>
|
|
42
|
+
(Object.keys(JobStatus) as Array<keyof typeof JobStatus>).find((k) => JobStatus[k] === s) ?? "None";
|
|
43
|
+
|
|
44
|
+
/** A job as stored by `JobEscrow.getJob`. */
|
|
45
|
+
export interface Job {
|
|
46
|
+
agentId: bigint;
|
|
47
|
+
hirer: Address;
|
|
48
|
+
verifier: Address;
|
|
49
|
+
token: Address;
|
|
50
|
+
amount: bigint;
|
|
51
|
+
deadline: bigint;
|
|
52
|
+
reviewWindow: bigint;
|
|
53
|
+
deliveredAt: bigint;
|
|
54
|
+
status: JobStatus;
|
|
55
|
+
specHash: Hex;
|
|
56
|
+
deliverableHash: Hex;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** Parameters for opening a job (mirrors `IJobEscrow.OpenParams`). */
|
|
60
|
+
export interface OpenParams {
|
|
61
|
+
agentId: bigint;
|
|
62
|
+
token: Address;
|
|
63
|
+
amount: bigint;
|
|
64
|
+
deadline: bigint;
|
|
65
|
+
reviewWindow: bigint;
|
|
66
|
+
verifier: Address;
|
|
67
|
+
specHash: Hex;
|
|
68
|
+
endpoint: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Friendlier input for opening a job; the SDK fills in the token and sane defaults. */
|
|
72
|
+
export interface HireInput {
|
|
73
|
+
agentId: bigint | number;
|
|
74
|
+
/** Amount in USDC base units (6 decimals). Use `parseUsdc("5")` for 5 USDC. */
|
|
75
|
+
amount: bigint;
|
|
76
|
+
/** keccak256 of the spec bytes (see `hashContent`). */
|
|
77
|
+
specHash: Hex;
|
|
78
|
+
/** Skill / endpoint label, forwarded to the ERC-8004 feedback entry. */
|
|
79
|
+
endpoint?: string;
|
|
80
|
+
/** Unix seconds; default now + 24 h. */
|
|
81
|
+
deadline?: bigint | number;
|
|
82
|
+
/** Seconds after delivery in which the hirer may dispute; default 3600. */
|
|
83
|
+
reviewWindow?: bigint | number;
|
|
84
|
+
/** Optional third party allowed to release. */
|
|
85
|
+
verifier?: Address;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** EIP-3009 authorization that funds `openWithAuthorization` (mirrors `IJobEscrow.Authorization`). */
|
|
89
|
+
export interface OpenAuthorization {
|
|
90
|
+
from: Address;
|
|
91
|
+
validAfter: bigint;
|
|
92
|
+
validBefore: bigint;
|
|
93
|
+
nonce: Hex;
|
|
94
|
+
signature: Hex;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** One line of a policy scorecard. */
|
|
98
|
+
export interface PolicyCheck {
|
|
99
|
+
rule: keyof Policy;
|
|
100
|
+
required: string;
|
|
101
|
+
actual: string;
|
|
102
|
+
ok: boolean;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Human- and machine-readable verdict for "should I trust / hire this agent?". */
|
|
106
|
+
export interface Scorecard {
|
|
107
|
+
agentId: string;
|
|
108
|
+
chainId: number;
|
|
109
|
+
blockNumber: string;
|
|
110
|
+
/** `AgentPassport.meets(agentId, policy)` as returned by the chain. */
|
|
111
|
+
meets: boolean;
|
|
112
|
+
checks: PolicyCheck[];
|
|
113
|
+
passport: {
|
|
114
|
+
jobsSettled: string;
|
|
115
|
+
jobsRefunded: string;
|
|
116
|
+
jobsDisputed: string;
|
|
117
|
+
volumeSettled: string;
|
|
118
|
+
volumeSettledUsdc: string;
|
|
119
|
+
firstSeen: string | null;
|
|
120
|
+
lastSettled: string | null;
|
|
121
|
+
token: Address | null;
|
|
122
|
+
};
|
|
123
|
+
identity: { owner: Address; agentWallet: Address | null; agentURI: string } | null;
|
|
124
|
+
/** Escrow-backed ERC-8004 feedback: entries written by the AgentPassport contract only. */
|
|
125
|
+
reputation: { count: string; summaryValue: string | null; client: Address };
|
|
126
|
+
policy: Record<keyof Policy, string>;
|
|
127
|
+
}
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { encodeAbiParameters, formatUnits, keccak256, parseUnits, toBytes, type Address, type Hex } from "viem";
|
|
2
|
+
import type { Passport, Policy, PolicyCheck, PolicyInput } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export const USDC_DECIMALS = 6;
|
|
5
|
+
export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000" as const;
|
|
6
|
+
|
|
7
|
+
/** "5" -> 5_000_000n. */
|
|
8
|
+
export const parseUsdc = (amount: string | number): bigint => parseUnits(String(amount), USDC_DECIMALS);
|
|
9
|
+
/** 5_000_000n -> "5". */
|
|
10
|
+
export const formatUsdc = (amount: bigint): string => formatUnits(amount, USDC_DECIMALS);
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* keccak256 over the exact bytes of a spec or deliverable. Strings are hashed as UTF-8; pass the
|
|
14
|
+
* raw bytes when hashing a downloaded file so line endings and encodings are not rewritten.
|
|
15
|
+
*/
|
|
16
|
+
export function hashContent(content: string | Uint8Array): Hex {
|
|
17
|
+
return keccak256(typeof content === "string" ? toBytes(content) : content);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The ERC-8004 `feedbackHash` AgentPassport writes for a job: keccak256(abi.encode(escrow, jobId)).
|
|
22
|
+
* Anyone can recompute it to link a feedback entry to the escrow job that paid for it.
|
|
23
|
+
*/
|
|
24
|
+
export function jobRef(escrow: Address, jobId: bigint): Hex {
|
|
25
|
+
return keccak256(encodeAbiParameters([{ type: "address" }, { type: "uint256" }], [escrow, jobId]));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const toBig = (v: bigint | number | string | undefined): bigint => (v === undefined ? 0n : BigInt(v));
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Fills a policy. Unset fields are 0, which matches Solidity defaults: in particular
|
|
32
|
+
* `maxJobsDisputed` defaults to 0, i.e. "no disputes tolerated".
|
|
33
|
+
*/
|
|
34
|
+
export function toPolicy(input: PolicyInput = {}): Policy {
|
|
35
|
+
return {
|
|
36
|
+
minJobsSettled: toBig(input.minJobsSettled),
|
|
37
|
+
minVolumeSettled: toBig(input.minVolumeSettled),
|
|
38
|
+
maxJobsDisputed: toBig(input.maxJobsDisputed),
|
|
39
|
+
maxAgeOfLastSettlement: toBig(input.maxAgeOfLastSettlement),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Ready-made policies. Volumes are in USDC base units. */
|
|
44
|
+
export const POLICIES = {
|
|
45
|
+
/** Has been paid through escrow at least once and never lost a dispute. */
|
|
46
|
+
proven: toPolicy({ minJobsSettled: 1 }),
|
|
47
|
+
/** 5+ settled jobs, 25+ USDC settled, no disputes, paid in the last 30 days. */
|
|
48
|
+
active: toPolicy({ minJobsSettled: 5, minVolumeSettled: 25_000_000, maxAgeOfLastSettlement: 30 * 86400 }),
|
|
49
|
+
} as const;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Explains a policy decision rule by rule. Mirrors `AgentPassport.meets` exactly; the chain's answer
|
|
53
|
+
* stays authoritative (see `scorecard`, which returns both).
|
|
54
|
+
*/
|
|
55
|
+
export function evaluatePolicy(p: Passport, policy: Policy, now: bigint): { ok: boolean; checks: PolicyCheck[] } {
|
|
56
|
+
const checks: PolicyCheck[] = [
|
|
57
|
+
{ rule: "minJobsSettled", required: `>= ${policy.minJobsSettled}`, actual: `${p.jobsSettled}`, ok: p.jobsSettled >= policy.minJobsSettled },
|
|
58
|
+
{
|
|
59
|
+
rule: "minVolumeSettled",
|
|
60
|
+
required: `>= ${policy.minVolumeSettled}`,
|
|
61
|
+
actual: `${p.volumeSettled}`,
|
|
62
|
+
ok: p.volumeSettled >= policy.minVolumeSettled,
|
|
63
|
+
},
|
|
64
|
+
{ rule: "maxJobsDisputed", required: `<= ${policy.maxJobsDisputed}`, actual: `${p.jobsDisputed}`, ok: p.jobsDisputed <= policy.maxJobsDisputed },
|
|
65
|
+
];
|
|
66
|
+
if (policy.maxAgeOfLastSettlement !== 0n) {
|
|
67
|
+
const age = p.lastSettled === 0n ? null : now - p.lastSettled;
|
|
68
|
+
checks.push({
|
|
69
|
+
rule: "maxAgeOfLastSettlement",
|
|
70
|
+
required: `<= ${policy.maxAgeOfLastSettlement}s`,
|
|
71
|
+
actual: age === null ? "never settled" : `${age}s`,
|
|
72
|
+
ok: age !== null && age <= policy.maxAgeOfLastSettlement,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return { ok: checks.every((c) => c.ok), checks };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Parses a decimal/hex/bigint agent id; throws on anything that is not a non-negative integer. */
|
|
79
|
+
export function toAgentId(v: bigint | number | string): bigint {
|
|
80
|
+
if (typeof v === "bigint") {
|
|
81
|
+
if (v < 0n) throw new Error(`invalid agentId: ${v}`);
|
|
82
|
+
return v;
|
|
83
|
+
}
|
|
84
|
+
const s = String(v).trim();
|
|
85
|
+
if (!/^(0x[0-9a-fA-F]+|\d+)$/.test(s)) throw new Error(`invalid agentId: ${s}`);
|
|
86
|
+
return BigInt(s);
|
|
87
|
+
}
|