@oobe-protocol-labs/synapse-sap-sdk 0.12.9 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/cjs/modules/base.js +61 -0
  2. package/dist/cjs/modules/base.js.map +1 -1
  3. package/dist/cjs/modules/escrow-v2.js +153 -0
  4. package/dist/cjs/modules/escrow-v2.js.map +1 -1
  5. package/dist/cjs/modules/escrow.js +36 -0
  6. package/dist/cjs/modules/escrow.js.map +1 -1
  7. package/dist/cjs/modules/staking.js +35 -0
  8. package/dist/cjs/modules/staking.js.map +1 -1
  9. package/dist/cjs/modules/tools.js +26 -0
  10. package/dist/cjs/modules/tools.js.map +1 -1
  11. package/dist/cjs/modules/vault.js +17 -0
  12. package/dist/cjs/modules/vault.js.map +1 -1
  13. package/dist/cjs/utils/anchor-errors.js +453 -0
  14. package/dist/cjs/utils/anchor-errors.js.map +1 -0
  15. package/dist/cjs/utils/index.js +12 -1
  16. package/dist/cjs/utils/index.js.map +1 -1
  17. package/dist/cjs/utils/volume-curve.js +117 -0
  18. package/dist/cjs/utils/volume-curve.js.map +1 -0
  19. package/dist/esm/modules/base.js +61 -0
  20. package/dist/esm/modules/base.js.map +1 -1
  21. package/dist/esm/modules/escrow-v2.js +153 -0
  22. package/dist/esm/modules/escrow-v2.js.map +1 -1
  23. package/dist/esm/modules/escrow.js +36 -0
  24. package/dist/esm/modules/escrow.js.map +1 -1
  25. package/dist/esm/modules/staking.js +35 -0
  26. package/dist/esm/modules/staking.js.map +1 -1
  27. package/dist/esm/modules/tools.js +26 -0
  28. package/dist/esm/modules/tools.js.map +1 -1
  29. package/dist/esm/modules/vault.js +17 -0
  30. package/dist/esm/modules/vault.js.map +1 -1
  31. package/dist/esm/utils/anchor-errors.js +447 -0
  32. package/dist/esm/utils/anchor-errors.js.map +1 -0
  33. package/dist/esm/utils/index.js +4 -0
  34. package/dist/esm/utils/index.js.map +1 -1
  35. package/dist/esm/utils/volume-curve.js +114 -0
  36. package/dist/esm/utils/volume-curve.js.map +1 -0
  37. package/dist/types/modules/base.d.ts +35 -0
  38. package/dist/types/modules/base.d.ts.map +1 -1
  39. package/dist/types/modules/escrow-v2.d.ts +70 -1
  40. package/dist/types/modules/escrow-v2.d.ts.map +1 -1
  41. package/dist/types/modules/escrow.d.ts.map +1 -1
  42. package/dist/types/modules/staking.d.ts.map +1 -1
  43. package/dist/types/modules/tools.d.ts.map +1 -1
  44. package/dist/types/modules/vault.d.ts.map +1 -1
  45. package/dist/types/utils/anchor-errors.d.ts +61 -0
  46. package/dist/types/utils/anchor-errors.d.ts.map +1 -0
  47. package/dist/types/utils/index.d.ts +3 -0
  48. package/dist/types/utils/index.d.ts.map +1 -1
  49. package/dist/types/utils/volume-curve.d.ts +60 -0
  50. package/dist/types/utils/volume-curve.d.ts.map +1 -0
  51. package/package.json +1 -1
  52. package/src/modules/base.ts +89 -0
  53. package/src/modules/escrow-v2.ts +214 -1
  54. package/src/modules/escrow.ts +56 -0
  55. package/src/modules/staking.ts +66 -0
  56. package/src/modules/tools.ts +43 -0
  57. package/src/modules/vault.ts +25 -0
  58. package/src/utils/anchor-errors.ts +461 -0
  59. package/src/utils/index.ts +16 -0
  60. package/src/utils/volume-curve.ts +131 -0
