@svsprotocol/solana 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 +158 -0
- package/README.md +365 -0
- package/dist/action-production-proof-evidence.js +553 -0
- package/dist/adapter-catalog.d.ts +29 -0
- package/dist/adapter-catalog.js +146 -0
- package/dist/adapter-core.d.ts +48 -0
- package/dist/adapter-core.js +249 -0
- package/dist/approval-signature.js +197 -0
- package/dist/base58.js +69 -0
- package/dist/bot-auth.js +50 -0
- package/dist/bot-certification-evidence.js +342 -0
- package/dist/bot-first-action-runbook.js +299 -0
- package/dist/bot-integration-contract.js +41 -0
- package/dist/certified-submit-status.js +176 -0
- package/dist/common.d.ts +1135 -0
- package/dist/elizaos.d.ts +43 -0
- package/dist/elizaos.js +227 -0
- package/dist/goat.d.ts +47 -0
- package/dist/goat.js +261 -0
- package/dist/index.d.ts +330 -0
- package/dist/index.js +128 -0
- package/dist/protocol.d.ts +205 -0
- package/dist/protocol.js +900 -0
- package/dist/receipt.js +51 -0
- package/dist/signed-proof-read-protection.js +495 -0
- package/dist/solana-agent-kit.d.ts +35 -0
- package/dist/solana-agent-kit.js +151 -0
- package/dist/svs-client.js +1232 -0
- package/dist/vercel-ai.d.ts +47 -0
- package/dist/vercel-ai.js +266 -0
- package/dist/verified-agent-adoption-kit.js +471 -0
- package/dist/verified-agent-profile.js +329 -0
- package/dist/verified-agent-registry-consumer.js +421 -0
- package/dist/verified-agent-registry.d.ts +36 -0
- package/dist/verified-agent-registry.js +826 -0
- package/dist/verified-agent-trust-score.js +335 -0
- package/dist/webhooks.js +834 -0
- package/package.json +72 -0
|
@@ -0,0 +1,553 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { summarizeApprovalDomain } from "./approval-signature.js";
|
|
4
|
+
import { hashObject } from "./receipt.js";
|
|
5
|
+
|
|
6
|
+
export const ACTION_PRODUCTION_PROOF_EVIDENCE_VERSION = "svs.action-production-proof-evidence.v1";
|
|
7
|
+
export const ACTION_PRODUCTION_PROOF_EVIDENCE_VERIFICATION_VERSION = "svs.action-production-proof-evidence-verification.v1";
|
|
8
|
+
export const DEFAULT_ACTION_PRODUCTION_PROOF_EVIDENCE_PATH = "./data/security/action-production-proof-evidence.json";
|
|
9
|
+
|
|
10
|
+
export function createActionProductionProofEvidence({
|
|
11
|
+
record,
|
|
12
|
+
status,
|
|
13
|
+
productionProofWebhook = null,
|
|
14
|
+
recordPath = null,
|
|
15
|
+
generatedAt = new Date()
|
|
16
|
+
} = {}) {
|
|
17
|
+
const productionStatus = status ?? createActionProductionProofStatus(record);
|
|
18
|
+
const approvalSignature = getActionApprovalSignature(record);
|
|
19
|
+
const approvalDomain = summarizeApprovalDomain(approvalSignature);
|
|
20
|
+
const requestSignature = record?.source?.requestSignature ?? null;
|
|
21
|
+
const webhookDelivery = summarizeProductionProofWebhookDelivery(productionProofWebhook);
|
|
22
|
+
const unsigned = {
|
|
23
|
+
version: ACTION_PRODUCTION_PROOF_EVIDENCE_VERSION,
|
|
24
|
+
generatedAt: generatedAt.toISOString(),
|
|
25
|
+
source: {
|
|
26
|
+
recordPath,
|
|
27
|
+
statusVersion: productionStatus?.version ?? null
|
|
28
|
+
},
|
|
29
|
+
productionProof: {
|
|
30
|
+
ready: productionStatus?.ready === true,
|
|
31
|
+
status: productionStatus?.status ?? null,
|
|
32
|
+
recordId: productionStatus?.recordId ?? record?.id ?? null,
|
|
33
|
+
botId: productionStatus?.botId ?? getActionRecordBotId(record),
|
|
34
|
+
receiptId: productionStatus?.receiptId ??
|
|
35
|
+
record?.independentVerification?.receiptId ??
|
|
36
|
+
record?.receipt?.id ??
|
|
37
|
+
null,
|
|
38
|
+
nextAction: productionStatus?.nextAction ?? null,
|
|
39
|
+
checks: Array.isArray(productionStatus?.checks)
|
|
40
|
+
? productionStatus.checks.map(summarizeProductionProofCheck)
|
|
41
|
+
: []
|
|
42
|
+
},
|
|
43
|
+
request: {
|
|
44
|
+
authenticatedBotId: record?.source?.authenticatedBotId ?? null,
|
|
45
|
+
requestSignatureVerified: requestSignature?.verified === true,
|
|
46
|
+
requestSignatureSlot: requestSignature?.secretSlot ?? null,
|
|
47
|
+
requestSignatureVersion: requestSignature?.signatureVersion ?? requestSignature?.version ?? null,
|
|
48
|
+
requestNonce: record?.source?.requestNonce ?? null,
|
|
49
|
+
requestId: record?.source?.requestId ?? null,
|
|
50
|
+
idempotencyKey: record?.source?.idempotencyKey ?? null,
|
|
51
|
+
requestTimestamp: record?.source?.requestTimestamp ?? null
|
|
52
|
+
},
|
|
53
|
+
humanApproval: {
|
|
54
|
+
approved: record?.review?.outcome === "approved",
|
|
55
|
+
reviewer: record?.review?.reviewer ?? null,
|
|
56
|
+
signer: approvalSignature?.signer ?? null,
|
|
57
|
+
verified: approvalSignature?.verified === true,
|
|
58
|
+
messageHash: approvalSignature?.messageHash ?? null,
|
|
59
|
+
domain: approvalDomain.domain,
|
|
60
|
+
domainStatus: approvalDomain.status,
|
|
61
|
+
currentDomain: approvalDomain.current,
|
|
62
|
+
legacyDomainCompatible: approvalDomain.legacyCompatible
|
|
63
|
+
},
|
|
64
|
+
broadcast: {
|
|
65
|
+
confirmed: actionBroadcastConfirmed(record),
|
|
66
|
+
signature: record?.broadcast?.signature ?? null,
|
|
67
|
+
confirmationStatus: record?.broadcast?.confirmationStatus ?? null,
|
|
68
|
+
slot: record?.broadcast?.slot ?? null,
|
|
69
|
+
rpcUrl: record?.broadcast?.rpcUrl ?? record?.receipt?.network?.rpcUrl ?? null
|
|
70
|
+
},
|
|
71
|
+
receiptRegistry: {
|
|
72
|
+
confirmed: actionReceiptRegistryConfirmed(record),
|
|
73
|
+
signature: record?.receiptRegistry?.signature ?? null,
|
|
74
|
+
confirmationStatus: record?.receiptRegistry?.confirmationStatus ?? null,
|
|
75
|
+
slot: record?.receiptRegistry?.slot ?? null,
|
|
76
|
+
programId: record?.receiptRegistry?.programId ?? null,
|
|
77
|
+
receiptAccount: record?.receiptRegistry?.receiptAccount ??
|
|
78
|
+
record?.independentVerification?.receiptAccount ??
|
|
79
|
+
null,
|
|
80
|
+
planHash: record?.receiptRegistry?.planHash ?? null,
|
|
81
|
+
transactionPlanHash: record?.receiptRegistry?.transactionPlanHash ?? null
|
|
82
|
+
},
|
|
83
|
+
actionRecordVerification: {
|
|
84
|
+
ok: record?.independentVerification?.version === "svs.action-record-verification.v1" &&
|
|
85
|
+
record.independentVerification.ok === true,
|
|
86
|
+
version: record?.independentVerification?.version ?? null,
|
|
87
|
+
checkedAt: record?.independentVerification?.checkedAt ?? null,
|
|
88
|
+
receiptId: record?.independentVerification?.receiptId ?? null,
|
|
89
|
+
receiptAccount: record?.independentVerification?.receiptAccount ?? null,
|
|
90
|
+
registryTransactionSignature: record?.independentVerification?.registryTransactionSignature ?? null,
|
|
91
|
+
failedCheckCount: Number.isInteger(record?.independentVerification?.failedCheckCount)
|
|
92
|
+
? record.independentVerification.failedCheckCount
|
|
93
|
+
: null
|
|
94
|
+
},
|
|
95
|
+
...(webhookDelivery
|
|
96
|
+
? {
|
|
97
|
+
productionProofWebhook: webhookDelivery
|
|
98
|
+
}
|
|
99
|
+
: {}),
|
|
100
|
+
policy: {
|
|
101
|
+
controllerWallet: record?.policySummary?.controllerWallet ??
|
|
102
|
+
record?.intent?.controllerWallet ??
|
|
103
|
+
record?.receipt?.controllerWallet ??
|
|
104
|
+
null,
|
|
105
|
+
policyHash: record?.receipt?.hashes?.policyHash ?? null,
|
|
106
|
+
intentHash: record?.receipt?.hashes?.intentHash ?? null,
|
|
107
|
+
simulationHash: record?.receipt?.hashes?.simulationHash ?? null
|
|
108
|
+
},
|
|
109
|
+
reportSafety: {
|
|
110
|
+
secretsIncluded: false,
|
|
111
|
+
redactedFields: [
|
|
112
|
+
"SVS_BOT_API_KEY",
|
|
113
|
+
"SVS_BOT_REQUEST_SIGNING_SECRET",
|
|
114
|
+
"SVS_BOT_PENDING_REQUEST_SIGNING_SECRET",
|
|
115
|
+
"apiKey",
|
|
116
|
+
"requestSigningSecret",
|
|
117
|
+
"pendingRequestSigningSecret",
|
|
118
|
+
"webhookSecret"
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
...unsigned,
|
|
125
|
+
evidenceHash: hashActionProductionProofEvidence(unsigned)
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function persistActionProductionProofEvidence({
|
|
130
|
+
outputPath = DEFAULT_ACTION_PRODUCTION_PROOF_EVIDENCE_PATH,
|
|
131
|
+
...options
|
|
132
|
+
} = {}) {
|
|
133
|
+
const evidence = createActionProductionProofEvidence(options);
|
|
134
|
+
const text = `${JSON.stringify(evidence, null, 2)}\n`;
|
|
135
|
+
|
|
136
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
137
|
+
await writeFile(outputPath, text);
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
path: outputPath,
|
|
141
|
+
bytes: Buffer.byteLength(text, "utf8"),
|
|
142
|
+
evidence
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function verifyActionProductionProofEvidence(evidence, {
|
|
147
|
+
requireReady = true,
|
|
148
|
+
expectedRecordId = null,
|
|
149
|
+
requireProductionProofWebhookDelivery = false,
|
|
150
|
+
staleAfterMs = null,
|
|
151
|
+
now = new Date()
|
|
152
|
+
} = {}) {
|
|
153
|
+
const freshness = checkEvidenceFreshness({
|
|
154
|
+
generatedAt: evidence?.generatedAt,
|
|
155
|
+
staleAfterMs,
|
|
156
|
+
now
|
|
157
|
+
});
|
|
158
|
+
const recomputedHash = hashActionProductionProofEvidence(evidence);
|
|
159
|
+
const checks = [
|
|
160
|
+
check(
|
|
161
|
+
"Action production proof evidence version is supported",
|
|
162
|
+
evidence?.version === ACTION_PRODUCTION_PROOF_EVIDENCE_VERSION,
|
|
163
|
+
evidence?.version ?? "missing"
|
|
164
|
+
),
|
|
165
|
+
check(
|
|
166
|
+
"Action production proof evidence hash is valid",
|
|
167
|
+
evidence?.evidenceHash === recomputedHash,
|
|
168
|
+
`declared=${evidence?.evidenceHash ?? "missing"} recomputed=${recomputedHash ?? "missing"}`
|
|
169
|
+
),
|
|
170
|
+
check(
|
|
171
|
+
"Action production proof evidence excludes secrets",
|
|
172
|
+
evidence?.reportSafety?.secretsIncluded === false && !containsSecretMaterial(evidence),
|
|
173
|
+
`secretsIncluded=${evidence?.reportSafety?.secretsIncluded ?? "missing"}`
|
|
174
|
+
),
|
|
175
|
+
check(
|
|
176
|
+
"Action production proof is ready",
|
|
177
|
+
!requireReady || evidence?.productionProof?.ready === true,
|
|
178
|
+
`status=${evidence?.productionProof?.status ?? "missing"}`
|
|
179
|
+
),
|
|
180
|
+
check(
|
|
181
|
+
"Action production proof was requested by an authenticated signed bot",
|
|
182
|
+
!requireReady || Boolean(evidence?.request?.authenticatedBotId) &&
|
|
183
|
+
evidence.request.requestSignatureVerified === true,
|
|
184
|
+
`bot=${evidence?.request?.authenticatedBotId ?? "missing"} signed=${evidence?.request?.requestSignatureVerified ?? "missing"}`
|
|
185
|
+
),
|
|
186
|
+
check(
|
|
187
|
+
"Action production proof has verified human approval",
|
|
188
|
+
!requireReady || evidence?.humanApproval?.approved === true &&
|
|
189
|
+
evidence.humanApproval.verified === true,
|
|
190
|
+
`approved=${evidence?.humanApproval?.approved ?? "missing"} verified=${evidence?.humanApproval?.verified ?? "missing"}`
|
|
191
|
+
),
|
|
192
|
+
check(
|
|
193
|
+
"Action production proof approval domain is supported",
|
|
194
|
+
!requireReady || ["current", "legacy_compatible", "missing"].includes(evidence?.humanApproval?.domainStatus ?? "missing"),
|
|
195
|
+
`domain=${evidence?.humanApproval?.domain ?? "missing"} status=${evidence?.humanApproval?.domainStatus ?? "missing"}`
|
|
196
|
+
),
|
|
197
|
+
check(
|
|
198
|
+
"Action production proof broadcast is confirmed",
|
|
199
|
+
!requireReady || evidence?.broadcast?.confirmed === true,
|
|
200
|
+
`signature=${evidence?.broadcast?.signature ?? "missing"} status=${evidence?.broadcast?.confirmationStatus ?? "missing"}`
|
|
201
|
+
),
|
|
202
|
+
check(
|
|
203
|
+
"Action production proof custom registry is confirmed",
|
|
204
|
+
!requireReady || evidence?.receiptRegistry?.confirmed === true,
|
|
205
|
+
`account=${evidence?.receiptRegistry?.receiptAccount ?? "missing"} status=${evidence?.receiptRegistry?.confirmationStatus ?? "missing"}`
|
|
206
|
+
),
|
|
207
|
+
check(
|
|
208
|
+
"Action production proof independent action-record verification passed",
|
|
209
|
+
!requireReady || evidence?.actionRecordVerification?.ok === true,
|
|
210
|
+
`version=${evidence?.actionRecordVerification?.version ?? "missing"} ok=${evidence?.actionRecordVerification?.ok ?? "missing"}`
|
|
211
|
+
)
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
if (expectedRecordId) {
|
|
215
|
+
checks.push(check(
|
|
216
|
+
"Action production proof evidence record matches expected record",
|
|
217
|
+
evidence?.productionProof?.recordId === expectedRecordId,
|
|
218
|
+
`expected=${expectedRecordId} actual=${evidence?.productionProof?.recordId ?? "missing"}`
|
|
219
|
+
));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (staleAfterMs !== null && staleAfterMs !== undefined) {
|
|
223
|
+
checks.push(check(
|
|
224
|
+
"Action production proof evidence is fresh",
|
|
225
|
+
!freshness.stale,
|
|
226
|
+
freshness.ageMs === null
|
|
227
|
+
? `generatedAt=${evidence?.generatedAt ?? "missing"}`
|
|
228
|
+
: `ageMs=${freshness.ageMs} staleAfterMs=${staleAfterMs}`
|
|
229
|
+
));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const embeddedChecks = Array.isArray(evidence?.productionProof?.checks)
|
|
233
|
+
? evidence.productionProof.checks
|
|
234
|
+
: [];
|
|
235
|
+
checks.push(...embeddedChecks.map((item) => check(
|
|
236
|
+
`Embedded production proof check: ${item.id ?? "unknown"}`,
|
|
237
|
+
!requireReady || item.ok === true,
|
|
238
|
+
item.detail ?? "missing"
|
|
239
|
+
)));
|
|
240
|
+
checks.push(...createProductionProofWebhookDeliveryChecks(evidence?.productionProofWebhook, {
|
|
241
|
+
required: requireProductionProofWebhookDelivery,
|
|
242
|
+
expectedRecordId: expectedRecordId ?? evidence?.productionProof?.recordId ?? null,
|
|
243
|
+
expectedBotId: evidence?.productionProof?.botId ?? evidence?.request?.authenticatedBotId ?? null
|
|
244
|
+
}));
|
|
245
|
+
|
|
246
|
+
const failedChecks = checks.filter((item) => !item.ok);
|
|
247
|
+
|
|
248
|
+
return {
|
|
249
|
+
version: ACTION_PRODUCTION_PROOF_EVIDENCE_VERIFICATION_VERSION,
|
|
250
|
+
ok: failedChecks.length === 0,
|
|
251
|
+
status: failedChecks.length === 0 ? "verified" : freshness.stale ? "stale" : "failed",
|
|
252
|
+
checkedAt: now.toISOString(),
|
|
253
|
+
found: Boolean(evidence),
|
|
254
|
+
generatedAt: evidence?.generatedAt ?? null,
|
|
255
|
+
stale: freshness.stale,
|
|
256
|
+
ageMs: freshness.ageMs,
|
|
257
|
+
staleAfterMs,
|
|
258
|
+
evidenceHash: evidence?.evidenceHash ?? null,
|
|
259
|
+
computedEvidenceHash: recomputedHash,
|
|
260
|
+
recordId: evidence?.productionProof?.recordId ?? null,
|
|
261
|
+
botId: evidence?.productionProof?.botId ?? evidence?.request?.authenticatedBotId ?? null,
|
|
262
|
+
ready: evidence?.productionProof?.ready === true,
|
|
263
|
+
failedCheckCount: failedChecks.length,
|
|
264
|
+
failedChecks,
|
|
265
|
+
checks
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function summarizeProductionProofWebhookDelivery(webhook) {
|
|
270
|
+
const event = webhook?.event ?? webhook;
|
|
271
|
+
|
|
272
|
+
if (!event || typeof event !== "object") {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const delivery = event.delivery ?? {};
|
|
277
|
+
const attempts = Array.isArray(event.deliveryAttempts) ? event.deliveryAttempts : [];
|
|
278
|
+
const signature = delivery.signature ?? attempts.at(-1)?.signature ?? null;
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
version: "svs.action-production-proof-webhook-delivery.v1",
|
|
282
|
+
eventVersion: event.version ?? null,
|
|
283
|
+
eventType: event.eventType ?? null,
|
|
284
|
+
eventId: event.eventId ?? null,
|
|
285
|
+
createdAt: event.createdAt ?? null,
|
|
286
|
+
recordId: event.recordId ?? null,
|
|
287
|
+
botId: event.botId ?? null,
|
|
288
|
+
authenticatedBotId: event.authenticatedBotId ?? null,
|
|
289
|
+
payloadHashAlgorithm: event.payloadHashAlgorithm ?? "sha256",
|
|
290
|
+
payloadHash: event.payloadHash ?? null,
|
|
291
|
+
proofHash: event.data?.proofHash ?? null,
|
|
292
|
+
productionProofStatus: event.data?.status ?? null,
|
|
293
|
+
productionProofReady: event.data?.ready ?? null,
|
|
294
|
+
outboxPath: webhook?.path ?? null,
|
|
295
|
+
delivery: {
|
|
296
|
+
ok: delivery.ok === true,
|
|
297
|
+
mode: delivery.mode ?? null,
|
|
298
|
+
attemptedAt: delivery.attemptedAt ?? null,
|
|
299
|
+
deliveredAt: delivery.deliveredAt ?? null,
|
|
300
|
+
statusCode: delivery.statusCode ?? null,
|
|
301
|
+
error: delivery.error ?? null,
|
|
302
|
+
attemptCount: attempts.length,
|
|
303
|
+
signaturePresent: Boolean(signature),
|
|
304
|
+
signatureVersion: typeof signature === "string" && signature.includes("=")
|
|
305
|
+
? signature.split("=")[0]
|
|
306
|
+
: null,
|
|
307
|
+
signatureTimestamp: delivery.signatureTimestamp ?? attempts.at(-1)?.signatureTimestamp ?? null
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
export function createProductionProofWebhookDeliveryChecks(webhook, {
|
|
313
|
+
required = false,
|
|
314
|
+
expectedRecordId = null,
|
|
315
|
+
expectedBotId = null
|
|
316
|
+
} = {}) {
|
|
317
|
+
if (!webhook) {
|
|
318
|
+
return required
|
|
319
|
+
? [check("Action production proof webhook delivery evidence is present", false, "missing")]
|
|
320
|
+
: [];
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
return [
|
|
324
|
+
check(
|
|
325
|
+
"Action production proof webhook delivery version is supported",
|
|
326
|
+
webhook.version === "svs.action-production-proof-webhook-delivery.v1",
|
|
327
|
+
webhook.version ?? "missing"
|
|
328
|
+
),
|
|
329
|
+
check(
|
|
330
|
+
"Action production proof webhook event type is production proof ready",
|
|
331
|
+
webhook.eventType === "action.production_proof_ready",
|
|
332
|
+
webhook.eventType ?? "missing"
|
|
333
|
+
),
|
|
334
|
+
check(
|
|
335
|
+
"Action production proof webhook record matches action",
|
|
336
|
+
!expectedRecordId || webhook.recordId === expectedRecordId,
|
|
337
|
+
`expected=${expectedRecordId ?? "none"} actual=${webhook.recordId ?? "missing"}`
|
|
338
|
+
),
|
|
339
|
+
check(
|
|
340
|
+
"Action production proof webhook bot matches action",
|
|
341
|
+
!expectedBotId || [webhook.authenticatedBotId, webhook.botId].filter(Boolean).includes(expectedBotId),
|
|
342
|
+
`expected=${expectedBotId ?? "none"} bot=${webhook.botId ?? "missing"} authenticated=${webhook.authenticatedBotId ?? "missing"}`
|
|
343
|
+
),
|
|
344
|
+
check(
|
|
345
|
+
"Action production proof webhook payload hash is pinned",
|
|
346
|
+
webhook.payloadHashAlgorithm === "sha256" && /^[0-9a-f]{64}$/.test(String(webhook.payloadHash ?? "")),
|
|
347
|
+
`${webhook.payloadHashAlgorithm ?? "missing"}:${webhook.payloadHash ?? "missing"}`
|
|
348
|
+
),
|
|
349
|
+
check(
|
|
350
|
+
"Action production proof webhook delivery succeeded",
|
|
351
|
+
webhook.delivery?.ok === true,
|
|
352
|
+
`status=${webhook.delivery?.statusCode ?? "missing"} deliveredAt=${webhook.delivery?.deliveredAt ?? "missing"}`
|
|
353
|
+
),
|
|
354
|
+
check(
|
|
355
|
+
"Action production proof webhook used signed delivery",
|
|
356
|
+
webhook.delivery?.signaturePresent === true && webhook.delivery?.signatureVersion === "v1",
|
|
357
|
+
`signaturePresent=${webhook.delivery?.signaturePresent ?? "missing"} version=${webhook.delivery?.signatureVersion ?? "missing"}`
|
|
358
|
+
)
|
|
359
|
+
];
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export function createActionProductionProofStatus(record) {
|
|
363
|
+
const recordId = record?.id ?? null;
|
|
364
|
+
const botId = getActionRecordBotId(record);
|
|
365
|
+
const requestedByAuthenticatedBot = Boolean(record?.source?.authenticatedBotId);
|
|
366
|
+
const approvalSignature = getActionApprovalSignature(record);
|
|
367
|
+
const humanApproved = approvalSignature?.verified === true;
|
|
368
|
+
const broadcastConfirmed = actionBroadcastConfirmed(record);
|
|
369
|
+
const receiptRegistryConfirmed = actionReceiptRegistryConfirmed(record);
|
|
370
|
+
const actionRecordVerified = record?.independentVerification?.version === "svs.action-record-verification.v1" &&
|
|
371
|
+
record.independentVerification.ok === true;
|
|
372
|
+
const checks = [
|
|
373
|
+
productionProofStatusCheck(
|
|
374
|
+
"requested_by_authenticated_bot",
|
|
375
|
+
requestedByAuthenticatedBot,
|
|
376
|
+
requestedByAuthenticatedBot
|
|
377
|
+
? `requested by ${record.source.authenticatedBotId}`
|
|
378
|
+
: "record does not include authenticated bot source evidence"
|
|
379
|
+
),
|
|
380
|
+
productionProofStatusCheck(
|
|
381
|
+
"human_wallet_approval_verified",
|
|
382
|
+
humanApproved,
|
|
383
|
+
humanApproved
|
|
384
|
+
? `approved by ${approvalSignature.signer ?? record?.intent?.controllerWallet ?? "controller wallet"}`
|
|
385
|
+
: "operator must approve with the controller wallet"
|
|
386
|
+
),
|
|
387
|
+
productionProofStatusCheck(
|
|
388
|
+
"broadcast_confirmed",
|
|
389
|
+
broadcastConfirmed,
|
|
390
|
+
broadcastConfirmed
|
|
391
|
+
? `broadcast ${record.broadcast.signature}`
|
|
392
|
+
: "approved transaction must be broadcast and confirmed"
|
|
393
|
+
),
|
|
394
|
+
productionProofStatusCheck(
|
|
395
|
+
"custom_receipt_registry_confirmed",
|
|
396
|
+
receiptRegistryConfirmed,
|
|
397
|
+
receiptRegistryConfirmed
|
|
398
|
+
? `registry ${record.receiptRegistry.signature}`
|
|
399
|
+
: "confirmed action must be registered with the custom receipt registry"
|
|
400
|
+
),
|
|
401
|
+
productionProofStatusCheck(
|
|
402
|
+
"action_record_verified",
|
|
403
|
+
actionRecordVerified,
|
|
404
|
+
actionRecordVerified
|
|
405
|
+
? `receipt account ${record.independentVerification.receiptAccount ?? "verified"}`
|
|
406
|
+
: "operator must run Verify action after registry registration"
|
|
407
|
+
)
|
|
408
|
+
];
|
|
409
|
+
const missingChecks = checks.filter((item) => !item.ok);
|
|
410
|
+
const ready = missingChecks.length === 0;
|
|
411
|
+
|
|
412
|
+
return {
|
|
413
|
+
version: "svs.action-production-proof-status.v1",
|
|
414
|
+
ready,
|
|
415
|
+
status: ready ? "ready" : "not_ready",
|
|
416
|
+
recordId,
|
|
417
|
+
botId,
|
|
418
|
+
queueStatus: record?.status ?? null,
|
|
419
|
+
txType: record?.intent?.txType ?? null,
|
|
420
|
+
receiptId: record?.independentVerification?.receiptId ?? record?.receipt?.id ?? null,
|
|
421
|
+
receiptRegistry: {
|
|
422
|
+
confirmationStatus: record?.receiptRegistry?.confirmationStatus ?? null,
|
|
423
|
+
signature: record?.receiptRegistry?.signature ?? null,
|
|
424
|
+
receiptAccount: record?.receiptRegistry?.receiptAccount ??
|
|
425
|
+
record?.independentVerification?.receiptAccount ??
|
|
426
|
+
null
|
|
427
|
+
},
|
|
428
|
+
actionRecordVerification: {
|
|
429
|
+
ok: actionRecordVerified,
|
|
430
|
+
version: record?.independentVerification?.version ?? null,
|
|
431
|
+
receiptAccount: record?.independentVerification?.receiptAccount ?? null,
|
|
432
|
+
registryTransactionSignature: record?.independentVerification?.registryTransactionSignature ?? null
|
|
433
|
+
},
|
|
434
|
+
checks,
|
|
435
|
+
missing: missingChecks.map((item) => item.id),
|
|
436
|
+
links: {
|
|
437
|
+
action: recordId ? `/api/actions/${encodeURIComponent(recordId)}` : null,
|
|
438
|
+
productionProof: ready && recordId ? `/api/actions/${encodeURIComponent(recordId)}/production-proof?checkReceiptRegistryChain=false` : null,
|
|
439
|
+
productionProofStatus: recordId ? `/api/actions/${encodeURIComponent(recordId)}/production-proof-status` : null
|
|
440
|
+
},
|
|
441
|
+
nextAction: createActionProductionProofNextAction(missingChecks[0])
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
export function hashActionProductionProofEvidence(evidence) {
|
|
446
|
+
if (!evidence || typeof evidence !== "object") {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const { evidenceHash: _evidenceHash, ...unsigned } = evidence;
|
|
451
|
+
|
|
452
|
+
return hashObject(unsigned);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function summarizeProductionProofCheck(check) {
|
|
456
|
+
return {
|
|
457
|
+
id: check?.id ?? null,
|
|
458
|
+
ok: check?.ok === true,
|
|
459
|
+
detail: check?.detail ?? null
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function productionProofStatusCheck(id, ok, detail) {
|
|
464
|
+
return { id, ok: Boolean(ok), detail };
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
function getActionRecordBotId(record) {
|
|
468
|
+
return record?.source?.authenticatedBotId ?? record?.intent?.botId ?? record?.receipt?.botId ?? null;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
function getActionApprovalSignature(record) {
|
|
472
|
+
return record?.review?.signature ?? record?.approvalSignature ?? null;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
function actionBroadcastConfirmed(record) {
|
|
476
|
+
return Boolean(
|
|
477
|
+
record?.broadcast?.signature &&
|
|
478
|
+
!record.broadcast.error &&
|
|
479
|
+
["confirmed", "finalized"].includes(record.broadcast.confirmationStatus)
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function actionReceiptRegistryConfirmed(record) {
|
|
484
|
+
return Boolean(
|
|
485
|
+
record?.receiptRegistry?.signature &&
|
|
486
|
+
!record.receiptRegistry.error &&
|
|
487
|
+
["confirmed", "finalized"].includes(record.receiptRegistry.confirmationStatus)
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function createActionProductionProofNextAction(firstMissingCheck) {
|
|
492
|
+
if (!firstMissingCheck) {
|
|
493
|
+
return {
|
|
494
|
+
code: "fetch_production_proof",
|
|
495
|
+
message: "Action production proof is ready. Fetch /api/actions/{recordId}/production-proof."
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const messages = {
|
|
500
|
+
requested_by_authenticated_bot: "Submit this action through authenticated bot credentials before treating it as a bot production proof.",
|
|
501
|
+
human_wallet_approval_verified: "Wait for the operator to approve this action with the controller wallet.",
|
|
502
|
+
broadcast_confirmed: "Wait for the approved transaction to be broadcast and confirmed on Solana.",
|
|
503
|
+
custom_receipt_registry_confirmed: "Wait for the operator to register the confirmed receipt with the custom receipt registry.",
|
|
504
|
+
action_record_verified: "Wait for the operator to run Verify action so the custom registry PDA proof is persisted."
|
|
505
|
+
};
|
|
506
|
+
|
|
507
|
+
return {
|
|
508
|
+
code: firstMissingCheck.id,
|
|
509
|
+
message: messages[firstMissingCheck.id] ?? firstMissingCheck.detail
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function check(name, ok, detail) {
|
|
514
|
+
return {
|
|
515
|
+
name,
|
|
516
|
+
ok: Boolean(ok),
|
|
517
|
+
detail
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function checkEvidenceFreshness({
|
|
522
|
+
generatedAt,
|
|
523
|
+
staleAfterMs,
|
|
524
|
+
now
|
|
525
|
+
}) {
|
|
526
|
+
const generatedAtMs = Date.parse(generatedAt ?? "");
|
|
527
|
+
|
|
528
|
+
if (!Number.isFinite(generatedAtMs)) {
|
|
529
|
+
return {
|
|
530
|
+
stale: true,
|
|
531
|
+
ageMs: null
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const ageMs = Math.max(0, now.getTime() - generatedAtMs);
|
|
536
|
+
|
|
537
|
+
return {
|
|
538
|
+
stale: staleAfterMs === null || staleAfterMs === undefined ? false : ageMs > staleAfterMs,
|
|
539
|
+
ageMs
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function containsSecretMaterial(value) {
|
|
544
|
+
const text = JSON.stringify(value ?? {});
|
|
545
|
+
|
|
546
|
+
return [
|
|
547
|
+
"SVS_BOT_API_KEY=",
|
|
548
|
+
"SVS_BOT_REQUEST_SIGNING_SECRET=",
|
|
549
|
+
"SVS_BOT_PENDING_REQUEST_SIGNING_SECRET=",
|
|
550
|
+
"svs_",
|
|
551
|
+
"PRIVATE_SHARED_SECRET"
|
|
552
|
+
].some((needle) => text.includes(needle));
|
|
553
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export const SVS_ADAPTER_CATALOG_VERSION: "svs.agent-framework-adapter-catalog.v1";
|
|
2
|
+
|
|
3
|
+
export interface SvsAgentFrameworkAdapterCatalogEntry {
|
|
4
|
+
id: "custom-adapter-core" | "solana-agent-kit" | "elizaos" | "goat" | "vercel-ai-sdk" | string;
|
|
5
|
+
runtime: string;
|
|
6
|
+
category: "adapter-core" | "framework-adapter" | string;
|
|
7
|
+
packageExport: string;
|
|
8
|
+
exportPath: string;
|
|
9
|
+
adapterVersion: string;
|
|
10
|
+
readinessHelper: string;
|
|
11
|
+
submitHelper: string;
|
|
12
|
+
toolName: string | null;
|
|
13
|
+
pluginName: string | null;
|
|
14
|
+
actionName: string | null;
|
|
15
|
+
demoCommand: string;
|
|
16
|
+
docsPath: string;
|
|
17
|
+
hostValidationTarget: string;
|
|
18
|
+
bestFit: string;
|
|
19
|
+
primary: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const SVS_AGENT_FRAMEWORK_ADAPTERS: readonly Readonly<SvsAgentFrameworkAdapterCatalogEntry>[];
|
|
23
|
+
|
|
24
|
+
export function getSvsAgentFrameworkAdapters(options?: {
|
|
25
|
+
includeCustom?: boolean;
|
|
26
|
+
primaryOnly?: boolean;
|
|
27
|
+
}): SvsAgentFrameworkAdapterCatalogEntry[];
|
|
28
|
+
|
|
29
|
+
export function findSvsAgentFrameworkAdapter(identifier: string | null | undefined): SvsAgentFrameworkAdapterCatalogEntry | null;
|