@heyanon-arp/sdk 0.0.9 → 0.0.11

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.
@@ -41,14 +41,6 @@ export interface AssetIdentifier {
41
41
  /** Optional UI hint — `USDC`, `SOL`. Never used for protocol logic. */
42
42
  symbol?: string;
43
43
  }
44
- /**
45
- * Closed set of delegation pricing models. `flat` = the locked amount
46
- * is the agreed total; `usage_based` = the locked amount is a ceiling
47
- * and the final payout is computed from reported usage at receipt time.
48
- * Referenced both by `DelegationContent.pricing_model` (the offer's
49
- * inline term) and by agent accept-prefs (`AcceptPrefs.pricingModels`).
50
- */
51
- export type PricingModel = 'flat' | 'usage_based';
52
44
  /**
53
45
  * Closed enum of machine-readable decline reasons used across the
54
46
  * two decline sites in V1:
@@ -129,7 +121,6 @@ export interface DelegationContent {
129
121
  amount?: string;
130
122
  currency?: AssetIdentifier;
131
123
  scope_summary?: string;
132
- pricing_model?: PricingModel;
133
124
  /** Machine-readable reason — REQUIRED when `action === 'decline'`. See `DeclineReason`. */
134
125
  reason?: DeclineReason;
135
126
  /** Optional free-text elaboration (e.g. "delegation offer missing required brief.goal field"). */
@@ -206,117 +197,11 @@ export interface DisputeContent {
206
197
  evidence_refs?: string[];
207
198
  response_text?: string;
208
199
  }