@@ -0,0 +1,461 @@
1
+ /**
2
+ * @module utils/anchor-errors
3
+ * @description Full SAP program error table (147 entries, codes 6000-6146)
4
+ * plus decoder utilities. Mirrors `programs/synapse-agent-sap/src/errors.rs`.
5
+ *
6
+ * Use {@link decodeAnchorError} to extract a structured error from any
7
+ * thrown RPC / simulation error. Use {@link SAP_ERRORS} for direct lookups.
8
+ *
9
+ * @category Utils
10
+ * @since v0.13.0
11
+ */
12
+
13
+ export interface SapErrorEntry { readonly code: number; readonly name: string; readonly msg: string; }
14
+ export const SAP_ERRORS: Readonly<Record<number, SapErrorEntry>> = Object.freeze({
15
+ 6000: { code: 6000, name: "NameTooLong", msg: "name>64" },
16
+ 6001: { code: 6001, name: "DescriptionTooLong", msg: "desc>256" },
17
+ 6002: { code: 6002, name: "UriTooLong", msg: "uri>256" },
18
+ 6003: { code: 6003, name: "TooManyCapabilities", msg: "caps>10" },
19
+ 6004: { code: 6004, name: "TooManyPricingTiers", msg: "tiers>5" },
20
+ 6005: { code: 6005, name: "TooManyProtocols", msg: "protos>5" },
21
+ 6006: { code: 6006, name: "TooManyPlugins", msg: "plugins>5" },
22
+ 6007: { code: 6007, name: "AlreadyActive", msg: "already active" },
23
+ 6008: { code: 6008, name: "AlreadyInactive", msg: "already inactive" },
24
+ 6009: { code: 6009, name: "InvalidFeedbackScore", msg: "score 0-1000" },
25
+ 6010: { code: 6010, name: "TagTooLong", msg: "tag>32" },
26
+ 6011: { code: 6011, name: "SelfReviewNotAllowed", msg: "self review" },
27
+ 6012: { code: 6012, name: "FeedbackAlreadyRevoked", msg: "already revoked" },
28
+ 6013: { code: 6013, name: "CapabilityIndexFull", msg: "cap idx full" },
29
+ 6014: { code: 6014, name: "ProtocolIndexFull", msg: "proto idx full" },
30
+ 6015: { code: 6015, name: "AgentNotInIndex", msg: "not in idx" },
31
+ 6016: { code: 6016, name: "InvalidCapabilityHash", msg: "cap hash" },
32
+ 6017: { code: 6017, name: "InvalidProtocolHash", msg: "proto hash" },
33
+ 6018: { code: 6018, name: "InvalidPluginType", msg: "bad plugin type" },
34
+ 6019: { code: 6019, name: "ChunkDataTooLarge", msg: "chunk>900" },
35
+ 6020: { code: 6020, name: "ContentTypeTooLong", msg: "ctype>max" },
36
+ 6021: { code: 6021, name: "IpfsCidTooLong", msg: "cid>max" },
37
+ 6022: { code: 6022, name: "EmptyName", msg: "empty name" },
38
+ 6023: { code: 6023, name: "ControlCharInName", msg: "ctrl char" },
39
+ 6024: { code: 6024, name: "EmptyDescription", msg: "empty desc" },
40
+ 6025: { code: 6025, name: "AgentIdTooLong", msg: "agentid>128" },
41
+ 6026: { code: 6026, name: "InvalidCapabilityFormat", msg: "cap format" },
42
+ 6027: { code: 6027, name: "DuplicateCapability", msg: "dup cap" },
43
+ 6028: { code: 6028, name: "EmptyTierId", msg: "empty tier" },
44
+ 6029: { code: 6029, name: "DuplicateTierId", msg: "dup tier" },
45
+ 6030: { code: 6030, name: "InvalidRateLimit", msg: "rate=0" },
46
+ 6031: { code: 6031, name: "SplRequiresTokenMint", msg: "spl needs mint" },
47
+ 6032: { code: 6032, name: "InvalidX402Endpoint", msg: "x402 https" },
48
+ 6033: { code: 6033, name: "InvalidVolumeCurve", msg: "curve order" },
49
+ 6034: { code: 6034, name: "TooManyVolumeCurvePoints", msg: "curve>5" },
50
+ 6035: { code: 6035, name: "MinPriceExceedsMax", msg: "min>max price" },
51
+ 6036: { code: 6036, name: "InvalidUptimePercent", msg: "uptime 0-100" },
52
+ 6037: { code: 6037, name: "SessionClosed", msg: "session closed" },
53
+ 6038: { code: 6038, name: "InvalidSequence", msg: "bad seq" },
54
+ 6039: { code: 6039, name: "InvalidFragmentIndex", msg: "frag idx" },
55
+ 6040: { code: 6040, name: "InscriptionTooLarge", msg: "data>750" },
56
+ 6041: { code: 6041, name: "EmptyInscription", msg: "empty data" },
57
+ 6042: { code: 6042, name: "InvalidTotalFragments", msg: "frags<1" },
58
+ 6043: { code: 6043, name: "EpochMismatch", msg: "epoch mismatch" },
59
+ 6044: { code: 6044, name: "VaultNotClosed", msg: "vault open" },
60
+ 6045: { code: 6045, name: "SessionNotClosed", msg: "session open" },
61
+ 6046: { code: 6046, name: "DelegateExpired", msg: "delegate expired" },
62
+ 6047: { code: 6047, name: "InvalidDelegate", msg: "bad delegate" },
63
+ 6048: { code: 6048, name: "ToolNameTooLong", msg: "tool>32" },
64
+ 6049: { code: 6049, name: "EmptyToolName", msg: "empty tool" },
65
+ 6050: { code: 6050, name: "InvalidToolNameHash", msg: "tool hash" },
66
+ 6051: { code: 6051, name: "InvalidToolHttpMethod", msg: "bad method" },
67
+ 6052: { code: 6052, name: "InvalidToolCategory", msg: "bad category" },
68
+ 6053: { code: 6053, name: "ToolAlreadyInactive", msg: "tool inactive" },
69
+ 6054: { code: 6054, name: "ToolAlreadyActive", msg: "tool active" },
70
+ 6055: { code: 6055, name: "InvalidSchemaHash", msg: "schema hash" },
71
+ 6056: { code: 6056, name: "InvalidSchemaType", msg: "schema type" },
72
+ 6057: { code: 6057, name: "InvalidCheckpointIndex", msg: "cp index" },
73
+ 6058: { code: 6058, name: "FeedbackNotRevoked", msg: "not revoked" },
74
+ 6059: { code: 6059, name: "IndexNotEmpty", msg: "idx not empty" },
75
+ 6060: { code: 6060, name: "SessionStillOpen", msg: "session open" },
76
+ 6061: { code: 6061, name: "NoFieldsToUpdate", msg: "no fields" },
77
+ 6062: { code: 6062, name: "InsufficientEscrowBalance", msg: "low balance" },
78
+ 6063: { code: 6063, name: "EscrowMaxCallsExceeded", msg: "max calls" },
79
+ 6064: { code: 6064, name: "EscrowEmpty", msg: "escrow empty" },
80
+ 6065: { code: 6065, name: "EscrowNotEmpty", msg: "escrow!=0" },
81
+ 6066: { code: 6066, name: "InvalidSettlementCalls", msg: "calls<1" },
82
+ 6067: { code: 6067, name: "AttestationTypeTooLong", msg: "atype>32" },
83
+ 6068: { code: 6068, name: "EmptyAttestationType", msg: "empty atype" },
84
+ 6069: { code: 6069, name: "SelfAttestationNotAllowed", msg: "self attest" },
85
+ 6070: { code: 6070, name: "AttestationAlreadyRevoked", msg: "already revoked" },
86
+ 6071: { code: 6071, name: "AttestationNotRevoked", msg: "not revoked" },
87
+ 6072: { code: 6072, name: "ToolCategoryIndexFull", msg: "cat idx full" },
88
+ 6073: { code: 6073, name: "ToolNotInCategoryIndex", msg: "not in cat" },
89
+ 6074: { code: 6074, name: "ToolCategoryMismatch", msg: "cat mismatch" },
90
+ 6075: { code: 6075, name: "ArithmeticOverflow", msg: "overflow" },
91
+ 6076: { code: 6076, name: "EscrowExpired", msg: "escrow expired" },
92
+ 6077: { code: 6077, name: "AgentInactive", msg: "agent inactive" },
93
+ 6078: { code: 6078, name: "AttestationExpired", msg: "attest expired" },
94
+ 6079: { code: 6079, name: "BufferFull", msg: "buf full" },
95
+ 6080: { code: 6080, name: "BufferDataTooLarge", msg: "buf>750" },
96
+ 6081: { code: 6081, name: "Unauthorized", msg: "unauthorized" },
97
+ 6082: { code: 6082, name: "InvalidSession", msg: "bad session" },
98
+ 6083: { code: 6083, name: "EmptyDigestHash", msg: "empty hash" },
99
+ 6084: { code: 6084, name: "LedgerDataTooLarge", msg: "ledger>750" },
100
+ 6085: { code: 6085, name: "LedgerRingEmpty", msg: "ring empty" },
101
+ 6086: { code: 6086, name: "BatchEmpty", msg: "batch empty" },
102
+ 6087: { code: 6087, name: "BatchTooLarge", msg: "batch>10" },
103
+ 6088: { code: 6088, name: "SplTokenRequired", msg: "spl accts" },
104
+ 6089: { code: 6089, name: "InvalidTokenAccount", msg: "bad token" },
105
+ 6090: { code: 6090, name: "InvalidTokenProgram", msg: "bad prog" },
106
+ 6091: { code: 6091, name: "InvalidSettlementSecurity", msg: "bad security" },
107
+ 6092: { code: 6092, name: "CoSignerRequired", msg: "cosigner" },
108
+ 6093: { code: 6093, name: "InvalidCoSigner", msg: "bad cosigner" },
109
+ 6094: { code: 6094, name: "InvalidArbiter", msg: "bad arbiter" },
110
+ 6095: { code: 6095, name: "ArbiterRequired", msg: "arbiter=0" },
111
+ 6096: { code: 6096, name: "EscrowNonceReused", msg: "nonce reused" },
112
+ 6097: { code: 6097, name: "SettlementNotPending", msg: "not pending" },
113
+ 6098: { code: 6098, name: "SettlementAlreadyFinalized", msg: "already final" },
114
+ 6099: { code: 6099, name: "DisputeWindowNotExpired", msg: "too early" },
115
+ 6100: { code: 6100, name: "DisputeWindowExpired", msg: "window closed" },
116
+ 6101: { code: 6101, name: "NotDepositor", msg: "not depositor" },
117
+ 6102: { code: 6102, name: "DisputeAlreadyFiled", msg: "dup dispute" },
118
+ 6103: { code: 6103, name: "DisputeStillOpen", msg: "dispute open" },
119
+ 6104: { code: 6104, name: "NotArbiter", msg: "not arbiter" },
120
+ 6105: { code: 6105, name: "InvalidDisputeOutcome", msg: "bad outcome" },
121
+ 6106: { code: 6106, name: "StakeBelowMinimum", msg: "stake<min" },
122
+ 6107: { code: 6107, name: "NoStakeAccount", msg: "no stake" },
123
+ 6108: { code: 6108, name: "UnstakeAlreadyPending", msg: "unstake pending" },
124
+ 6109: { code: 6109, name: "UnstakeCooldownNotMet", msg: "cooldown" },
125
+ 6110: { code: 6110, name: "NoUnstakePending", msg: "no unstake" },
126
+ 6111: { code: 6111, name: "SlashExceedsStake", msg: "slash>stake" },
127
+ 6112: { code: 6112, name: "SubscriptionAlreadyActive", msg: "sub active" },
128
+ 6113: { code: 6113, name: "SubscriptionCancelled", msg: "sub cancelled" },
129
+ 6114: { code: 6114, name: "NoIntervalDue", msg: "no due" },
130
+ 6115: { code: 6115, name: "SubscriptionInsufficientBalance", msg: "sub low bal" },
131
+ 6116: { code: 6116, name: "InvalidBillingInterval", msg: "bad interval" },
132
+ 6117: { code: 6117, name: "InvalidShardIndex", msg: "bad shard" },
133
+ 6118: { code: 6118, name: "IndexPageFull", msg: "page full" },
134
+ 6119: { code: 6119, name: "InvalidPageIndex", msg: "bad page" },
135
+ 6120: { code: 6120, name: "IndexPageNotEmpty", msg: "page≠empty" },
136
+ 6121: { code: 6121, name: "AlreadyMigrated", msg: "already v2" },
137
+ 6122: { code: 6122, name: "MigrationV1Only", msg: "v1 only" },
138
+ 6123: { code: 6123, name: "SettlementDisputed", msg: "disputed" },
139
+ 6124: { code: 6124, name: "InvalidAgentWallet", msg: "bad agent wallet" },
140
+ 6125: { code: 6125, name: "StakeAgentMismatch", msg: "stake agent mismatch" },
141
+ 6126: { code: 6126, name: "NotAuthority", msg: "not authority" },
142
+ 6127: { code: 6127, name: "UnstakeBelowRent", msg: "unstake below rent" },
143
+ 6128: { code: 6128, name: "InsufficientStake", msg: "insufficient stake" },
144
+ 6129: { code: 6129, name: "SelfReportDeprecated", msg: "SelfReport deprecated" },
145
+ 6130: { code: 6130, name: "ArbiterDeprecated", msg: "arbiter deprecated" },
146
+ 6131: { code: 6131, name: "InvalidBatchIndex", msg: "bad batch idx" },
147
+ 6132: { code: 6132, name: "InvalidPeriod", msg: "bad period" },
148
+ 6133: { code: 6133, name: "InvalidDisputeType", msg: "bad dispute type" },
149
+ 6134: { code: 6134, name: "ProofDeadlineExpired", msg: "proof expired" },
150
+ 6135: { code: 6135, name: "ProofDeadlineNotExpired", msg: "proof not expired" },
151
+ 6136: { code: 6136, name: "InvalidReceiptProof", msg: "bad receipt proof" },
152
+ 6137: { code: 6137, name: "SettlementReplay", msg: "settlement replay" },
153
+ 6138: { code: 6138, name: "PaymentTokenNotAllowed", msg: "token not allowed" },
154
+ 6139: { code: 6139, name: "AgentStakeRequired", msg: "agent stake required" },
155
+ 6140: { code: 6140, name: "DelegateExpiryInvalid", msg: "delegate expiry invalid" },
156
+ 6141: { code: 6141, name: "EscrowNotClosed", msg: "escrow not closed" },
157
+ 6142: { code: 6142, name: "VolumeCurveNotDescending", msg: "curve not descending" },
158
+ 6143: { code: 6143, name: "DuplicateServiceHash", msg: "dup service hash" },
159
+ 6144: { code: 6144, name: "StakeBelowCoverage", msg: "stake under coverage" },
160
+ 6145: { code: 6145, name: "StakeNotClosable", msg: "stake not closable" },
161
+ 6146: { code: 6146, name: "AgentStakeAccountMissing", msg: "agent stake account missing" },
162
+ });
163
+ export const SAP_ERROR_BY_NAME: Readonly<Record<string, number>> = Object.freeze({
164
+ NameTooLong: 6000,
165
+ DescriptionTooLong: 6001,
166
+ UriTooLong: 6002,
167
+ TooManyCapabilities: 6003,
168
+ TooManyPricingTiers: 6004,
169
+ TooManyProtocols: 6005,
170
+ TooManyPlugins: 6006,
171
+ AlreadyActive: 6007,
172
+ AlreadyInactive: 6008,
173
+ InvalidFeedbackScore: 6009,
174
+ TagTooLong: 6010,
175
+ SelfReviewNotAllowed: 6011,
176
+ FeedbackAlreadyRevoked: 6012,
177
+ CapabilityIndexFull: 6013,
178
+ ProtocolIndexFull: 6014,
179
+ AgentNotInIndex: 6015,
180
+ InvalidCapabilityHash: 6016,
181
+ InvalidProtocolHash: 6017,
182
+ InvalidPluginType: 6018,
183
+ ChunkDataTooLarge: 6019,
184
+ ContentTypeTooLong: 6020,
185
+ IpfsCidTooLong: 6021,
186
+ EmptyName: 6022,
187
+ ControlCharInName: 6023,
188
+ EmptyDescription: 6024,
189
+ AgentIdTooLong: 6025,
190
+ InvalidCapabilityFormat: 6026,
191
+ DuplicateCapability: 6027,
192
+ EmptyTierId: 6028,
193
+ DuplicateTierId: 6029,
194
+ InvalidRateLimit: 6030,
195
+ SplRequiresTokenMint: 6031,
196
+ InvalidX402Endpoint: 6032,
197
+ InvalidVolumeCurve: 6033,
198
+ TooManyVolumeCurvePoints: 6034,
199
+ MinPriceExceedsMax: 6035,
200
+ InvalidUptimePercent: 6036,
201
+ SessionClosed: 6037,
202
+ InvalidSequence: 6038,
203
+ InvalidFragmentIndex: 6039,
204
+ InscriptionTooLarge: 6040,
205
+ EmptyInscription: 6041,
206
+ InvalidTotalFragments: 6042,
207
+ EpochMismatch: 6043,
208
+ VaultNotClosed: 6044,
209
+ SessionNotClosed: 6045,
210
+ DelegateExpired: 6046,
211
+ InvalidDelegate: 6047,
212
+ ToolNameTooLong: 6048,
213
+ EmptyToolName: 6049,
214
+ InvalidToolNameHash: 6050,
215
+ InvalidToolHttpMethod: 6051,
216
+ InvalidToolCategory: 6052,
217
+ ToolAlreadyInactive: 6053,
218
+ ToolAlreadyActive: 6054,
219
+ InvalidSchemaHash: 6055,
220
+ InvalidSchemaType: 6056,
221
+ InvalidCheckpointIndex: 6057,
222
+ FeedbackNotRevoked: 6058,
223
+ IndexNotEmpty: 6059,
224
+ SessionStillOpen: 6060,
225
+ NoFieldsToUpdate: 6061,
226
+ InsufficientEscrowBalance: 6062,
227
+ EscrowMaxCallsExceeded: 6063,
228
+ EscrowEmpty: 6064,
229
+ EscrowNotEmpty: 6065,
230
+ InvalidSettlementCalls: 6066,
231
+ AttestationTypeTooLong: 6067,
232
+ EmptyAttestationType: 6068,
233
+ SelfAttestationNotAllowed: 6069,
234
+ AttestationAlreadyRevoked: 6070,
235
+ AttestationNotRevoked: 6071,
236
+ ToolCategoryIndexFull: 6072,
237
+ ToolNotInCategoryIndex: 6073,
238
+ ToolCategoryMismatch: 6074,
239
+ ArithmeticOverflow: 6075,
240
+ EscrowExpired: 6076,
241
+ AgentInactive: 6077,
242
+ AttestationExpired: 6078,
243
+ BufferFull: 6079,
244
+ BufferDataTooLarge: 6080,
245
+ Unauthorized: 6081,
246
+ InvalidSession: 6082,
247
+ EmptyDigestHash: 6083,
248
+ LedgerDataTooLarge: 6084,
249
+ LedgerRingEmpty: 6085,
250
+ BatchEmpty: 6086,
251
+ BatchTooLarge: 6087,
252
+ SplTokenRequired: 6088,
253
+ InvalidTokenAccount: 6089,
254
+ InvalidTokenProgram: 6090,
255
+ InvalidSettlementSecurity: 6091,
256
+ CoSignerRequired: 6092,
257
+ InvalidCoSigner: 6093,
258
+ InvalidArbiter: 6094,
259
+ ArbiterRequired: 6095,
260
+ EscrowNonceReused: 6096,
261
+ SettlementNotPending: 6097,
262
+ SettlementAlreadyFinalized: 6098,
263
+ DisputeWindowNotExpired: 6099,
264
+ DisputeWindowExpired: 6100,
265
+ NotDepositor: 6101,
266
+ DisputeAlreadyFiled: 6102,
267
+ DisputeStillOpen: 6103,
268
+ NotArbiter: 6104,
269
+ InvalidDisputeOutcome: 6105,
270
+ StakeBelowMinimum: 6106,
271
+ NoStakeAccount: 6107,
272
+ UnstakeAlreadyPending: 6108,
273
+ UnstakeCooldownNotMet: 6109,
274
+ NoUnstakePending: 6110,
275
+ SlashExceedsStake: 6111,
276
+ SubscriptionAlreadyActive: 6112,
277
+ SubscriptionCancelled: 6113,
278
+ NoIntervalDue: 6114,
279
+ SubscriptionInsufficientBalance: 6115,
280
+ InvalidBillingInterval: 6116,
281
+ InvalidShardIndex: 6117,
282
+ IndexPageFull: 6118,
283
+ InvalidPageIndex: 6119,
284
+ IndexPageNotEmpty: 6120,
285
+ AlreadyMigrated: 6121,
286
+ MigrationV1Only: 6122,
287
+ SettlementDisputed: 6123,
288
+ InvalidAgentWallet: 6124,
289
+ StakeAgentMismatch: 6125,
290
+ NotAuthority: 6126,
291
+ UnstakeBelowRent: 6127,
292
+ InsufficientStake: 6128,
293
+ SelfReportDeprecated: 6129,
294
+ ArbiterDeprecated: 6130,
295
+ InvalidBatchIndex: 6131,
296
+ InvalidPeriod: 6132,
297
+ InvalidDisputeType: 6133,
298
+ ProofDeadlineExpired: 6134,
299
+ ProofDeadlineNotExpired: 6135,
300
+ InvalidReceiptProof: 6136,
301
+ SettlementReplay: 6137,
302
+ PaymentTokenNotAllowed: 6138,
303
+ AgentStakeRequired: 6139,
304
+ DelegateExpiryInvalid: 6140,
305
+ EscrowNotClosed: 6141,
306
+ VolumeCurveNotDescending: 6142,
307
+ DuplicateServiceHash: 6143,
308
+ StakeBelowCoverage: 6144,
309
+ StakeNotClosable: 6145,
310
+ AgentStakeAccountMissing: 6146,
311
+ });
312
+
313
+ /**
314
+ * @name DecodedAnchorError
315
+ * @description Structured error extracted from a thrown RPC/simulation error.
316
+ * @since v0.13.0
317
+ */
318
+ export interface DecodedAnchorError {
319
+ readonly code: number;
320
+ readonly name: string;
321
+ readonly msg: string;
322
+ readonly friendly: string;
323
+ readonly logs?: readonly string[];
324
+ }
325
+
326
+ const FRIENDLY_OVERRIDES: Readonly<Record<string, string>> = Object.freeze({
327
+ Unauthorized: "Unauthorized — wallet does not match the on-chain authority for this PDA.",
328
+ AgentInactive: "Agent is inactive (deactivated). Reactivate before publishing tools or accepting escrows.",
329
+ AgentStakeRequired: "Agent stake account missing or below MIN_STAKE (0.1 SOL). Initialize stake first.",
330
+ StakeBelowMinimum: "Stake below minimum (0.1 SOL). Top up before requesting unstake or accepting escrows.",
331
+ StakeBelowCoverage: "Stake below coverage requirement for outstanding escrow. Increase stake or wait for escrows to settle.",
332
+ PaymentTokenNotAllowed: "Token mint not in allowlist. Use SOL (null) or USDC (mainnet/devnet).",
333
+ DelegateExpiryInvalid: "Delegate expiry exceeds MAX_DELEGATE_DURATION_SECS (365 days) from now.",
334
+ EscrowNotEmpty: "Escrow balance != 0. Withdraw or settle remaining funds before closing.",
335
+ EscrowEmpty: "Escrow balance is zero — cannot settle.",
336
+ InsufficientEscrowBalance: "Insufficient escrow balance for the requested settlement amount.",
337
+ ArithmeticOverflow: "Arithmetic overflow — likely an orphan PendingSettlement, mismatched amount, or unsigned subtraction. Run `escrowV2.diagnoseOrphanPending()` to inspect.",
338
+ EscrowNonceReused: "Escrow nonce already used by this depositor. Pick a fresh nonce.",
339
+ SettlementNotPending: "PendingSettlement is not in pending state (already finalized or never created).",
340
+ SettlementAlreadyFinalized: "PendingSettlement already finalized — cannot finalize twice.",
341
+ DisputeWindowNotExpired: "Dispute window still open. Wait until escrow.dispute_window_slots elapse before finalizing.",
342
+ DisputeWindowExpired: "Dispute window already closed. Cannot file dispute.",
343
+ CoSignerRequired: "Settlement security mode requires a co-signer. Pass the co-signer keypair.",
344
+ InvalidCoSigner: "Co-signer pubkey does not match the on-chain `escrow.co_signer`.",
345
+ InvalidSettlementSecurity: "Settlement security mode mismatch with on-chain escrow config.",
346
+ SettlementReplay: "Settlement receipt PDA already exists for this serviceHash/batchRoot. Replay blocked.",
347
+ DuplicateServiceHash: "Two settlements in the same batch share the same serviceHash. Make each call unique.",
348
+ BatchTooLarge: "Batch settle exceeds 10 entries. Split across multiple transactions.",
349
+ BatchEmpty: "Batch settle requires at least 1 settlement.",
350
+ InscriptionTooLarge: "Inscription chunk exceeds 750 bytes. Split into more fragments.",
351
+ InvalidSchemaHash: "Tool schema hash is empty / invalid. v0.2.0+ requires every tool to publish a JSON schema (or schema_hash).",
352
+ EmptyToolName: "Tool name cannot be empty.",
353
+ ToolNameTooLong: "Tool name exceeds 32 bytes.",
354
+ EscrowExpired: "Escrow expired (expiresAt passed). Create a new escrow.",
355
+ UnstakeCooldownNotMet: "Unstake cooldown not elapsed. Wait for the cooldown window before completing unstake.",
356
+ UnstakeBelowRent: "Resulting stake balance would fall below the rent-exempt minimum. Reduce unstake amount.",
357
+ });
358
+
359
+ /**
360
+ * @name decodeAnchorError
361
+ * @description Pull an Anchor / SAP error out of any caught value.
362
+ * Handles: AnchorError, raw RPC SimulateError, `0x...` hex codes,
363
+ * nested `error.errorCode.number`, and direct `code` numbers.
364
+ * @returns Structured {@link DecodedAnchorError} or `null` if not a SAP error.
365
+ * @since v0.13.0
366
+ */
367
+ export function decodeAnchorError(err: unknown): DecodedAnchorError | null {
368
+ if (err == null || typeof err !== "object") return null;
369
+
370
+ const code = extractCode(err);
371
+ if (code == null) return null;
372
+
373
+ const entry = SAP_ERRORS[code];
374
+ if (!entry) {
375
+ return {
376
+ code,
377
+ name: "Unknown",
378
+ msg: `custom program error 0x${code.toString(16)}`,
379
+ friendly: `Unknown SAP error (code ${code}). Check IDL.`,
380
+ logs: extractLogs(err),
381
+ };
382
+ }
383
+
384
+ return {
385
+ code: entry.code,
386
+ name: entry.name,
387
+ msg: entry.msg,
388
+ friendly: FRIENDLY_OVERRIDES[entry.name] ?? `${entry.name}: ${entry.msg}`,
389
+ logs: extractLogs(err),
390
+ };
391
+ }
392
+
393
+ function extractCode(err: unknown): number | null {
394
+ if (typeof err !== "object" || err == null) return null;
395
+ const e = err as Record<string, unknown>;
396
+ if (typeof e.code === "number") return e.code;
397
+
398
+ const nested = e.error;
399
+ if (nested && typeof nested === "object") {
400
+ const errorCode = (nested as Record<string, unknown>).errorCode;
401
+ if (errorCode && typeof errorCode === "object") {
402
+ const num = (errorCode as Record<string, unknown>).number;
403
+ if (typeof num === "number") return num;
404
+ }
405
+ }
406
+
407
+ const msg = (err as Error).message;
408
+ if (typeof msg === "string") {
409
+ const hex = msg.match(/custom program error:\s*0x([0-9a-fA-F]+)/);
410
+ if (hex?.[1]) return parseInt(hex[1], 16);
411
+ const dec = msg.match(/Error Number:\s*(\d+)/);
412
+ if (dec?.[1]) return parseInt(dec[1], 10);
413
+ }
414
+ return null;
415
+ }
416
+
417
+ function extractLogs(err: unknown): string[] | undefined {
418
+ if (typeof err !== "object" || err == null) return undefined;
419
+ const logs = (err as Record<string, unknown>).logs;
420
+ if (Array.isArray(logs)) return logs as string[];
421
+ const nested = (err as Record<string, unknown>).simulationResponse;
422
+ if (nested && typeof nested === "object") {
423
+ const inner = (nested as Record<string, unknown>).logs;
424
+ if (Array.isArray(inner)) return inner as string[];
425
+ }
426
+ return undefined;
427
+ }
428
+
429
+ /**
430
+ * @name SapPreflightError
431
+ * @description Thrown by SDK preflights when an on-chain check is guaranteed
432
+ * to fail. Carries the predicted error code/name so callers can branch
433
+ * without parsing strings.
434
+ * @since v0.13.0
435
+ */
436
+ export class SapPreflightError extends Error {
437
+ readonly preflight = true as const;
438
+ constructor(
439
+ message: string,
440
+ readonly predictedCode: number,
441
+ readonly predictedName: string,
442
+ readonly hint?: string,
443
+ ) {
444
+ super(message);
445
+ this.name = "SapPreflightError";
446
+ }
447
+ }
448
+
449
+ /**
450
+ * @name throwPredicted
451
+ * @description Helper for SDK preflights. Throws a {@link SapPreflightError}
452
+ * carrying the on-chain error name + friendly message.
453
+ * @since v0.13.0
454
+ */
455
+ export function throwPredicted(name: keyof typeof SAP_ERROR_BY_NAME, hint?: string): never {
456
+ const code = SAP_ERROR_BY_NAME[name as string] ?? -1;
457
+ const entry = code >= 0 ? SAP_ERRORS[code] : undefined;
458
+ const friendly = FRIENDLY_OVERRIDES[name as string] ?? `${String(name)}: ${entry?.msg ?? ""}`;
459
+ const full = hint ? `${friendly} (${hint})` : friendly;
460
+ throw new SapPreflightError(full, code, name as string, hint);
461
+ }
@@ -100,3 +100,19 @@ export type {
100
100
  SettlementPayload,
101
101
  GetX402DirectOptions,
102
102
  } from "./x402-direct";
