@telaro/sacp 1.0.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.
Files changed (75) hide show
  1. package/INTEGRATION.md +238 -0
  2. package/README.md +253 -0
  3. package/dist/codec.d.ts +35 -0
  4. package/dist/codec.d.ts.map +1 -0
  5. package/dist/codec.js +63 -0
  6. package/dist/codec.js.map +1 -0
  7. package/dist/constants.d.ts +50 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/constants.js +50 -0
  10. package/dist/constants.js.map +1 -0
  11. package/dist/dispatcher.d.ts +87 -0
  12. package/dist/dispatcher.d.ts.map +1 -0
  13. package/dist/dispatcher.js +175 -0
  14. package/dist/dispatcher.js.map +1 -0
  15. package/dist/events.d.ts +93 -0
  16. package/dist/events.d.ts.map +1 -0
  17. package/dist/events.js +142 -0
  18. package/dist/events.js.map +1 -0
  19. package/dist/index.d.ts +38 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +39 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/job.d.ts +99 -0
  24. package/dist/job.d.ts.map +1 -0
  25. package/dist/job.js +297 -0
  26. package/dist/job.js.map +1 -0
  27. package/dist/lst.d.ts +52 -0
  28. package/dist/lst.d.ts.map +1 -0
  29. package/dist/lst.js +58 -0
  30. package/dist/lst.js.map +1 -0
  31. package/dist/negotiation.d.ts +66 -0
  32. package/dist/negotiation.d.ts.map +1 -0
  33. package/dist/negotiation.js +184 -0
  34. package/dist/negotiation.js.map +1 -0
  35. package/dist/offering.d.ts +65 -0
  36. package/dist/offering.d.ts.map +1 -0
  37. package/dist/offering.js +190 -0
  38. package/dist/offering.js.map +1 -0
  39. package/dist/pdas.d.ts +44 -0
  40. package/dist/pdas.d.ts.map +1 -0
  41. package/dist/pdas.js +95 -0
  42. package/dist/pdas.js.map +1 -0
  43. package/dist/runtime.d.ts +244 -0
  44. package/dist/runtime.d.ts.map +1 -0
  45. package/dist/runtime.js +481 -0
  46. package/dist/runtime.js.map +1 -0
  47. package/dist/signer.d.ts +107 -0
  48. package/dist/signer.d.ts.map +1 -0
  49. package/dist/signer.js +94 -0
  50. package/dist/signer.js.map +1 -0
  51. package/dist/take_rate.d.ts +44 -0
  52. package/dist/take_rate.d.ts.map +1 -0
  53. package/dist/take_rate.js +141 -0
  54. package/dist/take_rate.js.map +1 -0
  55. package/dist/timeout.d.ts +35 -0
  56. package/dist/timeout.d.ts.map +1 -0
  57. package/dist/timeout.js +113 -0
  58. package/dist/timeout.js.map +1 -0
  59. package/dist/types.d.ts +39 -0
  60. package/dist/types.d.ts.map +1 -0
  61. package/dist/types.js +13 -0
  62. package/dist/types.js.map +1 -0
  63. package/dist/validation.d.ts +133 -0
  64. package/dist/validation.d.ts.map +1 -0
  65. package/dist/validation.js +315 -0
  66. package/dist/validation.js.map +1 -0
  67. package/dist/watcher.d.ts +67 -0
  68. package/dist/watcher.d.ts.map +1 -0
  69. package/dist/watcher.js +176 -0
  70. package/dist/watcher.js.map +1 -0
  71. package/dist/wormhole.d.ts +88 -0
  72. package/dist/wormhole.d.ts.map +1 -0
  73. package/dist/wormhole.js +152 -0
  74. package/dist/wormhole.js.map +1 -0
  75. package/package.json +138 -0