209
- /**
210
- * `settlement_signature` — payee's settlement-key signature on a
211
- * release-digest, sent as a STAND-ALONE envelope AFTER the matching
212
- * receipt-propose envelope is committed.
213
- *
214
- * Why a separate envelope (and not an attachment on receipt-propose)?
215
- * The release digest (`buildReleaseDigest` / `buildPartialReleaseDigest`
216
- * in `packages/sdk/src/settlement/settlement.ts`) takes `receiptEventHash`
217
- * as one of its inputs. `receipt_event_hash` is the SERVER-ASSIGNED
218
- * hash of the receipt envelope — it is computed only AFTER server-side
219
- * validation completes (it includes server-assigned `prev_server_event_hash`
220
- * + `server_timestamp` in its canonical input). The payee CANNOT
221
- * compute the digest at receipt-propose time because the digest input
222
- * does not yet exist. So the wire flow is necessarily two envelopes:
223
- *
224
- * 1. Payee sends `receipt` (propose) — server commits + returns
225
- * `IngestResultDto.serverEventHash`.
226
- * 2. Payee reads `serverEventHash`, computes the release digest,
227
- * signs it, and sends THIS `settlement_signature` envelope.
228
- * 3. Buyer reads the `settlement_signature` envelope from inbox SSE
229
- * (sender-recipient routing is standard), then assembles the
230
- * `attachments.settlement_signatures` block on the cosign envelope.
231
- *
232
- * This body type carries ONLY the payee side. The payer's settlement
233
- * sig still lands on the cosign envelope's `attachments` block — that
234
- * stays unchanged. The server's handler for `settlement_signature`
235
- * also performs Ed25519 verification of the payee sig against the
236
- * reconstructed digest as defence-in-depth: a bad sig fails loudly on
237
- * the worker side instead of stranding the buyer's cosign later.
238
- *
239
- * Refund flow is NOT served by this body type — `buildRefundDigest`
240
- * does NOT bind to `receipt_event_hash` (it binds to lock-derived
241
- * fields only), so refund signatures can be computed independent of
242
- * any envelope timing and ride their own dedicated paths. The
243
- * `purpose` field below is intentionally narrowed to RELEASE +
244
- * PARTIAL_RELEASE for the same reason — REFUND-v1 sigs do not belong
245
- * on this envelope.
246
- */
247
- export interface SettlementSignatureBody extends Body<SettlementSignatureContent> {
248
- type: 'settlement_signature';
249
- }
250
- export interface SettlementSignatureContent {
251
- /** The delegation whose receipt is being settlement-signed. */
252
- delegation_id: string;
253
- /**
254
- * Server-assigned hash of the receipt-propose envelope this signature
255
- * settles. Must match `Receipt.receiptEventHash` server-side; that is
256
- * the value the server's cosign-validator feeds into the digest
257
- * reconstruction as `receiptEventHash`.
258
- */
259
- receipt_event_hash: Sha256Hex;
260
- /**
261
- * Which digest the `sig` was computed over. Narrowed to RELEASE +
262
- * PARTIAL_RELEASE: REFUND-v1 sigs ride other paths because the
263
- * refund digest is independent of `receipt_event_hash` and never
264
- * needs this envelope as a transport.
265
- */
266
- purpose: 'ARP-SOLANA-RELEASE-v1.5' | 'ARP-SOLANA-PARTIAL-RELEASE-v1.5';
267
- /**
268
- * Payee's settlement-key public key (base58, 32 bytes raw). The
269
- * server cross-checks this against the registered settlement key on
270
- * the payee's DID document before re-verifying the sig — a sig
271
- * signed by an unregistered key is rejected even if it
272
- * mathematically verifies.
273
- */
274
- payee_settlement_pubkey: string;
275
- /**
276
- * Ed25519 sig over the reconstructed release/partial-release digest,
277
- * **raw base64 — NO `ed25519:` prefix.** Wire format intentionally
278
- * mismatches the SDK's prefixed `Ed25519Sig` type because the buyer
279
- * forwards this exact string verbatim into
280
- * `attachments.settlement_signatures.payee.sig` at cosign time, and
281
- * the server's `ReceiptCosignValidatorService.parseBase64Sig`
282
- * (`apps/arp-server/src/escrow/services/receipt-cosign-validator.service.ts:557-565`)
283
- * `Buffer.from(input, 'base64')` directly — no prefix stripping.
284
- * Aligns with the CLI's `--payer-settlement-sig <base64>` /
285
- * `--payee-settlement-sig <base64>` flags that consumers already
286
- * wire to (see `packages/cli/src/commands/receipt.ts:670-673`).
287
- *
288
- * Server re-builds the same digest from lock + receipt + envelope
289
- * content and verifies this sig as defence-in-depth at handler time
290
- * — a malformed or wrong-digest sig is rejected pre-projection so
291
- * the bad receipt sig never reaches the buyer's cosign attempt.
292
- */
293
- sig: string;
294
- /**
295
- * Unix seconds — the `expires_at` value the payee bound into the
296
- * digest. Server re-uses it when reconstructing the digest and
297
- * cross-checks against `expires_at > now` + `expires_at <=
298
- * lock.expiry - DISPUTE_BUFFER_SECONDS`. The payer
299
- * echoes the SAME value on the cosign envelope's settlement_signatures
300
- * block so both sides sign the same bytes.
301
- */
302
- expires_at: number;
303
- /**
304
- * Base-unit decimal-integer string — required when `purpose ===
305
- * 'ARP-SOLANA-PARTIAL-RELEASE-v1.5'`, omitted (or undefined) for
306
- * full RELEASE. The server cross-checks it against
307
- * `receipt.usage.computed_amount` for usage_based delegations before
308
- * verifying the digest (same invariant
309
- * `ESC_USAGE_COMPUTED_AMOUNT_MISMATCH` already guards on the
310
- * propose-time receipt body).
311
- */
312
- payee_amount?: string;
313
- [extra: string]: unknown;
314
- }
315
200
  /**
316
201
  * Union over every standard body type. Consumers can narrow on
317
202
  * `body.type` via discriminated dispatch.
318
203
  */
319
- export type AnyBody = HandshakeBody | HandshakeResponseBody | DelegationBody | WorkRequestBody | WorkResponseBody | ReceiptBody | DisputeBody | SettlementSignatureBody;
204
+ export type AnyBody = HandshakeBody | HandshakeResponseBody | DelegationBody | WorkRequestBody | WorkResponseBody | ReceiptBody | DisputeBody;
320
205
  /** Receipt co-signature payload — what gets `payload_hash`'d in `attachments.co_signature`. */
