@heyanon-arp/sdk 0.0.2

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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +147 -0
  3. package/dist/assets.d.ts +101 -0
  4. package/dist/attestation/attestation.d.ts +29 -0
  5. package/dist/attestation/index.d.ts +2 -0
  6. package/dist/attestation/scrypt-proof.d.ts +28 -0
  7. package/dist/canonical/canonicalize.d.ts +33 -0
  8. package/dist/canonical/index.d.ts +1 -0
  9. package/dist/challenge/challenge.d.ts +11 -0
  10. package/dist/challenge/index.d.ts +1 -0
  11. package/dist/cosignature/cosign.d.ts +35 -0
  12. package/dist/cosignature/index.d.ts +2 -0
  13. package/dist/did/document.d.ts +30 -0
  14. package/dist/did/format.d.ts +23 -0
  15. package/dist/did/index.d.ts +2 -0
  16. package/dist/envelope/index.d.ts +4 -0
  17. package/dist/envelope/sign.d.ts +28 -0
  18. package/dist/envelope/verify.d.ts +37 -0
  19. package/dist/escrow/caip19.d.ts +41 -0
  20. package/dist/escrow/condition-hash.d.ts +79 -0
  21. package/dist/escrow/create-lock.d.ts +39 -0
  22. package/dist/escrow/index.d.ts +4 -0
  23. package/dist/escrow/lock-id.d.ts +67 -0
  24. package/dist/index.d.ts +38 -0
  25. package/dist/index.js +853 -0
  26. package/dist/index.mjs +761 -0
  27. package/dist/keys/base58btc.d.ts +10 -0
  28. package/dist/keys/ed25519.d.ts +33 -0
  29. package/dist/keys/index.d.ts +3 -0
  30. package/dist/purpose.d.ts +52 -0
  31. package/dist/server-chain/chain.d.ts +52 -0
  32. package/dist/server-chain/index.d.ts +2 -0
  33. package/dist/settlement/index.d.ts +4 -0
  34. package/dist/settlement/settlement.d.ts +111 -0
  35. package/dist/settlement/token-program.d.ts +72 -0
  36. package/dist/types/body.d.ts +263 -0
  37. package/dist/types/envelope.d.ts +121 -0
  38. package/dist/types/identity.d.ts +62 -0
  39. package/dist/types/index.d.ts +5 -0
  40. package/dist/utils/index.d.ts +3 -0
  41. package/dist/utils/nonce.d.ts +9 -0
  42. package/dist/utils/timestamp.d.ts +17 -0
  43. package/dist/utils/uuid.d.ts +10 -0
  44. package/dist/webhook/index.d.ts +2 -0
  45. package/dist/webhook/webhook.d.ts +38 -0
  46. package/package.json +58 -0