103
+
104
+ // ── v0.13.0 Full SAP error table + preflight helpers ─
105
+ export {
106
+ SAP_ERRORS,
107
+ SAP_ERROR_BY_NAME,
108
+ decodeAnchorError,
109
+ SapPreflightError,
110
+ throwPredicted,
111
+ } from "./anchor-errors";
112
+ export type {
113
+ SapErrorEntry,
114
+ DecodedAnchorError,
115
+ } from "./anchor-errors";
116
+
117
+ // ── v0.13.0 Volume-curve mirror for client-side amount preview ──
118
+ export { calculateSettleAmount } from "./volume-curve";
@@ -0,0 +1,131 @@
1
+ /**
2
+ * @module volume-curve
3
+ * @description Client-side mirror of the on-chain `calculate_settle_amount`
4
+ * function from `programs/synapse-agent-sap/src/instructions/escrow_v2.rs`.
5
+ *
6
+ * Used by {@link EscrowV2Module.settle} to pre-compute the settlement
7
+ * `amount` so it can chain `createPendingSettlement` in the same transaction
8
+ * as `settleCallsV2` (DisputeWindow flow). Keeping the math in one place
9
+ * here ensures the SDK stays byte-for-byte aligned with the program; if the
10
+ * on-chain curve algorithm ever changes, this file is the single source of
11
+ * truth on the client.
12
+ *
13
+ * @category Utilities
14
+ * @since v0.13.0
15
+ * @packageDocumentation
16
+ */
17
+
18
+ import { BN } from "@coral-xyz/anchor";
19
+ import type { VolumeCurveBreakpoint } from "../types/common";
20
+
21
+ const U64_MAX = new BN("18446744073709551615");
22
+
23
+ function checkedMul(a: BN, b: BN): BN {
24
+ const r = a.mul(b);
25
+ if (r.gt(U64_MAX)) {
26
+ throw new Error(
27
+ `volume-curve: u64 overflow on multiply (${a.toString()} * ${b.toString()})`,
28
+ );
29
+ }
30
+ return r;
31
+ }
32
+
33
+ function checkedAdd(a: BN, b: BN): BN {
34
+ const r = a.add(b);
35
+ if (r.gt(U64_MAX)) {
36
+ throw new Error(
37
+ `volume-curve: u64 overflow on add (${a.toString()} + ${b.toString()})`,
38
+ );
39
+ }
40
+ return r;
41
+ }
42
+
43
+ /**
44
+ * @function calculateSettleAmount
45
+ * @description Compute the lamport (or token base-unit) amount the on-chain
46
+ * `settle_calls_v2` handler will charge for `calls` calls, given the escrow's
47
+ * `pricePerCall`, `volumeCurve`, and the current settled+pending counter.
48
+ *
49
+ * Mirrors the exact algorithm of `calculate_settle_amount` in
50
+ * `escrow_v2.rs` (v0.7+):
51
+ *
52
+ * ```rust
53
+ * if curve.is_empty() { calls * base_price } else { walk-the-curve }
54
+ * ```
55
+ *
56
+ * Walks the curve from `cursor = totalCallsBefore` and at each cursor
57
+ * position picks the breakpoint price whose `afterCalls` threshold the
58
+ * cursor has passed. Calls are charged at the active price up to the next
59
+ * threshold, then the cursor advances and the loop repeats until all
60
+ * `calls` are accounted for.
61
+ *
62
+ * @param basePrice - Escrow's `pricePerCall` (BN, u64 lamports/base-units).
63
+ * @param curve - The escrow's `volumeCurve` array (may be empty).
64
+ * @param totalCallsBefore - `escrow.totalCallsSettled + escrow.pendingCalls`
65
+ * AT THE MOMENT `settleCallsV2` runs on-chain.
66
+ * @param calls - Number of calls being settled in this batch.
67
+ * @returns The amount the on-chain handler will compute (BN, u64).
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * import { calculateSettleAmount } from "@oobe-protocol-labs/synapse-sap-sdk";
72
+ *
73
+ * const amount = calculateSettleAmount(
74
+ * escrow.pricePerCall,
75
+ * escrow.volumeCurve,
76
+ * escrow.totalCallsSettled.add(escrow.pendingCalls),
77
+ * new BN(5),
78
+ * );
79
+ * ```
80
+ *
81
+ * @since v0.13.0
82
+ */
83
+ export function calculateSettleAmount(
84
+ basePrice: BN,
85
+ curve: VolumeCurveBreakpoint[],
86
+ totalCallsBefore: BN,
87
+ calls: BN,
88
+ ): BN {
89
+ if (calls.isZero()) return new BN(0);
90
+ if (!curve || curve.length === 0) {
91
+ return checkedMul(calls, basePrice);
92
+ }
93
+
94
+ let amount = new BN(0);
95
+ let remaining = calls.clone();
96
+ let cursor = totalCallsBefore.clone();
97
+
98
+ while (remaining.gtn(0)) {
99
+ let currentPrice = basePrice;
100
+ let nextThreshold: BN | null = null;
101
+
102
+ for (const bp of curve) {
103
+ const threshold = new BN(bp.afterCalls);
104
+ if (cursor.gte(threshold)) {
105
+ currentPrice = bp.pricePerCall;
106
+ } else {
107
+ nextThreshold = threshold;
108
+ break;
109
+ }
110
+ }
111
+
112
+ let callsAtPrice: BN;
113
+ if (nextThreshold) {
114
+ const room = nextThreshold.sub(cursor);
115
+ callsAtPrice = BN.min(remaining, room.isNeg() ? new BN(0) : room);
116
+ if (callsAtPrice.isZero()) {
117
+ // Defensive: shouldn't happen because cursor < nextThreshold by
118
+ // the `else` branch above, but guard anyway.
119
+ callsAtPrice = remaining;
120
+ }
121
+ } else {
122
+ callsAtPrice = remaining;
123
+ }
124
+
125
+ amount = checkedAdd(amount, checkedMul(callsAtPrice, currentPrice));
126
+ remaining = remaining.sub(callsAtPrice);
127
+ cursor = cursor.add(callsAtPrice);
128
+ }
129
+
130
+ return amount;
131
+ }