@@ -0,0 +1,50 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ /**
3
+ * sACP program IDs.
4
+ *
5
+ * v0.1 deployments live on Solana devnet. Mainnet program IDs will
6
+ * be added at v1.0; the SDK is version-locked, so a v0.1 SDK only
7
+ * talks to a v0.1 deployment.
8
+ *
9
+ * Deployed: 2026-06-04, slot 467078075 (job) / 467078115 (validation).
10
+ */
11
+ export const SACP_PROGRAM_ID = new PublicKey("8WAQhJJUnPqiKoJ35dNMSbRWNJsdRqu1f7uVqMwLHZuF");
12
+ export const SACP_VALIDATION_PROGRAM_ID = new PublicKey("GbWzXwirzzed3WjshJaMat9hiWgVSiPR8tAUj4oJnfMC");
13
+ /** Job state machine seed namespace — keeps PDAs cleanly separated. */
14
+ export const JOB_SEED_PREFIX = "job";
15
+ export const ESCROW_SEED_PREFIX = "escrow";
16
+ export const ESCROW_VAULT_SEED_PREFIX = "vault";
17
+ export const SUBMISSION_SEED_PREFIX = "submission";
18
+ export const VERDICT_SEED_PREFIX = "verdict";
19
+ export const CONFIG_SEED_PREFIX = "config";
20
+ export const OFFERING_SEED_PREFIX = "offering";
21
+ export const NEGOTIATION_SEED_PREFIX = "negotiation";
22
+ /** Validation registry seed namespace. */
23
+ export const VALIDATOR_SEED_PREFIX = "validator";
24
+ export const BOND_SEED_PREFIX = "bond";
25
+ export const BOND_AUTHORITY_SEED_PREFIX = "bond_authority";
26
+ export const BOND_VAULT_SEED_PREFIX = "bond_vault";
27
+ export const CHALLENGE_SEED_PREFIX = "challenge";
28
+ export const TREASURY_AUTHORITY_SEED_PREFIX = "treasury_authority";
29
+ export const TREASURY_VAULT_SEED_PREFIX = "treasury_vault";
30
+ export const RESOLVER_CONFIG_SEED_PREFIX = "resolver_config";
31
+ /**
32
+ * Default windows (seconds) baked into v0.1. These can be overridden
33
+ * per-job at `create_job` time; the constants are the protocol-level
34
+ * defaults that match the spec.
35
+ */
36
+ export const DEFAULT_SUBMIT_WINDOW_SECS = 24 * 60 * 60;
37
+ export const DEFAULT_ACCEPT_WINDOW_SECS = 48 * 60 * 60;
38
+ export const DEFAULT_DISPUTE_WINDOW_SECS = 7 * 24 * 60 * 60;
39
+ export const DEFAULT_CHALLENGE_WINDOW_SECS = 48 * 60 * 60;
40
+ /** Slash distribution constants (basis points). */
41
+ export const SLASH_TO_CHALLENGER_BPS = 7_000;
42
+ export const SLASH_TO_TREASURY_BPS = 3_000;
43
+ /** Protocol take-rate constants. Program-enforced cap; the authority
44
+ * can choose any value in [0, MAX_TAKE_RATE_BPS]. */
45
+ export const FEE_DENOMINATOR_BPS = 10_000;
46
+ export const MAX_TAKE_RATE_BPS = 500;
47
+ /** Maximum fraction of the protocol fee routable to the evaluator
48
+ * (v0.7+). 10_000 bps = 100% of the fee. */
49
+ export const MAX_VALIDATOR_SHARE_BPS = 10_000;
50
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,SAAS,CAC1C,8CAA8C,CAC/C,CAAC;AAEF,MAAM,CAAC,MAAM,0BAA0B,GAAG,IAAI,SAAS,CACrD,8CAA8C,CAC/C,CAAC;AAEF,uEAAuE;AACvE,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC;AACrC,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAC3C,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAChD,MAAM,CAAC,MAAM,sBAAsB,GAAG,YAAY,CAAC;AACnD,MAAM,CAAC,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAC7C,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAC3C,MAAM,CAAC,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAC/C,MAAM,CAAC,MAAM,uBAAuB,GAAG,aAAa,CAAC;AAErD,0CAA0C;AAC1C,MAAM,CAAC,MAAM,qBAAqB,GAAG,WAAW,CAAC;AACjD,MAAM,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC;AACvC,MAAM,CAAC,MAAM,0BAA0B,GAAG,gBAAgB,CAAC;AAC3D,MAAM,CAAC,MAAM,sBAAsB,GAAG,YAAY,CAAC;AACnD,MAAM,CAAC,MAAM,qBAAqB,GAAG,WAAW,CAAC;AACjD,MAAM,CAAC,MAAM,8BAA8B,GAAG,oBAAoB,CAAC;AACnE,MAAM,CAAC,MAAM,0BAA0B,GAAG,gBAAgB,CAAC;AAC3D,MAAM,CAAC,MAAM,2BAA2B,GAAG,iBAAiB,CAAC;AAE7D;;;;GAIG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACvD,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AACvD,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAC5D,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAE1D,mDAAmD;AACnD,MAAM,CAAC,MAAM,uBAAuB,GAAG,KAAK,CAAC;AAC7C,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAE3C;qDACqD;AACrD,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAC1C,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AACrC;4CAC4C;AAC5C,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC"}
@@ -0,0 +1,87 @@
1
+ import { Connection, PublicKey } from "@solana/web3.js";
2
+ /**
3
+ * v0.9 — Webhook event dispatcher.
4
+ *
5
+ * `WebhookDispatcher` subscribes to the sACP program's logs via the
6
+ * standard Solana `logsSubscribe` RPC and re-emits each Anchor `emit!`
7
+ * as an HTTP POST to one or more endpoints. Each request carries an
8
+ * HMAC-SHA256 signature in the `X-Sacp-Signature` header so receivers
9
+ * can verify authenticity without trusting the network path.
10
+ *
11
+ * Header format (Stripe-style):
12
+ * X-Sacp-Signature: t=<unix_ts>,v1=<hex_hmac>
13
+ * v1 = hex(HMAC-SHA256(secret, "<unix_ts>." + raw_body))
14
+ *
15
+ * The dispatcher is a thin worker — it doesn't parse the Anchor event
16
+ * payload, it ships the raw log line + program id. Receivers decode
17
+ * the discriminator themselves with `@coral-xyz/anchor` or matching
18
+ * borsh structs. Keeping it dumb here means new events (v0.9+ adds
19
+ * Offering* events) don't require a dispatcher update.
20
+ */
21
+ export type SacpEventName = "JobCreated" | "JobFunded" | "WorkSubmitted" | "JobDisputed" | "JobSettled" | "VerdictRecorded" | "SettlementPublished" | "FeeAccrued" | "ValidatorFeeAccrued";
22
+ export interface WebhookEndpoint {
23
+ url: string;
24
+ /** HMAC-SHA256 shared secret. Treat as a credential — rotate by
25
+ * deploying a new endpoint with a fresh secret, then deleting the
26
+ * old one once consumers are migrated. */
27
+ hmacSecret: string;
28
+ /** Optional allow-list. When set, only these event names are
29
+ * delivered to this endpoint. Defaults to "all sACP events". */
30
+ events?: SacpEventName[];
31
+ /** Custom headers (e.g. for partner-specific routing). */
32
+ extraHeaders?: Record<string, string>;
33
+ /** Override the default 10 s request timeout. */
34
+ timeoutMs?: number;
35
+ }
36
+ export interface WebhookDispatcherOptions {
37
+ connection: Connection;
38
+ endpoints: WebhookEndpoint[];
39
+ /** Defaults to the sACP job program. Override only when watching a
40
+ * sibling program (sacp_validation, future sacp_offering). */
41
+ programId?: PublicKey;
42
+ /** Defaults to 3 retries with exponential backoff (1s, 2s, 4s). */
43
+ retryStrategy?: {
44
+ maxAttempts: number;
45
+ baseDelayMs: number;
46
+ };
47
+ logger?: {
48
+ info: (m: string) => void;
49
+ error: (m: string, e?: unknown) => void;
50
+ };
51
+ /** Inject a fetch impl for tests / non-Node environments. Defaults
52
+ * to the global `fetch`. */
53
+ fetchImpl?: typeof fetch;
54
+ }
55
+ interface RawEvent {
56
+ programLogs: string[];
57
+ signature: string;
58
+ slot: number;
59
+ timestamp: number;
60
+ }
61
+ /**
62
+ * Sign a payload with the standard X-Sacp-Signature scheme. Exported
63
+ * so receivers can verify symmetrically.
64
+ */
65
+ export declare function signWebhookBody(body: string, secret: string, timestamp?: number): {
66
+ header: string;
67
+ timestamp: number;
68
+ };
69
+ /**
70
+ * Verify an incoming sACP webhook. Returns true iff the signature
71
+ * matches the body within `toleranceSecs` of the current clock.
72
+ * Receivers should reject otherwise (replay protection).
73
+ */
74
+ export declare function verifyWebhookSignature(body: string, header: string, secret: string, toleranceSecs?: number): boolean;
75
+ export declare class WebhookDispatcher {
76
+ private readonly opts;
77
+ private subscriptionId;
78
+ constructor(opts: WebhookDispatcherOptions);
79
+ start(): Promise<void>;
80
+ stop(): Promise<void>;
81
+ /** Manual dispatch — for tests or when feeding logs from a backfill. */
82
+ dispatch(event: RawEvent): Promise<void>;
83
+ private handle;
84
+ private deliver;
85
+ }
86
+ export {};
87
+ //# sourceMappingURL=dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../src/dispatcher.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAWxD;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,aAAa,GACrB,YAAY,GACZ,WAAW,GACX,eAAe,GACf,aAAa,GACb,YAAY,GACZ,iBAAiB,GACjB,qBAAqB,GACrB,YAAY,GACZ,qBAAqB,CAAC;AAE1B,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ;;8CAE0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB;oEACgE;IAChE,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,wBAAwB;IACvC,UAAU,EAAE,UAAU,CAAC;IACvB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B;kEAC8D;IAC9D,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,mEAAmE;IACnE,aAAa,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,KAAK,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;KAAE,CAAC;IAChF;gCAC4B;IAC5B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAED,UAAU,QAAQ;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,MAAsC,GAChD;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAGvC;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,aAAa,GAAE,MAAY,GAC1B,OAAO,CAoBT;AAwCD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAInB;IACF,OAAO,CAAC,cAAc,CAAuB;gBAEjC,IAAI,EAAE,wBAAwB;IAYpC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgBtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,wEAAwE;IAClE,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;YAIhC,MAAM;YAeN,OAAO;CAuDtB"}
@@ -0,0 +1,175 @@
1
+ import { hmac } from "@noble/hashes/hmac";
2
+ import { sha256 } from "@noble/hashes/sha256";
3
+ import { bytesToHex, randomBytes } from "@noble/hashes/utils";
4
+ import { SACP_PROGRAM_ID } from "./constants.js";
5
+ /** Pure-JS HMAC-SHA256 → hex. Works in both Node and the browser
6
+ * (no `node:crypto` dependency). */
7
+ function hmacHex(secret, message) {
8
+ return bytesToHex(hmac(sha256, new TextEncoder().encode(secret), new TextEncoder().encode(message)));
9
+ }
10
+ /**
11
+ * Sign a payload with the standard X-Sacp-Signature scheme. Exported
12
+ * so receivers can verify symmetrically.
13
+ */
14
+ export function signWebhookBody(body, secret, timestamp = Math.floor(Date.now() / 1000)) {
15
+ const sig = hmacHex(secret, `${timestamp}.${body}`);
16
+ return { header: `t=${timestamp},v1=${sig}`, timestamp };
17
+ }
18
+ /**
19
+ * Verify an incoming sACP webhook. Returns true iff the signature
20
+ * matches the body within `toleranceSecs` of the current clock.
21
+ * Receivers should reject otherwise (replay protection).
22
+ */
23
+ export function verifyWebhookSignature(body, header, secret, toleranceSecs = 300) {
24
+ const parts = Object.fromEntries(header.split(",").map((kv) => {
25
+ const [k, v] = kv.split("=");
26
+ return [k?.trim(), v?.trim()];
27
+ }));
28
+ const t = Number(parts["t"]);
29
+ const v1 = parts["v1"];
30
+ if (!t || !v1)
31
+ return false;
32
+ const now = Math.floor(Date.now() / 1000);
33
+ if (Math.abs(now - t) > toleranceSecs)
34
+ return false;
35
+ const expected = hmacHex(secret, `${t}.${body}`);
36
+ // Constant-time compare.
37
+ if (expected.length !== v1.length)
38
+ return false;
39
+ let diff = 0;
40
+ for (let i = 0; i < expected.length; i++) {
41
+ diff |= expected.charCodeAt(i) ^ v1.charCodeAt(i);
42
+ }
43
+ return diff === 0;
44
+ }
45
+ /** Extract the Anchor event name from a single log line, if present.
46
+ * Anchor emits events as `Program data: <base64>` after a `Program
47
+ * log: Instruction: <name>` separator. The event name itself doesn't
48
+ * appear on chain; receivers decode the discriminator. We surface a
49
+ * best-effort name by sniffing the preceding `Instruction:` line. */
50
+ function sniffEventName(logs) {
51
+ // The dispatcher exposes the raw logs; callers do the heavy
52
+ // lifting. We just return the instruction name as a coarse filter
53
+ // so endpoints can opt out cheaply.
54
+ for (let i = logs.length - 1; i >= 0; i--) {
55
+ const m = logs[i]?.match(/Program log: Instruction: (\w+)/);
56
+ if (m) {
57
+ const ix = m[1];
58
+ switch (ix) {
59
+ case "CreateJob":
60
+ return "JobCreated";
61
+ case "FundJob":
62
+ return "JobFunded";
63
+ case "SubmitWork":
64
+ return "WorkSubmitted";
65
+ case "DisputeWork":
66
+ return "JobDisputed";
67
+ case "AcceptWork":
68
+ case "SubmitVerdict":
69
+ case "ReclaimEscrow":
70
+ return "JobSettled";
71
+ case "RecordVerdict":
72
+ return "VerdictRecorded";
73
+ case "PublishSettlementVaa":
74
+ return "SettlementPublished";
75
+ default:
76
+ return "unknown";
77
+ }
78
+ }
79
+ }
80
+ return "unknown";
81
+ }
82
+ export class WebhookDispatcher {
83
+ opts;
84
+ subscriptionId = null;
85
+ constructor(opts) {
86
+ this.opts = {
87
+ programId: opts.programId ?? SACP_PROGRAM_ID,
88
+ retryStrategy: opts.retryStrategy ?? {
89
+ maxAttempts: 3,
90
+ baseDelayMs: 1_000,
91
+ },
92
+ fetchImpl: opts.fetchImpl ?? fetch,
93
+ ...opts,
94
+ };
95
+ }
96
+ async start() {
97
+ if (this.subscriptionId !== null)
98
+ return;
99
+ this.subscriptionId = this.opts.connection.onLogs(this.opts.programId, (logs, ctx) => {
100
+ void this.handle({
101
+ programLogs: logs.logs,
102
+ signature: logs.signature,
103
+ slot: ctx.slot,
104
+ timestamp: Math.floor(Date.now() / 1000),
105
+ });
106
+ }, "confirmed");
107
+ }
108
+ async stop() {
109
+ if (this.subscriptionId !== null) {
110
+ await this.opts.connection.removeOnLogsListener(this.subscriptionId);
111
+ this.subscriptionId = null;
112
+ }
113
+ }
114
+ /** Manual dispatch — for tests or when feeding logs from a backfill. */
115
+ async dispatch(event) {
116
+ return this.handle(event);
117
+ }
118
+ async handle(event) {
119
+ const name = sniffEventName(event.programLogs);
120
+ const body = JSON.stringify({
121
+ eventId: `${event.signature}:${event.slot}`,
122
+ event: name,
123
+ signature: event.signature,
124
+ slot: event.slot,
125
+ timestamp: event.timestamp,
126
+ logs: event.programLogs,
127
+ });
128
+ await Promise.all(this.opts.endpoints.map((ep) => this.deliver(ep, name, body)));
129
+ }
130
+ async deliver(ep, name, body) {
131
+ if (ep.events && !ep.events.includes(name))
132
+ return;
133
+ const { maxAttempts, baseDelayMs } = this.opts.retryStrategy;
134
+ const bodyBytes = new TextEncoder().encode(body);
135
+ const saltBytes = randomBytes(8);
136
+ const idemInput = new Uint8Array(bodyBytes.length + saltBytes.length);
137
+ idemInput.set(bodyBytes, 0);
138
+ idemInput.set(saltBytes, bodyBytes.length);
139
+ const idem = bytesToHex(sha256(idemInput)).slice(0, 24);
140
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
141
+ const { header } = signWebhookBody(body, ep.hmacSecret);
142
+ const controller = new AbortController();
143
+ const timeoutId = setTimeout(() => controller.abort(), ep.timeoutMs ?? 10_000);
144
+ try {
145
+ const res = await this.opts.fetchImpl(ep.url, {
146
+ method: "POST",
147
+ headers: {
148
+ "content-type": "application/json",
149
+ "x-sacp-signature": header,
150
+ "x-sacp-idempotency-key": idem,
151
+ ...(ep.extraHeaders ?? {}),
152
+ },
153
+ body,
154
+ signal: controller.signal,
155
+ });
156
+ clearTimeout(timeoutId);
157
+ if (res.ok)
158
+ return;
159
+ if (res.status >= 400 && res.status < 500) {
160
+ // 4xx: receiver rejected — don't retry.
161
+ this.opts.logger?.error(`webhook ${ep.url} returned ${res.status}; not retrying`);
162
+ return;
163
+ }
164
+ }
165
+ catch (e) {
166
+ clearTimeout(timeoutId);
167
+ this.opts.logger?.error(`webhook attempt ${attempt}/${maxAttempts} failed for ${ep.url}`, e);
168
+ }
169
+ if (attempt < maxAttempts) {
170
+ await new Promise((r) => setTimeout(r, baseDelayMs * Math.pow(2, attempt - 1)));
171
+ }
172
+ }
173
+ }
174
+ }
175
+ //# sourceMappingURL=dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.js","sourceRoot":"","sources":["../src/dispatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,93 @@
1
+ import { PublicKey } from "@solana/web3.js";
2
+ /**
3
+ * Anchor-event decoder for sACP.
4
+ *
5
+ * Anchor 0.30 emits events as `Program data: <base64>` lines in the
6
+ * program log. The base64 decodes to `[8-byte discriminator | borsh
7
+ * payload]`. The discriminator is `sha256("event:<EventName>")[..8]`.
8
+ *
9
+ * This module gives consumers a way to consume program logs (from
10
+ * `connection.onLogs` subscriptions) without depending on a generated
11
+ * IDL. We pre-compute every discriminator at module load.
12
+ *
13
+ * Usage:
14
+ * const events = parseSacpEvents(log.logs);
15
+ * for (const e of events) {
16
+ * if (e.type === "JobSettled") { ... }
17
+ * }
18
+ */
19
+ export type SacpEvent = {
20
+ type: "JobCreated";
21
+ jobId: bigint;
22
+ client: PublicKey;
23
+ provider: PublicKey;
24
+ evaluator: PublicKey;
25
+ amount: bigint;
26
+ } | {
27
+ type: "JobFunded";
28
+ jobId: bigint;
29
+ amount: bigint;
30
+ } | {
31
+ type: "WorkSubmitted";
32
+ jobId: bigint;
33
+ provider: PublicKey;
34
+ } | {
35
+ type: "JobDisputed";
36
+ jobId: bigint;
37
+ reasonHash: Uint8Array;
38
+ } | {
39
+ type: "JobSettled";
40
+ jobId: bigint;
41
+ winner: number;
42
+ } | {
43
+ type: "VerdictRecorded";
44
+ jobId: bigint;
45
+ winner: number;
46
+ evaluator: PublicKey;
47
+ } | {
48
+ type: "ValidatorRegistered";
49
+ authority: PublicKey;
50
+ metadataUri: string;
51
+ bondMint: PublicKey;
52
+ } | {
53
+ type: "BondStaked";
54
+ authority: PublicKey;
55
+ amount: bigint;
56
+ total: bigint;
57
+ } | {
58
+ type: "VerdictAccepted";
59
+ authority: PublicKey;
60
+ jobId: bigint;
61
+ winner: number;
62
+ } | {
63
+ type: "ChallengeFiled";
64
+ jobId: bigint;
65
+ challenger: PublicKey;
66
+ validator: PublicKey;
67
+ } | {
68
+ type: "ValidatorSlashed";
69
+ authority: PublicKey;
70
+ jobId: bigint;
71
+ amount: bigint;
72
+ toChallenger: bigint;
73
+ toTreasury: bigint;
74
+ } | {
75
+ type: "ChallengeDismissed";
76
+ jobId: bigint;
77
+ } | {
78
+ type: "BondWithdrawn";
79
+ authority: PublicKey;
80
+ amount: bigint;
81
+ };
82
+ /**
83
+ * Parse a single Anchor "Program data:" log line. Returns null when the
84
+ * line isn't a known sACP event (caller can ignore).
85
+ */
86
+ export declare function parseSacpEventLine(line: string): SacpEvent | null;
87
+ /**
88
+ * Sweep a whole `logs` array (from `Logs` callback or
89
+ * `getTransaction().meta.logMessages`) and return every decoded sACP
90
+ * event in order.
91
+ */
92
+ export declare function parseSacpEvents(logs: readonly string[]): SacpEvent[];
93
+ //# sourceMappingURL=events.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnH;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,GAC7D;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,GAC9D;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,GAChF;IAAE,IAAI,EAAE,qBAAqB,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,GAC/F;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC3E;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChF;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,SAAS,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,GACtF;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC3H;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAyGpE;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAkBjE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAAE,CAOpE"}
package/dist/events.js ADDED
@@ -0,0 +1,142 @@
1
+ import { sha256 } from "@noble/hashes/sha256";
2
+ import { PublicKey } from "@solana/web3.js";
3
+ function eventDiscriminator(name) {
4
+ const digest = sha256(new TextEncoder().encode(`event:${name}`));
5
+ return Buffer.from(digest.subarray(0, 8));
6
+ }
7
+ const DISCRIMINATORS = [
8
+ "JobCreated",
9
+ "JobFunded",
10
+ "WorkSubmitted",
11
+ "JobDisputed",
12
+ "JobSettled",
13
+ "VerdictRecorded",
14
+ "ValidatorRegistered",
15
+ "BondStaked",
16
+ "VerdictAccepted",
17
+ "ChallengeFiled",
18
+ "ValidatorSlashed",
19
+ "ChallengeDismissed",
20
+ "BondWithdrawn",
21
+ ].map((type) => ({ type: type, bytes: eventDiscriminator(type) }));
22
+ function eq(a, b) {
23
+ return a.length === b.length && a.compare(b) === 0;
24
+ }
25
+ class Reader {
26
+ buf;
27
+ offset = 0;
28
+ constructor(buf) {
29
+ this.buf = buf;
30
+ }
31
+ u64() {
32
+ const v = this.buf.readBigUInt64LE(this.offset);
33
+ this.offset += 8;
34
+ return v;
35
+ }
36
+ u8() {
37
+ const v = this.buf.readUInt8(this.offset);
38
+ this.offset += 1;
39
+ return v;
40
+ }
41
+ pubkey() {
42
+ const slice = this.buf.subarray(this.offset, this.offset + 32);
43
+ this.offset += 32;
44
+ return new PublicKey(slice);
45
+ }
46
+ string() {
47
+ const len = this.buf.readUInt32LE(this.offset);
48
+ this.offset += 4;
49
+ const s = this.buf.subarray(this.offset, this.offset + len).toString("utf8");
50
+ this.offset += len;
51
+ return s;
52
+ }
53
+ bytes32() {
54
+ const slice = this.buf.subarray(this.offset, this.offset + 32);
55
+ this.offset += 32;
56
+ return new Uint8Array(slice);
57
+ }
58
+ }
59
+ function decodePayload(type, payload) {
60
+ const r = new Reader(payload);
61
+ try {
62
+ switch (type) {
63
+ case "JobCreated":
64
+ return { type, jobId: r.u64(), client: r.pubkey(), provider: r.pubkey(), evaluator: r.pubkey(), amount: r.u64() };
65
+ case "JobFunded":
66
+ return { type, jobId: r.u64(), amount: r.u64() };
67
+ case "WorkSubmitted":
68
+ return { type, jobId: r.u64(), provider: r.pubkey() };
69
+ case "JobDisputed":
70
+ return { type, jobId: r.u64(), reasonHash: r.bytes32() };
71
+ case "JobSettled":
72
+ return { type, jobId: r.u64(), winner: r.u8() };
73
+ case "VerdictRecorded":
74
+ return { type, jobId: r.u64(), winner: r.u8(), evaluator: r.pubkey() };
75
+ case "ValidatorRegistered":
76
+ return { type, authority: r.pubkey(), metadataUri: r.string(), bondMint: r.pubkey() };
77
+ case "BondStaked":
78
+ return { type, authority: r.pubkey(), amount: r.u64(), total: r.u64() };
79
+ case "VerdictAccepted":
80
+ return { type, authority: r.pubkey(), jobId: r.u64(), winner: r.u8() };
81
+ case "ChallengeFiled":
82
+ return { type, jobId: r.u64(), challenger: r.pubkey(), validator: r.pubkey() };
83
+ case "ValidatorSlashed":
84
+ return {
85
+ type,
86
+ authority: r.pubkey(),
87
+ jobId: r.u64(),
88
+ amount: r.u64(),
89
+ toChallenger: r.u64(),
90
+ toTreasury: r.u64(),
91
+ };
92
+ case "ChallengeDismissed":
93
+ return { type, jobId: r.u64() };
94
+ case "BondWithdrawn":
95
+ return { type, authority: r.pubkey(), amount: r.u64() };
96
+ }
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ }
102
+ /**
103
+ * Parse a single Anchor "Program data:" log line. Returns null when the
104
+ * line isn't a known sACP event (caller can ignore).
105
+ */
106
+ export function parseSacpEventLine(line) {
107
+ const idx = line.indexOf("Program data: ");
108
+ if (idx === -1)
109
+ return null;
110
+ const b64 = line.slice(idx + "Program data: ".length).trim();
111
+ let buf;
112
+ try {
113
+ buf = Buffer.from(b64, "base64");
114
+ }
115
+ catch {
116
+ return null;
117
+ }
118
+ if (buf.length < 8)
119
+ return null;
120
+ const head = buf.subarray(0, 8);
121
+ for (const d of DISCRIMINATORS) {
122
+ if (eq(head, d.bytes)) {
123
+ return decodePayload(d.type, buf.subarray(8));
124
+ }
125
+ }
126
+ return null;
127
+ }
128
+ /**
129
+ * Sweep a whole `logs` array (from `Logs` callback or
130
+ * `getTransaction().meta.logMessages`) and return every decoded sACP
131
+ * event in order.
132
+ */
133
+ export function parseSacpEvents(logs) {
134
+ const out = [];
135
+ for (const line of logs) {
136
+ const e = parseSacpEventLine(line);
137
+ if (e)
138
+ out.push(e);
139
+ }
140
+ return out;
141
+ }
142
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @telaro/sacp — Solana Agent Commerce Protocol SDK
3
+ *
4
+ * Reference implementation of the sACP v0.1 specification. See
5
+ * `docs/srfc/sacp-v0.1.md` for the full protocol document.
6
+ *
7
+ * The SDK is split into two namespaces matching the two halves of the
8
+ * spec:
9
+ *
10
+ * - `./job` — Part A. Job lifecycle (Open → Funded → Submitted →
11
+ * Settled / Disputed). Used by Clients to create jobs, Providers to
12
+ * submit work, Evaluators to settle disputes.
13
+ * - `./validation` — Part B. Bonded validator registry. Used by
14
+ * validator operators to stake bond and act as Evaluators across
15
+ * many Jobs.
16
+ *
17
+ * The two parts share the constants and PDA helpers exported from this
18
+ * top-level entry point.
19
+ */
20
+ export * as job from "./job.js";
21
+ export * as validation from "./validation.js";
22
+ export * as events from "./events.js";
23
+ export * as wormhole from "./wormhole.js";
24
+ export * as lst from "./lst.js";
25
+ export * as takeRate from "./take_rate.js";
26
+ export * as offering from "./offering.js";
27
+ export * as negotiation from "./negotiation.js";
28
+ export { SacpClient, JobSession, type JobActors, type JobSnapshot, type JobAction, type SacpClientConfig, } from "./runtime.js";
29
+ export { LocalSigner, RemoteSigner, WalletAdapterSigner, type SacpSigner, type RemoteSignTransport, type BrowserWalletAdapter, } from "./signer.js";
30
+ export { ProviderRuntime, EvaluatorRuntime, type ProviderRuntimeOptions, type EvaluatorRuntimeOptions, type WatcherCallbackContext, } from "./watcher.js";
31
+ export { WebhookDispatcher, signWebhookBody, verifyWebhookSignature, type WebhookEndpoint, type WebhookDispatcherOptions, type SacpEventName, } from "./dispatcher.js";
32
+ export { ReclaimWatcher, type ReclaimWatcherOptions, } from "./timeout.js";
33
+ export { NegotiationNamespace, NegotiationSession, type NegotiationSessionAction, } from "./runtime.js";
34
+ export type { FetchedNegotiation, NegotiationState, } from "./negotiation.js";
35
+ export { SACP_PROGRAM_ID, SACP_VALIDATION_PROGRAM_ID, FEE_DENOMINATOR_BPS, MAX_TAKE_RATE_BPS, MAX_VALIDATOR_SHARE_BPS, } from "./constants.js";
36
+ export { findJobPda, findEscrowPda, findEscrowVaultPda, findSubmissionPda, findVerdictPda, findValidatorPda, findBondPda, findChallengePda, findSacpConfigPda, findResolverConfigPda, findOfferingPda, findNegotiationPda, } from "./pdas.js";
37
+ export type { JobState, JobRoles, VerdictWinner } from "./types.js";
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,WAAW,MAAM,kBAAkB,CAAC;AAGhD,OAAO,EACL,UAAU,EACV,UAAU,EACV,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,WAAW,EACX,YAAY,EACZ,mBAAmB,EACnB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,GAC1B,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,GAC5B,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,wBAAwB,EAC7B,KAAK,aAAa,GACnB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,cAAc,EACd,KAAK,qBAAqB,GAC3B,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,wBAAwB,GAC9B,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EACL,eAAe,EACf,0BAA0B,EAC1B,mBAAmB,EACnB,iBAAiB,EACjB,uBAAuB,GACxB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,kBAAkB,GACnB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}