321
206
  export interface ReceiptCosignPayload {
322
207
  purpose: 'ARP-RECEIPT-v1';
@@ -43,16 +43,14 @@ export interface Body<TContent = Record<string, unknown>> {
43
43
  content: TContent;
44
44
  }
45
45
  /**
46
- * Optional attachments. Three top-level fields are SDK-aware:
47
- * `co_signature` (semantic intent), `settlement_signatures`
48
- * (financial authorisation), and `escrow_lock` (`delegation.offer`
49
- * carries a pre-signed `create_lock` Solana tx). Other body-specific
50
- * attachments live under their own keys and are passed through
51
- * opaquely.
46
+ * Optional attachments. Two top-level fields are SDK-aware:
47
+ * `co_signature` (semantic intent) and `escrow_lock`
48
+ * (`delegation.offer` carries a pre-signed `create_lock` Solana tx).
49
+ * Other body-specific attachments live under their own keys and are
50
+ * passed through opaquely.
52
51
  */
53
52
  export interface Attachments {
54
53
  co_signature?: CoSignature;
55
- settlement_signatures?: SettlementSignatures;
56
54
  escrow_lock?: EscrowLockAttachment;
57
55
  [other: string]: unknown;
58
56
  }
@@ -69,9 +67,11 @@ export interface Attachments {
69
67
  * equal `toBaseUnits(body.content.amount, currency.decimals)`.
70
68
  * - `asset_id` is the CAIP-19 currency the lock holds; must equal
71
69
  * `body.content.currency.asset_id` (defence-in-depth).
72
- * - `expiry` is the on-chain unix-seconds expiry; must satisfy the
73
- * contract's MIN/MAX windows AND the spec's
74
- * `deadline + DISPUTE_BUFFER` constraint.
70
+ *
71
+ * There is NO expiry field: the V2 contract's `create_lock` carries no
72
+ * expiry argument. `Lock.expiry` is a rolling deadline the chain
73
+ * derives from the Config windows on each state transition
74
+ * (`accept_lock` → work window, `submit_work` → review window, …).
75
75
  *
76
76
  * Server validation in `EnvelopeValidator` decodes the tx blob via
77
77
  * Anchor IDL and cross-checks every field against the envelope body.
@@ -81,7 +81,6 @@ export interface EscrowLockAttachment {
81
81
  lock_id: string;
82
82
  amount: string;
83
83
  asset_id: string;
84
- expiry: number;
85
84
  }
86
85
  export interface CoSignature {
87
86
  agent_did: Did;
@@ -89,31 +88,6 @@ export interface CoSignature {
89
88
  payload_hash: Sha256Hex;
90
89
  sig: Ed25519Sig;
91
90
  }
92
- export interface SettlementSignatures {
93
- purpose: PurposeValue;
94
- payer: SettlementParty;
95
- payee: SettlementParty;
96
- expires_at: number;
97
- }
98
- export interface SettlementParty {
99
- settlement_pubkey: string;
100
- /**
101
- * Ed25519 signature, **raw base64 — NO `ed25519:` prefix.** Wire
102
- * format intentionally mismatches the prefixed `Ed25519Sig` type
103
- * because this block is consumed by the Solana Ed25519Program at
104
- * release-tx-builder time, where prefixed strings would break. The
105
- * server's `ReceiptCosignValidatorService.parseBase64Sig`
106
- * (`apps/arp-server/src/escrow/services/receipt-cosign-validator.service.ts:557-565`)
107
- * decodes 64 bytes directly via `Buffer.from(input, 'base64')`
108
- * without any prefix stripping. The CLI's
109
- * `heyarp wallet sign-settlement-release` already emits raw base64
110
- * (`packages/cli/src/commands/wallet.ts:1718-1722`). Matches the
111
- * raw-base64 shape of `SettlementSignatureContent.sig` — divergent
112
- * types here would leave buyers unable to copy the value verbatim
113
- * into the cosign attachment.
114
- */
115
- sig: string;
116
- }
117
91
  /** Top-level envelope as it appears on the wire. */
118
92
  export interface Envelope<TBody extends Body = Body> {
119
93
  protected: ProtectedBlock;
@@ -1,5 +1,5 @@
1
- export type { Sha256Hex, Ed25519Sig, Did, ProtectedBlock, Body, Attachments, CoSignature, SettlementSignatures, SettlementParty, EscrowLockAttachment, Envelope, PersistedEvent, } from './envelope';
2
- export type { HandshakeBody, HandshakeContent, HandshakeResponseBody, HandshakeResponseContent, DelegationBody, DelegationContent, WorkRequestBody, WorkRequestContent, WorkResponseBody, WorkResponseContent, ReceiptBody, ReceiptContent, DisputeBody, DisputeContent, SettlementSignatureBody, SettlementSignatureContent, AnyBody, ReceiptCosignPayload, DisputeResponseCosignPayload, CosignPayload, DeclineReason, AssetIdentifier, PricingModel, } from './body';
1
+ export type { Sha256Hex, Ed25519Sig, Did, ProtectedBlock, Body, Attachments, CoSignature, EscrowLockAttachment, Envelope, PersistedEvent, } from './envelope';
2
+ export type { HandshakeBody, HandshakeContent, HandshakeResponseBody, HandshakeResponseContent, DelegationBody, DelegationContent, WorkRequestBody, WorkRequestContent, WorkResponseBody, WorkResponseContent, ReceiptBody, ReceiptContent, DisputeBody, DisputeContent, AnyBody, ReceiptCosignPayload, DisputeResponseCosignPayload, CosignPayload, DeclineReason, AssetIdentifier, } from './body';
3
3
  export { DECLINE_REASONS, isDeclineReason } from './body';
4
4
  export type { AcceptPrefs, AcceptCurrency } from './agent';
5
5
  export type { OwnerSigningMethod, KeyLinkPayload, ScryptPasswordAttestation } from './identity';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heyanon-arp/sdk",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "TypeScript SDK for the Agent Relationship Protocol — canonical JSON, Ed25519 envelope sign/verify, did:arp identity, receipt co-signatures, scrypt key attestation, chain-audit helpers.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -1,35 +0,0 @@
1
- import type { CoSignature, CosignPayload, Did } from '../types';
2
- /**
3
- * Build the `attachments.co_signature` block over `payload`.
4
- *
5
- * The signing input is `sha256(canonical_json(payload))` — same
6
- * 32-byte digest the verifier reproduces — and the result is wrapped
7
- * in the protocol's `co_signature` shape. `payload.purpose` is the
8
- * domain separator; passing a payload whose purpose is not in the
9
- * allowed cosignature set throws (defence-in-depth against accidental
10
- * cross-purpose reuse).
11
- */
12
- export declare function signCosignature(input: {
13
- payload: CosignPayload;
14
- signerDid: Did;
15
- identitySecretKey: Uint8Array;
16
- }): CoSignature;
17
- export type CosignVerifyResult = {
18
- ok: true;
19
- } | {
20
- ok: false;
21
- reason: 'payload_hash_mismatch' | 'signature_invalid' | 'signature_malformed' | 'purpose_mismatch';
22
- detail?: string;
23
- };
24
- /**
25
- * Verify that `cosignature` was produced by `signerIdentityPubkey`
26
- * over `payload`. Three checks:
27
- * 1. `cosignature.purpose === payload.purpose` (domain consistency).
28
- * 2. recomputed `sha256(canonical_json(payload))` matches `payload_hash`.
29
- * 3. Ed25519 verifies signature over the recomputed digest.
30
- */
31
- export declare function verifyCosignature(input: {
32
- cosignature: CoSignature;
33
- payload: CosignPayload;
34
- signerIdentityPubkey: Uint8Array;
35
- }): CosignVerifyResult;
@@ -1,2 +0,0 @@
1
- export { signCosignature, verifyCosignature } from './cosign';
2
- export type { CosignVerifyResult } from './cosign';
@@ -1,111 +0,0 @@
1
- /**
2
- * Settlement signature builders / verifiers — `ARP-SOLANA-RELEASE-v1.5`,
3
- * `ARP-SOLANA-PARTIAL-RELEASE-v1.5`, `ARP-SOLANA-REFUND-v1`.
4
- *
5
- * Byte layout MUST match the Solang contract's `domain_sep.sol`
6
- * field-by-field. Any drift here causes Ed25519 verification to fail
7
- * on-chain, so the digest must be a byte-by-byte recompute of what
8
- * the contract reconstructs from on-chain state. Test vectors live
9
- * alongside this module and are exercised by the SDK test suite.
10
- *
11
- * On-chain layout (per `domain_sep.sol::buildReleaseDigest`):
12
- *
13
- * sha256(
14
- * purpose_bytes
15
- * || cluster_tag (1B)
16
- * || program_id (32B)
17
- * || lock_id (32B)
18
- * || payer (32B)
19
- * || payee (32B)
20
- * || mint (32B)
21
- * || amount (u64 LE)
22
- * || [partial only: payee_amount (u64 LE)]
23
- * || condition_hash (32B)
24
- * || delegation_id (16B)
25
- * || receipt_event_hash (32B)
26
- * || deliverable_hash (32B)
27
- * || expires_at (u64 LE)
28
- * || fee_bps_at_lock (u16 LE)
29
- * || fee_recipient_at_lock (32B)
30
- * )
31
- *
32
- * The fee fields are denormalized on the Lock at create_lock time so
33
- * subsequent fee changes by admin cannot retroactively affect an
34
- * in-flight lock. When fee was disabled at lock creation, bps=0 and
35
- * recipient is the all-zero address (System Program / NATIVE_SOL_MINT).
36
- *
37
- * Refund layout (`buildRefundDigest`) — UNCHANGED at v1 because refund
38
- * flows never charge a fee:
39
- *
40
- * sha256(
41
- * purpose_bytes
42
- * || cluster_tag (1B)
43
- * || program_id (32B)
44
- * || lock_id (32B)
45
- * || payer (32B)
46
- * || payee (32B)
47
- * || mint (32B)
48
- * || amount (u64 LE)
49
- * || reason_byte (1B)
50
- * || expires_at (u64 LE)
51
- * )
52
- */
53
- export declare const PURPOSE_RELEASE_STRING: "ARP-SOLANA-RELEASE-v1.5";
54
- export declare const PURPOSE_PARTIAL_RELEASE_STRING: "ARP-SOLANA-PARTIAL-RELEASE-v1.5";
55
- export declare const PURPOSE_REFUND_STRING: "ARP-SOLANA-REFUND-v1";
56
- export interface ReleaseDigestInput {
57
- clusterTag: 0 | 1;
58
- programId: Uint8Array;
59
- lockId: Uint8Array;
60
- payerSettlementPubkey: Uint8Array;
61
- payeeSettlementPubkey: Uint8Array;
62
- mint: Uint8Array;
63
- amount: bigint;
64
- conditionHash: Uint8Array;
65
- delegationId: string;
66
- receiptEventHash: Uint8Array;
67
- deliverableHash: Uint8Array;
68
- expiresAt: bigint;
69
- /**
70
- * Protocol fee bps denormalized on the Lock at create_lock.
71
- * Optional with default 0 (no fee). When the lock was created with
72
- * fee disabled, the on-chain Lock stores 0 — pass 0 here to match.
73
- */
74
- feeBpsAtLock?: number;
75
- /**
76
- * Protocol fee recipient denormalized on the Lock at create_lock.
77
- * Optional with default = 32 zero bytes (System Program address).
78
- * When fee was disabled at lock creation, the on-chain Lock stores
79
- * zero-bytes — pass undefined here to match.
80
- */
81
- feeRecipientAtLock?: Uint8Array;
82
- }
83
- /**
84
- * Build the canonical 32-byte digest for an `ARP-SOLANA-RELEASE-v1.5`
85
- * settlement. The bytes are the EXACT input the contract Ed25519Program
86
- * verifies against.
87
- */
88
- export declare function buildReleaseDigest(input: ReleaseDigestInput): Uint8Array;
89
- export interface PartialReleaseDigestInput extends ReleaseDigestInput {
90
- payeeAmount: bigint;
91
- }
92
- export declare function buildPartialReleaseDigest(input: PartialReleaseDigestInput): Uint8Array;
93
- export type RefundReasonByte = 0 | 1 | 2 | 3;
94
- export declare const REFUND_REASON_BYTES: {
95
- readonly expired: 0;
96
- readonly dispute_resolution: 1;
97
- readonly payer_cancellation: 2;
98
- readonly both_parties_agreed: 3;
99
- };
100
- export interface RefundDigestInput {
101
- clusterTag: 0 | 1;
102
- programId: Uint8Array;
103
- lockId: Uint8Array;
104
- payerSettlementPubkey: Uint8Array;
105
- payeeSettlementPubkey: Uint8Array;
106
- mint: Uint8Array;
107
- amount: bigint;
108
- reasonByte: RefundReasonByte;
109
- expiresAt: bigint;
110
- }
111
- export declare function buildRefundDigest(input: RefundDigestInput): Uint8Array;