@cascade-fyi/sati-sdk 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +82 -62
- package/dist/index.cjs +176 -35
- package/dist/index.d.cts +95 -27
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +95 -27
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +176 -37
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -19
- package/LICENSE +0 -201
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,30 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.0] - 2026-02-06
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `updateReputationScore` method for updating existing reputation scores
|
|
13
|
+
- `validateReputationScoreContent` helper function
|
|
14
|
+
- `SAS_DATA_LEN_OFFSET` constant for cleaner SAS account parsing
|
|
15
|
+
- Content validation in `createReputationScore` and `updateReputationScore`
|
|
16
|
+
- Bounds check on content length in `deserializeReputationScore`
|
|
17
|
+
- Known Issues documentation section
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- **BREAKING**: Migrated reputation scores to ReputationScoreV3 with VecU8 content layout, fixing variable-length JSON content support
|
|
22
|
+
- Fixed SAS credential authorized signers: `satiPda` is now correctly added as an authorized signer, enabling `createReputationScore` to succeed
|
|
23
|
+
- Fixed `fetchMaybeSchema` truthiness check that caused false negatives
|
|
24
|
+
- Fixed `deriveReputationAttestationPda` to use correct nonce format
|
|
25
|
+
- Deploy script is now fully idempotent for authorized signer management
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- `updateReputationScore` defaults to `ContentType.None` (was `ContentType.JSON`)
|
|
30
|
+
- Replaced magic number 97 with named `SAS_DATA_LEN_OFFSET` constant
|
|
31
|
+
|
|
8
32
|
## [0.3.0] - 2025-01-27
|
|
9
33
|
|
|
10
34
|
### Added
|
|
@@ -43,5 +67,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
43
67
|
- Compressed attestation storage via Light Protocol
|
|
44
68
|
- Basic querying via Photon RPC
|
|
45
69
|
|
|
70
|
+
[0.4.0]: https://github.com/cascade-protocol/sati/compare/v0.3.0...v0.4.0
|
|
46
71
|
[0.3.0]: https://github.com/cascade-protocol/sati/compare/v0.2.0...v0.3.0
|
|
47
72
|
[0.2.0]: https://github.com/cascade-protocol/sati/releases/tag/v0.2.0
|
package/README.md
CHANGED
|
@@ -16,10 +16,10 @@ pnpm add @solana/kit @solana-program/token-2022 @coral-xyz/anchor
|
|
|
16
16
|
## Quick Start
|
|
17
17
|
|
|
18
18
|
```typescript
|
|
19
|
-
import {
|
|
19
|
+
import { Sati, Outcome } from "@cascade-fyi/sati-sdk";
|
|
20
20
|
|
|
21
21
|
// Initialize client
|
|
22
|
-
const sati = new
|
|
22
|
+
const sati = new Sati({
|
|
23
23
|
network: "devnet",
|
|
24
24
|
photonRpcUrl: "https://devnet.helius-rpc.com?api-key=YOUR_KEY", // For compressed attestations
|
|
25
25
|
});
|
|
@@ -67,22 +67,15 @@ import {
|
|
|
67
67
|
} from "@cascade-fyi/sati-sdk";
|
|
68
68
|
|
|
69
69
|
// 1. Agent signs BEFORE knowing outcome (blind commitment)
|
|
70
|
-
const interactionHash = computeInteractionHash(
|
|
70
|
+
const interactionHash = computeInteractionHash(
|
|
71
71
|
sasSchema,
|
|
72
72
|
taskRef, // 32-byte task identifier
|
|
73
|
-
tokenAccount, // Agent's token address
|
|
74
73
|
dataHash, // Hash of request data
|
|
75
|
-
|
|
74
|
+
);
|
|
76
75
|
const agentSig = await signMessage(agentKeypair, interactionHash);
|
|
77
76
|
|
|
78
|
-
// 2. After task completion, counterparty signs
|
|
79
|
-
|
|
80
|
-
sasSchema,
|
|
81
|
-
taskRef,
|
|
82
|
-
tokenAccount,
|
|
83
|
-
outcome: Outcome.Positive,
|
|
84
|
-
});
|
|
85
|
-
const counterpartySig = await signMessage(clientKeypair, feedbackHash);
|
|
77
|
+
// 2. After task completion, counterparty signs human-readable SIWS message
|
|
78
|
+
// (built automatically by the SDK)
|
|
86
79
|
```
|
|
87
80
|
|
|
88
81
|
### Create Feedback Attestation
|
|
@@ -92,12 +85,10 @@ const result = await sati.createFeedback({
|
|
|
92
85
|
payer,
|
|
93
86
|
sasSchema,
|
|
94
87
|
taskRef: new Uint8Array(32), // CAIP-220 tx hash or arbitrary ID
|
|
95
|
-
|
|
88
|
+
agentMint, // Agent's NFT mint address
|
|
96
89
|
counterparty: clientAddress,
|
|
97
90
|
dataHash: requestHash,
|
|
98
91
|
outcome: Outcome.Positive, // Negative, Neutral, Positive
|
|
99
|
-
tag1: "quality", // Optional, max 32 chars
|
|
100
|
-
tag2: "speed", // Optional, max 32 chars
|
|
101
92
|
content: JSON.stringify({ ... }), // Optional extended data
|
|
102
93
|
agentSignature: {
|
|
103
94
|
pubkey: agentAddress,
|
|
@@ -121,29 +112,21 @@ Validation attestations are for third-party validators assessing agent work:
|
|
|
121
112
|
import { computeValidationHash, ValidationType } from "@cascade-fyi/sati-sdk";
|
|
122
113
|
|
|
123
114
|
// 1. Agent signs blind (same as Feedback)
|
|
124
|
-
const interactionHash = computeInteractionHash(
|
|
125
|
-
|
|
115
|
+
const interactionHash = computeInteractionHash(
|
|
116
|
+
validationSchema,
|
|
126
117
|
taskRef,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
});
|
|
118
|
+
workHash, // Hash of work being validated
|
|
119
|
+
);
|
|
130
120
|
const agentSig = await signMessage(agentKeypair, interactionHash);
|
|
131
121
|
|
|
132
|
-
// 2. Validator signs
|
|
133
|
-
const validationHash = computeValidationHash({
|
|
134
|
-
sasSchema: validationSchema,
|
|
135
|
-
taskRef,
|
|
136
|
-
tokenAccount: agentMint,
|
|
137
|
-
response: 95, // 0-100 score
|
|
138
|
-
});
|
|
139
|
-
const validatorSig = await signMessage(validatorKeypair, validationHash);
|
|
122
|
+
// 2. Validator signs human-readable SIWS message (built by SDK)
|
|
140
123
|
|
|
141
124
|
// 3. Create attestation
|
|
142
125
|
const result = await sati.createValidation({
|
|
143
126
|
payer,
|
|
144
127
|
sasSchema: validationSchema,
|
|
145
128
|
taskRef,
|
|
146
|
-
|
|
129
|
+
agentMint,
|
|
147
130
|
counterparty: validatorAddress,
|
|
148
131
|
dataHash: workHash,
|
|
149
132
|
validationType: ValidationType.Automated, // Manual, Automated, Hybrid
|
|
@@ -163,31 +146,66 @@ const result = await sati.createValidation({
|
|
|
163
146
|
});
|
|
164
147
|
```
|
|
165
148
|
|
|
166
|
-
### Create
|
|
149
|
+
### Create ReputationScoreV3 (Regular Attestation)
|
|
150
|
+
|
|
151
|
+
ReputationScoreV3 uses VecU8 for variable-length content and CounterpartySigned mode (provider only).
|
|
167
152
|
|
|
168
153
|
```typescript
|
|
169
|
-
import {
|
|
154
|
+
import {
|
|
155
|
+
computeInteractionHash,
|
|
156
|
+
computeReputationNonce,
|
|
157
|
+
zeroDataHash,
|
|
158
|
+
createJsonContent,
|
|
159
|
+
ContentType,
|
|
160
|
+
} from "@cascade-fyi/sati-sdk";
|
|
170
161
|
|
|
171
|
-
//
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
162
|
+
// Compute deterministic nonce and taskRef
|
|
163
|
+
const nonce = computeReputationNonce(providerAddress, agentMint);
|
|
164
|
+
const taskRef = nonce; // same as nonce per spec
|
|
165
|
+
const dataHash = zeroDataHash();
|
|
166
|
+
|
|
167
|
+
// Provider signs the interaction hash
|
|
168
|
+
const interactionHash = computeInteractionHash(sasSchema, taskRef, dataHash);
|
|
169
|
+
const providerSig = await signMessage(providerKeypair, interactionHash);
|
|
170
|
+
|
|
171
|
+
const result = await sati.createReputationScore({
|
|
172
|
+
payer,
|
|
175
173
|
provider: providerAddress,
|
|
176
|
-
|
|
174
|
+
providerSignature: providerSig,
|
|
175
|
+
sasSchema,
|
|
176
|
+
satiCredential,
|
|
177
|
+
agentMint,
|
|
178
|
+
taskRef,
|
|
179
|
+
dataHash,
|
|
180
|
+
outcome: Outcome.Positive,
|
|
181
|
+
contentType: ContentType.JSON,
|
|
182
|
+
content: createJsonContent({
|
|
183
|
+
score: 85,
|
|
184
|
+
methodology: "weighted_feedback",
|
|
185
|
+
feedbackCount: 127,
|
|
186
|
+
validationCount: 5,
|
|
187
|
+
}),
|
|
177
188
|
});
|
|
178
|
-
|
|
189
|
+
```
|
|
179
190
|
|
|
180
|
-
|
|
191
|
+
### Update ReputationScoreV3
|
|
192
|
+
|
|
193
|
+
High-level convenience method that closes the existing score and creates a new one:
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
const result = await sati.updateReputationScore({
|
|
181
197
|
payer,
|
|
198
|
+
provider: providerKeypair, // Must be KeyPairSigner (signs close + create)
|
|
182
199
|
sasSchema,
|
|
183
200
|
satiCredential,
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
201
|
+
agentMint,
|
|
202
|
+
outcome: Outcome.Positive,
|
|
203
|
+
contentType: ContentType.JSON,
|
|
204
|
+
content: createJsonContent({
|
|
205
|
+
score: 90,
|
|
189
206
|
methodology: "weighted_feedback",
|
|
190
|
-
|
|
207
|
+
feedbackCount: 150,
|
|
208
|
+
validationCount: 8,
|
|
191
209
|
}),
|
|
192
210
|
});
|
|
193
211
|
```
|
|
@@ -206,7 +224,7 @@ const attestations = await rpc.getCompressedAccountsByOwner({
|
|
|
206
224
|
owner: SATI_PROGRAM_ADDRESS,
|
|
207
225
|
filters: [
|
|
208
226
|
{ memcmp: { offset: 8, bytes: feedbackSchema } },
|
|
209
|
-
{ memcmp: { offset: 40, bytes:
|
|
227
|
+
{ memcmp: { offset: 40, bytes: agentMint } },
|
|
210
228
|
],
|
|
211
229
|
});
|
|
212
230
|
|
|
@@ -216,7 +234,7 @@ const toClose = attestations.value.items[0];
|
|
|
216
234
|
const result = await sati.closeAttestation({
|
|
217
235
|
payer,
|
|
218
236
|
sasSchema: feedbackSchema,
|
|
219
|
-
|
|
237
|
+
agentMint,
|
|
220
238
|
// Current attestation state (for proof verification)
|
|
221
239
|
dataType: DataType.Feedback,
|
|
222
240
|
currentData: toClose.data,
|
|
@@ -229,20 +247,20 @@ const result = await sati.closeAttestation({
|
|
|
229
247
|
console.log(result.signature); // Transaction signature
|
|
230
248
|
```
|
|
231
249
|
|
|
232
|
-
### Close Regular Attestation (
|
|
250
|
+
### Close Regular Attestation (ReputationScoreV3)
|
|
233
251
|
|
|
234
252
|
```typescript
|
|
235
|
-
//
|
|
253
|
+
// ReputationScoreV3 uses SAS storage, close via PDA
|
|
236
254
|
const result = await sati.closeReputationScore({
|
|
237
255
|
payer,
|
|
238
256
|
sasSchema: reputationSchema,
|
|
239
257
|
satiCredential,
|
|
240
|
-
|
|
258
|
+
agentMint,
|
|
241
259
|
provider: providerAddress, // Provider who created it
|
|
242
260
|
});
|
|
243
261
|
```
|
|
244
262
|
|
|
245
|
-
**Note:** Only the original provider can close a
|
|
263
|
+
**Note:** Only the original provider can close a ReputationScoreV3. Compressed attestations can be closed by anyone with the proof, but the rent goes back to the original payer.
|
|
246
264
|
|
|
247
265
|
---
|
|
248
266
|
|
|
@@ -262,8 +280,8 @@ const feedbacks = await rpc.getCompressedAccountsByOwner({
|
|
|
262
280
|
filters: [
|
|
263
281
|
// sas_schema at offset 8 (after 8-byte Light discriminator)
|
|
264
282
|
{ memcmp: { offset: 8, bytes: feedbackSchemaAddress } },
|
|
265
|
-
//
|
|
266
|
-
{ memcmp: { offset: 40, bytes:
|
|
283
|
+
// agent_mint at offset 40
|
|
284
|
+
{ memcmp: { offset: 40, bytes: agentMint } },
|
|
267
285
|
],
|
|
268
286
|
limit: 50,
|
|
269
287
|
});
|
|
@@ -282,7 +300,7 @@ The SDK exports offset constants for filtering:
|
|
|
282
300
|
|
|
283
301
|
```typescript
|
|
284
302
|
import {
|
|
285
|
-
COMPRESSED_OFFSETS, // Base offsets (sas_schema,
|
|
303
|
+
COMPRESSED_OFFSETS, // Base offsets (sas_schema, agent_mint)
|
|
286
304
|
FEEDBACK_OFFSETS, // Feedback-specific (outcome at 129 + 8)
|
|
287
305
|
VALIDATION_OFFSETS, // Validation-specific (response at 130 + 8)
|
|
288
306
|
} from "@cascade-fyi/sati-sdk";
|
|
@@ -291,7 +309,7 @@ import {
|
|
|
291
309
|
| Field | Offset | Notes |
|
|
292
310
|
|-------|--------|-------|
|
|
293
311
|
| `sas_schema` | 8 | Filter by attestation type |
|
|
294
|
-
| `
|
|
312
|
+
| `agent_mint` | 40 | Filter by agent |
|
|
295
313
|
| `outcome` (Feedback) | 137 | 0=Negative, 1=Neutral, 2=Positive |
|
|
296
314
|
| `response` (Validation) | 138 | Score 0-100 |
|
|
297
315
|
|
|
@@ -345,7 +363,7 @@ const result = await sati.createFeedback({
|
|
|
345
363
|
payer,
|
|
346
364
|
sasSchema,
|
|
347
365
|
taskRef,
|
|
348
|
-
|
|
366
|
+
agentMint,
|
|
349
367
|
counterparty: clientAddress,
|
|
350
368
|
dataHash: requestHash,
|
|
351
369
|
outcome: Outcome.Positive,
|
|
@@ -545,7 +563,7 @@ try {
|
|
|
545
563
|
|-------|-------|----------|
|
|
546
564
|
| `InvalidSignatureCount` | Wrong number of sigs for SignatureMode | DualSignature needs 2, SingleSigner needs 1 |
|
|
547
565
|
| `SignatureMismatch` | Sig pubkey doesn't match expected | Verify agent signs interaction hash, counterparty signs feedback hash |
|
|
548
|
-
| `SelfAttestationNotAllowed` | `
|
|
566
|
+
| `SelfAttestationNotAllowed` | `agentMint == counterparty` | Use different addresses for agent and counterparty |
|
|
549
567
|
| `InvalidAuthority` | Signer is not registry authority | Only authority can register schemas |
|
|
550
568
|
| `ImmutableAuthority` | Registry authority was renounced | Cannot modify immutable registry |
|
|
551
569
|
| `AttestationNotCloseable` | Schema has `closeable: false` | Use a different schema or don't close |
|
|
@@ -602,7 +620,7 @@ function validateFeedbackParams(params: CreateFeedbackParams) {
|
|
|
602
620
|
if (params.content && params.content.length > MAX_CONTENT_SIZE) {
|
|
603
621
|
throw new Error(`content exceeds ${MAX_CONTENT_SIZE} bytes`);
|
|
604
622
|
}
|
|
605
|
-
if (params.
|
|
623
|
+
if (params.agentMint === params.counterparty) {
|
|
606
624
|
throw new Error("Self-attestation not allowed");
|
|
607
625
|
}
|
|
608
626
|
}
|
|
@@ -616,10 +634,12 @@ function validateFeedbackParams(params: CreateFeedbackParams) {
|
|
|
616
634
|
|
|
617
635
|
```typescript
|
|
618
636
|
import {
|
|
619
|
-
computeInteractionHash,
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
637
|
+
computeInteractionHash, // Agent signs (blind to outcome)
|
|
638
|
+
computeAttestationNonce, // Deterministic nonce for compressed attestation address
|
|
639
|
+
computeReputationNonce, // Deterministic nonce for ReputationScoreV3 (one per provider+agent)
|
|
640
|
+
computeDataHash, // Hash request + response content
|
|
641
|
+
computeDataHashFromStrings, // Convenience wrapper for string content
|
|
642
|
+
zeroDataHash, // Zero-filled hash for CounterpartySigned schemas
|
|
623
643
|
} from "@cascade-fyi/sati-sdk";
|
|
624
644
|
```
|
|
625
645
|
|