@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.
- package/LICENSE +21 -0
- package/README.md +147 -0
- package/dist/assets.d.ts +101 -0
- package/dist/attestation/attestation.d.ts +29 -0
- package/dist/attestation/index.d.ts +2 -0
- package/dist/attestation/scrypt-proof.d.ts +28 -0
- package/dist/canonical/canonicalize.d.ts +33 -0
- package/dist/canonical/index.d.ts +1 -0
- package/dist/challenge/challenge.d.ts +11 -0
- package/dist/challenge/index.d.ts +1 -0
- package/dist/cosignature/cosign.d.ts +35 -0
- package/dist/cosignature/index.d.ts +2 -0
- package/dist/did/document.d.ts +30 -0
- package/dist/did/format.d.ts +23 -0
- package/dist/did/index.d.ts +2 -0
- package/dist/envelope/index.d.ts +4 -0
- package/dist/envelope/sign.d.ts +28 -0
- package/dist/envelope/verify.d.ts +37 -0
- package/dist/escrow/caip19.d.ts +41 -0
- package/dist/escrow/condition-hash.d.ts +79 -0
- package/dist/escrow/create-lock.d.ts +39 -0
- package/dist/escrow/index.d.ts +4 -0
- package/dist/escrow/lock-id.d.ts +67 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +853 -0
- package/dist/index.mjs +761 -0
- package/dist/keys/base58btc.d.ts +10 -0
- package/dist/keys/ed25519.d.ts +33 -0
- package/dist/keys/index.d.ts +3 -0
- package/dist/purpose.d.ts +52 -0
- package/dist/server-chain/chain.d.ts +52 -0
- package/dist/server-chain/index.d.ts +2 -0
- package/dist/settlement/index.d.ts +4 -0
- package/dist/settlement/settlement.d.ts +111 -0
- package/dist/settlement/token-program.d.ts +72 -0
- package/dist/types/body.d.ts +263 -0
- package/dist/types/envelope.d.ts +121 -0
- package/dist/types/identity.d.ts +62 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/nonce.d.ts +9 -0
- package/dist/utils/timestamp.d.ts +17 -0
- package/dist/utils/uuid.d.ts +10 -0
- package/dist/webhook/index.d.ts +2 -0
- package/dist/webhook/webhook.d.ts +38 -0
- 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,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,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;
|