@@ -0,0 +1,10 @@
1
+ /**
2
+ * base58btc encoding (Bitcoin alphabet) — used for `did:arp:<...>`.
3
+ *
4
+ * The DID method-specific identifier is `base58btc(identity_public_key)`
5
+ * per [00-core/identity.md](../../../00-core/identity.md). For a 32-byte
6
+ * Ed25519 pubkey the output is 43-44 chars; length varies because
7
+ * leading zero bytes encode as `1` (single char) which compresses.
8
+ */
9
+ export declare function base58btcEncode(bytes: Uint8Array): string;
10
+ export declare function base58btcDecode(text: string): Uint8Array;
@@ -0,0 +1,33 @@
1
+ export interface KeyPair {
2
+ publicKey: Uint8Array;
3
+ secretKey: Uint8Array;
4
+ }
5
+ /**
6
+ * Generate a fresh Ed25519 keypair.
7
+ *
8
+ * Both the identity key and the settlement key are Ed25519 — same
9
+ * primitive, different roles ([00-core/identity.md](../../../00-core/identity.md)).
10
+ * Caller decides which slot the result fills.
11
+ */
12
+ export declare function generateKeyPair(): KeyPair;
13
+ /**
14
+ * Recover the public key from a 32-byte secret seed. Used when only
15
+ * the seed has been persisted (e.g. BIP-39 derived) and the public
16
+ * key needs to be re-derived for verification or DID encoding.
17
+ */
18
+ export declare function getPublicKey(secretKey: Uint8Array): Uint8Array;
19
+ /**
20
+ * Sign `message` with `secretKey`. Returns 64-byte signature.
21
+ *
22
+ * The protocol's domain separation lives at the *payload* level
23
+ * (each `purpose` includes itself in the bytes signed), not at the
24
+ * key level — so a single Ed25519 key can sign multiple purposes
25
+ * without cross-purpose confusion. See [00-core/protocol.md#domain-separation](../../../00-core/protocol.md).
26
+ */
27
+ export declare function sign(message: Uint8Array, secretKey: Uint8Array): Uint8Array;
28
+ /**
29
+ * Verify `signature` against `message` under `publicKey`.
30
+ * Returns boolean; never throws on a malformed signature (returns
31
+ * `false` instead) so consumers can branch cleanly.
32
+ */
33
+ export declare function verify(signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): boolean;
@@ -0,0 +1,3 @@
1
+ export { base58btcEncode, base58btcDecode } from './base58btc';
2
+ export { generateKeyPair, getPublicKey, sign, verify } from './ed25519';
3
+ export type { KeyPair } from './ed25519';
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Domain separators per [00-core/protocol.md#domain-separation](../../00-core/protocol.md).
3
+ *
4
+ * Each Ed25519 signature in the protocol embeds its purpose in the
5
+ * payload bytes — so the same key signing for two different purposes
6
+ * cannot be tricked into validating one as the other (a generic
7
+ * "this byte string was signed" assertion is not enough; the bytes
8
+ * themselves carry the role).
9
+ *
10
+ * Adding a new purpose = add an entry here AND amend
11
+ * [00-core/protocol.md](../../00-core/protocol.md) in the same PR.
12
+ */
13
+ export declare const Purpose: {
14
+ /** Default for `protected.purpose` on body messages. */
15
+ readonly ENVELOPE: "ARP-ENVELOPE-v1";
16
+ /** Receipt co-signature payload (delegation completion). */
17
+ readonly RECEIPT: "ARP-RECEIPT-v1";
18
+ /** Dispute response co-signature payload. */
19
+ readonly DISPUTE_RESPONSE: "ARP-DISPUTE-RESPONSE-v1";
20
+ /** Webhook delivery HMAC signature payload. */
21
+ readonly WEBHOOK: "ARP-WEBHOOK-v1";
22
+ /** Identity ownership challenge proof. */
23
+ readonly CHALLENGE: "ARP-CHALLENGE-v1";
24
+ /** Verifiable Credential issued by the platform. */
25
+ readonly VC: "ARP-VC-v1";
26
+ /** Owner attestation linking identity ↔ settlement keys at registration. */
27
+ readonly KEY_LINK: "ARP-KEY-LINK-v1";
28
+ /** Owner attestation for an identity-key rotation event. */
29
+ readonly KEY_ROTATION: "ARP-KEY-ROTATION-v1";
30
+ /**
31
+ * Settlement-key signature authorising an on-chain `release_lock`.
32
+ * V1.5 — digest now binds fee_bps_at_lock + fee_recipient_at_lock.
33
+ */
34
+ readonly SOLANA_RELEASE: "ARP-SOLANA-RELEASE-v1.5";
35
+ /**
36
+ * Settlement-key signature authorising an on-chain `partial_release`.
37
+ * V1.5 — digest now binds fee_bps_at_lock + fee_recipient_at_lock.
38
+ */
39
+ readonly SOLANA_PARTIAL_RELEASE: "ARP-SOLANA-PARTIAL-RELEASE-v1.5";
40
+ /** Settlement-key signature authorising an on-chain co-signed `refund_lock`. */
41
+ readonly SOLANA_REFUND: "ARP-SOLANA-REFUND-v1";
42
+ /** Admin (platform multisig) signature authorising `resolve_dispute`. */
43
+ readonly SOLANA_RESOLVE_DISPUTE: "ARP-SOLANA-RESOLVE-DISPUTE-v1";
44
+ };
45
+ export type PurposeValue = (typeof Purpose)[keyof typeof Purpose];
46
+ /**
47
+ * `protected.purpose` accepts a subset — the others are payload-level
48
+ * (co-signature / settlement-signature / webhook).
49
+ */
50
+ export declare const PROTECTED_PURPOSES: readonly PurposeValue[];
51
+ export declare const COSIGNATURE_PURPOSES: readonly PurposeValue[];
52
+ export declare const SETTLEMENT_PURPOSES: readonly PurposeValue[];
@@ -0,0 +1,52 @@
1
+ import type { Body, Envelope, Sha256Hex } from '../types';
2
+ /**
3
+ * Server-side hash chain primitives per [00-core/protocol.md](../../../00-core/protocol.md).
4
+ *
5
+ * The chain is server-built — clients NEVER sign chain fields. SDK
6
+ * exposes the helpers because external auditors and the indexer need
7
+ * to recompute hashes to verify the chain end-to-end without trusting
8
+ * the server.
9
+ */
10
+ /**
11
+ * `signed_message_hash = sha256(canonical_json({ protected, body, attachments }))`.
12
+ *
13
+ * Same input as the envelope signature, but here we expose the digest
14
+ * separately because the chain step uses it as one of its inputs.
15
+ */
16
+ export declare function signedMessageHash<TBody extends Body>(envelope: Envelope<TBody>): Sha256Hex;
17
+ /**
18
+ * `server_event_hash = sha256(canonical_json({
19
+ * prev_server_event_hash,
20
+ * relationship_event_index,
21
+ * server_timestamp,
22
+ * signed_message_hash,
23
+ * sender_signature,
24
+ * }))`.
25
+ *
26
+ * `prev_server_event_hash` is null only for the first event in a
27
+ * relationship; pass `null` explicitly so the canonical input
28
+ * preserves the field rather than dropping it.
29
+ */
30
+ export declare function serverEventHash(input: {
31
+ prevServerEventHash: string | null;
32
+ relationshipEventIndex: number;
33
+ serverTimestamp: string;
34
+ signedMessageHash: string;
35
+ senderSignature: string;
36
+ }): Sha256Hex;
37
+ /**
38
+ * Walk a list of events ordered by `relationship_event_index` and
39
+ * confirm each `server_event_hash` matches what we recompute. Returns
40
+ * the index of the first divergent event, or `null` if every link
41
+ * reproduces. Auditors / indexer reconcilers consume this to detect
42
+ * server tampering or split-brain corruption.
43
+ */
44
+ export interface ChainAuditEvent {
45
+ relationship_event_index: number;
46
+ prev_server_event_hash: string | null;
47
+ server_timestamp: string;
48
+ signed_message_hash: string;
49
+ sender_signature: string;
50
+ server_event_hash: string;
51
+ }
52
+ export declare function findFirstChainDivergence(events: readonly ChainAuditEvent[]): number | null;
@@ -0,0 +1,2 @@
1
+ export { signedMessageHash, serverEventHash, findFirstChainDivergence } from './chain';
2
+ export type { ChainAuditEvent } from './chain';
@@ -0,0 +1,4 @@
1
+ export { buildReleaseDigest, buildPartialReleaseDigest, buildRefundDigest, REFUND_REASON_BYTES, PURPOSE_RELEASE_STRING, PURPOSE_PARTIAL_RELEASE_STRING, PURPOSE_REFUND_STRING, } from './settlement';
2
+ export type { ReleaseDigestInput, PartialReleaseDigestInput, RefundDigestInput, RefundReasonByte } from './settlement';
3
+ export { detectTokenProgramFromOwner, detectTokenProgramFromOwnerBytes, SPL_TOKEN_PROGRAM_ID_BASE58, TOKEN_2022_PROGRAM_ID_BASE58, } from './token-program';
4
+ export type { TokenProgramKind, TokenProgramDetection } from './token-program';
@@ -0,0 +1,111 @@
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;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Token-2022 program detection helpers.
3
+ *
4
+ * The escrow contract dispatches transfer / close-account CPIs based on
5
+ * the mint's program kind: legacy SPL Token (`TokenkegQ...`) or Token-2022
6
+ * (`TokenzQdB...`). The kind is detected on-chain from the mint account's
7
+ * `owner` field; this helper mirrors that logic for off-chain consumers
8
+ * (tx builders, indexers, decoders).
9
+ *
10
+ * The function takes a 40-byte (or longer) account info buffer in the
11
+ * standard Solana on-chain account layout — the FIRST 32 bytes are the
12
+ * account's owner pubkey (in the wire-level AccountInfoSerialised shape
13
+ * used by getAccountInfo RPC's "encoding=base64" + custom layout). For
14
+ * the more common `getAccountInfo` response, callers should pass the
15
+ * `owner` field directly via a 32-byte buffer.
16
+ *
17
+ * NOTE: `mintAccountOwnerPubkey` is the OWNER of the mint account on
18
+ * Solana — i.e. the token program that minted it — NOT the mint's
19
+ * mint_authority. Confusingly, both are called "owner" in different
20
+ * contexts.
21
+ */
22
+ /**
23
+ * Legacy SPL Token program ID (base58: `TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA`).
24
+ */
25
+ export declare const SPL_TOKEN_PROGRAM_ID_BASE58 = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
26
+ /**
27
+ * Token-2022 program ID (base58: `TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb`).
28
+ */
29
+ export declare const TOKEN_2022_PROGRAM_ID_BASE58 = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb";
30
+ /**
31
+ * Token program kind. Maps to the new contract's `token_program_kind`
32
+ * u8 emitted on `LockCreated` events
33
+ * (`apps/arp-solana-contract/programs/arp-solana-contract/src/events.rs`):
34
+ * 'native' → 0 (mint == `Pubkey::default()`; the program
35
+ * ignores the token_program slot but Anchor
36
+ * still requires SPL Token or Token-2022 in it)
37
+ * 'legacy' → 1 (legacy SPL Token program)
38
+ * 'token-2022' → 2 (Token-2022 program)
39
+ *
40
+ * `detectTokenProgramFromOwner` below resolves the kind for a NON-
41
+ * native mint by looking at its `.owner` field; native locks are
42
+ * detected from the mint slot value, not from this helper.
43
+ */
44
+ export type TokenProgramKind = 'legacy' | 'token-2022' | 'native';
45
+ /**
46
+ * Result of `detectTokenProgram`: the program kind + a typed branding for
47
+ * downstream consumers.
48
+ */
49
+ export interface TokenProgramDetection {
50
+ kind: TokenProgramKind;
51
+ /** The detected program ID in base58 form (always the canonical address). */
52
+ programIdBase58: string;
53
+ }
54
+ /**
55
+ * Detect a mint's token program kind from its OWNER pubkey (the program
56
+ * that owns the mint account in Solana account terms).
57
+ *
58
+ * Throws if the owner is neither legacy SPL Token nor Token-2022 — escrow
59
+ * does not support any other token program (would dispatch CPI to a
60
+ * non-existent surface).
61
+ *
62
+ * @param mintAccountOwnerBase58 — the mint account's `.owner` field as
63
+ * a base58 string. From `connection.getAccountInfo(mintPubkey)`, this is
64
+ * `accountInfo.owner.toBase58()`.
65
+ */
66
+ export declare function detectTokenProgramFromOwner(mintAccountOwnerBase58: string): TokenProgramDetection;
67
+ /**
68
+ * Same as `detectTokenProgramFromOwner` but accepts a 32-byte raw owner
69
+ * buffer instead of base58 string. Useful for callers that already have
70
+ * the binary owner bytes (e.g. from a parsed AccountInfo).
71
+ */
72
+ export declare function detectTokenProgramFromOwnerBytes(mintAccountOwnerBytes: Uint8Array): TokenProgramDetection;
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Per-`body.type` shapes. Each top-level interface here mirrors a
3
+ * `body/<type>.json` schema in [00-core/schemas.md](../../../00-core/schemas.md).
4
+ *
5
+ * Bodies are kept in a single file so consumers can `import type`
6
+ * without picking individual paths. Nothing here uses runtime AJV
7
+ * validation — those checks belong to the consumer (typically the
8
+ * backend's MessageService); SDK provides only the static types.
9
+ */
10
+ import type { Body, Did, Sha256Hex } from './envelope';
11
+ /**
12
+ * Chain-qualified asset identifier carried by `contract.rate_currency`
13
+ * and `delegation.currency`. Replaces the V1 string-enum `'USDC'`
14
+ * placeholder — that shape can't disambiguate `USDC on Solana mainnet`
15
+ * from `USDC on Polygon` or `USDC.e bridged on Avalanche` (all the same
16
+ * ticker, different on-chain assets). It also can't represent native
17
+ * tokens (SOL, ETH) where `slip44` is the canonical asset namespace.
18
+ *
19
+ * Fields:
20
+ * - `asset_id` — [CAIP-19](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-19.md)
21
+ * fully-qualified identifier:
22
+ * `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/spl:EPjFWdd5...` (USDC Solana mainnet)
23
+ * `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp/slip44:501` (native SOL Solana mainnet)
24
+ * Required, validated against the CAIP-19 regex on the server.
25
+ * - `decimals` — integer 0-18, used to convert human-readable
26
+ * `rate_amount` / `amount` strings to base units for on-chain
27
+ * escrow (USDC = 6, SOL = 9, ETH = 18). Required.
28
+ * - `symbol` — short human-readable hint for UI ("USDC", "SOL").
29
+ * Not used for any logic — purely display sugar. Optional.
30
+ *
31
+ * Validation invariants (server-enforced, both `rate_currency` on the
32
+ * contract and `currency` on the delegation):
33
+ * • `asset_id` ∈ /^[-a-z0-9]{3,8}:[-_a-zA-Z0-9]{1,32}\/[-a-z0-9]{3,8}:[-.%a-zA-Z0-9]{1,128}$/
34
+ * • `decimals` ∈ [0, 18]
35
+ * • `symbol` length ∈ [1, 16] if present
36
+ * • For `delegation.currency`: must match the contract's
37
+ * `rate_currency.asset_id` if the contract specifies one
38
+ * (a delegation under a USDC-priced contract can't quote in SOL).
39
+ */
40
+ export interface AssetIdentifier {
41
+ /** CAIP-19 chain-qualified asset id — e.g. `solana:5eykt.../spl:EPjFWdd5...` */
42
+ asset_id: string;
43
+ /** Decimals for base-unit conversion. Required (USDC = 6, SOL = 9). */
44
+ decimals: number;
45
+ /** Optional UI hint — `USDC`, `SOL`. Never used for protocol logic. */
46
+ symbol?: string;
47
+ }
48
+ /**
49
+ * Closed enum of machine-readable decline reasons used across the
50
+ * three decline sites in V1:
51
+ * • `handshake_response.content.decision === 'decline'`
52
+ * • `contract.content.action === 'decline'`
53
+ * • `delegation.content.action === 'decline'`
54
+ *
55
+ * Required on every decline envelope so the counterparty's reactor
56
+ * (or a human operator) can distinguish "you sent garbage" from
57
+ * "policy rejected" from "the worker is at capacity right now" without
58
+ * parsing free-text. The companion `reason_detail` field carries any
59
+ * additional context the sender wants to surface.
60
+ *
61
+ * Closed list at V1 — adding a value bumps the SDK and the server
62
+ * validator's allowlist. The intent of `unspecified` is for senders
63
+ * that genuinely have no useful detail (still better than no reason
64
+ * at all); `other` means "see `reason_detail` for the specifics".
65
+ */
66
+ export type DeclineReason = 'missing_brief' | 'rate_too_low' | 'out_of_scope' | 'policy' | 'expired_proposal' | 'capacity' | 'unspecified' | 'other';
67
+ /**
68
+ * Runtime allowlist mirror of `DeclineReason` — exported so the
69
+ * server validator + CLI both reference the same source of truth.
70
+ * Order is preserved for the `--help` `choices(...)` list.
71
+ */
72
+ export declare const DECLINE_REASONS: readonly DeclineReason[];
73
+ /**
74
+ * Type guard for a runtime string → `DeclineReason`. Used by the
75
+ * server validator + CLI parsers.
76
+ */
77
+ export declare function isDeclineReason(v: unknown): v is DeclineReason;
78
+ /**
79
+ * `handshake` — first signed exchange between two agents. Establishes
80
+ * relationship; not a contract.
81
+ */
82
+ export interface HandshakeBody extends Body<HandshakeContent> {
83
+ type: 'handshake';
84
+ }
85
+ export interface HandshakeContent {
86
+ greeting?: string;
87
+ intent?: string;
88
+ [extra: string]: unknown;
89
+ }
90
+ /**
91
+ * `handshake_response` — acceptance / decline of an inbound handshake.
92
+ *
93
+ * When `decision === 'decline'`, `reason` is REQUIRED at the validator
94
+ * level (silent declines with no machine-readable reason are
95
+ * debugging-blind). The SDK type marks it optional because TypeScript
96
+ * discriminated unions can't easily encode "required only for this
97
+ * variant" without a stricter shape; the server validator rejects
98
+ * decline envelopes that omit `reason`.
99
+ */
100
+ export interface HandshakeResponseBody extends Body<HandshakeResponseContent> {
101
+ type: 'handshake_response';
102
+ }
103
+ export interface HandshakeResponseContent {
104
+ decision: 'accept' | 'decline';
105
+ notes?: string;
106
+ /** Machine-readable reason — REQUIRED when `decision === 'decline'`. See `DeclineReason`. */
107
+ reason?: DeclineReason;
108
+ /** Optional free-text elaboration (e.g. "current GPU pricing pushed our floor to 0.20 USDC/task"). */
109
+ reason_detail?: string;
110
+ [extra: string]: unknown;
111
+ }
112
+ /**
113
+ * `contract` — co-signed agreement between two agents. `action`
114
+ * discriminates lifecycle events.
115
+ */
116
+ export interface ContractBody extends Body<ContractContent> {
117
+ type: 'contract';
118
+ }
119
+ export interface ContractContent {
120
+ action: 'proposal' | 'counter' | 'sign' | 'decline';
121
+ contract_id: string;
122
+ version: number;
123
+ scope_summary?: string;
124
+ pricing_model?: 'flat' | 'usage_based';
125
+ settlement_model?: 'prepaid' | 'escrow';
126
+ rate_amount?: string;
127
+ rate_currency?: AssetIdentifier;
128
+ rate_unit?: 'task' | 'thread' | 'handoff';
129
+ allowed_delegation_tags?: string[];
130
+ /** Machine-readable reason — REQUIRED when `action === 'decline'`. See `DeclineReason`. */
131
+ reason?: DeclineReason;
132
+ /** Optional free-text elaboration (e.g. "rate floor 0.20 USDC for current model pricing"). */
133
+ reason_detail?: string;
134
+ [extra: string]: unknown;
135
+ }
136
+ /**
137
+ * `delegation` — concrete task offer or lifecycle action under an
138
+ * active contract. `action` discriminates the lifecycle event.
139
+ */
140
+ export interface DelegationBody extends Body<DelegationContent> {
141
+ type: 'delegation';
142
+ }
143
+ export interface DelegationContent {
144
+ action: 'offer' | 'accept' | 'decline' | 'cancel';
145
+ delegation_id: string;
146
+ contract_id: string;
147
+ title?: string;
148
+ brief?: Record<string, unknown>;
149
+ acceptance_criteria?: string[];
150
+ deadline?: string;
151
+ amount?: string;
152
+ currency?: AssetIdentifier;
153
+ /** Machine-readable reason — REQUIRED when `action === 'decline'`. See `DeclineReason`. */
154
+ reason?: DeclineReason;
155
+ /** Optional free-text elaboration (e.g. "delegation offer missing required brief.goal field"). */
156
+ reason_detail?: string;
157
+ [extra: string]: unknown;
158
+ }
159
+ /**
160
+ * `work_request` — caller asks the payee to perform a sub-task within
161
+ * an accepted delegation.
162
+ */
163
+ export interface WorkRequestBody extends Body<WorkRequestContent> {
164
+ type: 'work_request';
165
+ }
166
+ export interface WorkRequestContent {
167
+ delegation_id: string;
168
+ request_id: string;
169
+ params: Record<string, unknown>;
170
+ [extra: string]: unknown;
171
+ }
172
+ /**
173
+ * `work_response` — payee's reply to a work_request.
174
+ */
175
+ export interface WorkResponseBody extends Body<WorkResponseContent> {
176
+ type: 'work_response';
177
+ }
178
+ export interface WorkResponseContent {
179
+ delegation_id: string;
180
+ request_id: string;
181
+ output?: Record<string, unknown>;
182
+ error?: {
183
+ code: string;
184
+ message: string;
185
+ };
186
+ [extra: string]: unknown;
187
+ }
188
+ /**
189
+ * `receipt` — payee-signed message describing completed work. The
190
+ * `attachments.co_signature` (with purpose `ARP-RECEIPT-v1`) carries
191
+ * the matching identity-key cosign on a payload that includes the
192
+ * receipt event hash.
193
+ */
194
+ export interface ReceiptBody extends Body<ReceiptContent> {
195
+ type: 'receipt';
196
+ }
197
+ export interface ReceiptContent {
198
+ delegation_id: string;
199
+ request_hash: Sha256Hex;
200
+ response_hash: Sha256Hex;
201
+ usage?: {
202
+ input_tokens?: number;
203
+ output_tokens?: number;
204
+ latency_ms?: number;
205
+ model?: string;
206
+ computed_amount?: string;
207
+ };
208
+ verdict_proposed: 'accepted' | 'accepted_with_notes' | 'rejected';
209
+ deliverable_hash?: Sha256Hex;
210
+ notes_hash?: Sha256Hex;
211
+ [extra: string]: unknown;
212
+ }
213
+ /**
214
+ * `memory_delta` — append-only update to a relationship's shared memory.
215
+ */
216
+ export interface MemoryDeltaBody extends Body<MemoryDeltaContent> {
217
+ type: 'memory_delta';
218
+ }
219
+ export interface MemoryDeltaContent {
220
+ kind: 'intro' | 'handoff' | 'preference' | 'note' | 'decision' | 'continuity';
221
+ scope: 'thread_only' | 'thread_and_pilot';
222
+ content: string;
223
+ supersedes?: string;
224
+ }
225
+ /**
226
+ * `dispute` — challenge against a delegation outcome. `action`
227
+ * discriminates lifecycle events.
228
+ */
229
+ export interface DisputeBody extends Body<DisputeContent> {
230
+ type: 'dispute';
231
+ }
232
+ export interface DisputeContent {
233
+ action: 'open' | 'respond' | 'escalate' | 'withdraw';
234
+ dispute_id: string;
235
+ delegation_id: string;
236
+ claim?: string;
237
+ remedy_requested?: 'refund' | 'rework' | 'partial_release' | 'release';
238
+ evidence_refs?: string[];
239
+ response_text?: string;
240
+ }
241
+ /**
242
+ * Union over every standard body type. Consumers can narrow on
243
+ * `body.type` via discriminated dispatch.
244
+ */
245
+ export type AnyBody = HandshakeBody | HandshakeResponseBody | ContractBody | DelegationBody | WorkRequestBody | WorkResponseBody | ReceiptBody | MemoryDeltaBody | DisputeBody;
246
+ /** Receipt co-signature payload — what gets `payload_hash`'d in `attachments.co_signature`. */
247
+ export interface ReceiptCosignPayload {
248
+ purpose: 'ARP-RECEIPT-v1';
249
+ delegation_id: string;
250
+ receipt_event_hash: Sha256Hex;
251
+ verdict: 'accepted' | 'accepted_with_notes' | 'rejected';
252
+ notes_hash: Sha256Hex | null;
253
+ }
254
+ /** Dispute response co-signature payload — analogous shape for `ARP-DISPUTE-RESPONSE-v1`. */
255
+ export interface DisputeResponseCosignPayload {
256
+ purpose: 'ARP-DISPUTE-RESPONSE-v1';
257
+ dispute_id: string;
258
+ dispute_event_hash: Sha256Hex;
259
+ stance: 'accept' | 'reject' | 'partial';
260
+ notes_hash: Sha256Hex | null;
261
+ responder_did: Did;
262
+ }
263
+ export type CosignPayload = ReceiptCosignPayload | DisputeResponseCosignPayload;