@inversealtruism/cairn-sdk 0.2.3 → 0.3.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/dist/board.cjs CHANGED
@@ -27,7 +27,7 @@ var import_csd_codec = require("@inversealtruism/csd-codec");
27
27
  var import_csd_codec2 = require("@inversealtruism/csd-codec");
28
28
 
29
29
  // src/errors.ts
30
- var SDK_VERSION = "0.2.3";
30
+ var SDK_VERSION = "0.3.0";
31
31
  var DOCS_BASE = "https://cairn-substrate.com/docs/sdk";
32
32
  var CairnError = class extends Error {
33
33
  /** Stable machine code for programmatic branching. */
@@ -38,6 +38,12 @@ var CairnError = class extends Error {
38
38
  docsPath;
39
39
  /** The cairn-sdk version that produced this error. */
40
40
  version = SDK_VERSION;
41
+ /**
42
+ * Whether a dApp may safely AUTO-retry this failure. `false` for fund-safety refusals and user-intent
43
+ * declines (the default); `true` only for provably transient infra faults where nothing was signed.
44
+ * A `SubmitInFlightError` is `false` too: reconcile its `txid`, never blind-retry.
45
+ */
46
+ retryable;
41
47
  constructor(shortMessage, opts = {}) {
42
48
  const docs = opts.docsPath;
43
49
  super(
@@ -48,6 +54,7 @@ var CairnError = class extends Error {
48
54
  this.code = opts.code ?? "UNKNOWN";
49
55
  this.shortMessage = shortMessage;
50
56
  this.docsPath = docs;
57
+ this.retryable = opts.retryable ?? false;
51
58
  }
52
59
  /**
53
60
  * Walk the `cause` chain. With a predicate, returns the FIRST matching error (or null). Without one,
package/dist/board.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  BoardClient
3
- } from "./chunk-SVW7FUBJ.js";
4
- import "./chunk-M6OSWJVC.js";
3
+ } from "./chunk-NLCF5T2F.js";
4
+ import "./chunk-E2Z3XSCW.js";
5
5
  export {
6
6
  BoardClient
7
7
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  ContentVerificationError
3
- } from "./chunk-M6OSWJVC.js";
3
+ } from "./chunk-E2Z3XSCW.js";
4
4
 
5
5
  // src/content.ts
6
6
  import { payloadHash, canonicalJson, verifyContentBytes } from "@inversealtruism/csd-codec";
@@ -1,5 +1,5 @@
1
1
  // src/errors.ts
2
- var SDK_VERSION = "0.2.3";
2
+ var SDK_VERSION = "0.3.0";
3
3
  var DOCS_BASE = "https://cairn-substrate.com/docs/sdk";
4
4
  var CairnError = class extends Error {
5
5
  /** Stable machine code for programmatic branching. */
@@ -10,6 +10,12 @@ var CairnError = class extends Error {
10
10
  docsPath;
11
11
  /** The cairn-sdk version that produced this error. */
12
12
  version = SDK_VERSION;
13
+ /**
14
+ * Whether a dApp may safely AUTO-retry this failure. `false` for fund-safety refusals and user-intent
15
+ * declines (the default); `true` only for provably transient infra faults where nothing was signed.
16
+ * A `SubmitInFlightError` is `false` too: reconcile its `txid`, never blind-retry.
17
+ */
18
+ retryable;
13
19
  constructor(shortMessage, opts = {}) {
14
20
  const docs = opts.docsPath;
15
21
  super(
@@ -20,6 +26,7 @@ var CairnError = class extends Error {
20
26
  this.code = opts.code ?? "UNKNOWN";
21
27
  this.shortMessage = shortMessage;
22
28
  this.docsPath = docs;
29
+ this.retryable = opts.retryable ?? false;
23
30
  }
24
31
  /**
25
32
  * Walk the `cause` chain. With a predicate, returns the FIRST matching error (or null). Without one,
@@ -74,11 +81,43 @@ var ContentVerificationError = class extends CairnError {
74
81
  this.expected = expected;
75
82
  }
76
83
  };
84
+ var SubmitInFlightError = class extends CairnError {
85
+ /** The locally-computed consensus txid to reconcile against the chain (may be undefined if the wallet omitted it). */
86
+ txid;
87
+ /** Always true: the tx MAY be in the mempool. Reconcile via `txid`; never blind-retry. */
88
+ maybeSent = true;
89
+ constructor(message, code, txid) {
90
+ super(message, { code, docsPath: "/errors#submit-inflight", retryable: false });
91
+ this.txid = txid;
92
+ }
93
+ };
77
94
  var NATIVE_CODES = /* @__PURE__ */ new Set(["ACCOUNT_CHANGED", "FIRST_PARTY_ONLY", "RATE_LIMITED", "APPROVAL_CLOSED", "FORBIDDEN", "INTERNAL"]);
95
+ var NESTED_TRANSIENT = /* @__PURE__ */ new Set(["VERIFY_UNAVAILABLE", "OFFER_UNKNOWN"]);
96
+ var NESTED_TERMINAL = /* @__PURE__ */ new Set([
97
+ "FILL_UNSAFE",
98
+ "FILL_WRONG_TARGET",
99
+ "SOURCE_DIVERGENCE",
100
+ "VERIFY_TAMPER",
101
+ "SUBMIT_REJECTED",
102
+ "BAD_REQUEST",
103
+ "BAD_FEE",
104
+ "BAD_OUTPUTS",
105
+ "NO_OUTPUTS",
106
+ "ZERO_ADDR_REFUSED",
107
+ "TOO_MANY_INPUTS",
108
+ "INSUFFICIENT",
109
+ "FEE_CAP",
110
+ "FEE_TOO_LOW",
111
+ "ACCOUNT_CHANGED",
112
+ "GHOST_INPUTS_SKIPPED",
113
+ "NOTHING_TO_CONSOLIDATE"
114
+ ]);
78
115
  function mapProviderError(error, code) {
79
116
  if (code === "USER_REJECTED" || code === "APPROVAL_CLOSED") return new UserRejectedError(error);
80
117
  if (code === "WALLET_LOCKED") return new WalletLockedError(error);
81
118
  if (code === "UNSUPPORTED_METHOD" || code === "UNKNOWN_KIND") return new UnsupportedMethodError(error);
119
+ if (code && NESTED_TRANSIENT.has(code)) return new CairnError(error || code, { code, retryable: true });
120
+ if (code && NESTED_TERMINAL.has(code)) return new CairnError(error || code, { code, retryable: false });
82
121
  if (code && NATIVE_CODES.has(code)) return new CairnError(error || code, { code });
83
122
  const e = String(error || "").toLowerCase();
84
123
  if (e.includes("rejected by user")) return new UserRejectedError(error);
@@ -86,6 +125,14 @@ function mapProviderError(error, code) {
86
125
  if (e.includes("unsupported dapp method") || e.includes("predates") || e.includes("too old")) return new UnsupportedMethodError(error);
87
126
  return new CairnError(error || "Unknown wallet error");
88
127
  }
128
+ function mapSubmitResultError(result) {
129
+ const code = result?.code;
130
+ const msg = typeof result?.error === "string" && result.error || code || "The wallet refused the transaction.";
131
+ if (code === "SUBMIT_MAYBE_INFLIGHT" || code === "SUBMIT_DUPLICATE") {
132
+ return new SubmitInFlightError(msg, code, typeof result?.txid === "string" ? result.txid : void 0);
133
+ }
134
+ return mapProviderError(msg, code);
135
+ }
89
136
  function errorCode(err) {
90
137
  return err instanceof CairnError ? err.code : "UNKNOWN";
91
138
  }
@@ -99,6 +146,8 @@ export {
99
146
  UnsupportedMethodError,
100
147
  HttpError,
101
148
  ContentVerificationError,
149
+ SubmitInFlightError,
102
150
  mapProviderError,
151
+ mapSubmitResultError,
103
152
  errorCode
104
153
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  CairnError
3
- } from "./chunk-M6OSWJVC.js";
3
+ } from "./chunk-E2Z3XSCW.js";
4
4
 
5
5
  // src/board.ts
6
6
  import { payloadHash } from "@inversealtruism/csd-codec";
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  NotInstalledError,
3
3
  UnsupportedMethodError,
4
- mapProviderError
5
- } from "./chunk-M6OSWJVC.js";
4
+ mapProviderError,
5
+ mapSubmitResultError
6
+ } from "./chunk-E2Z3XSCW.js";
6
7
 
7
8
  // src/connect.ts
8
9
  function discoverProviders(opts = {}) {
@@ -74,6 +75,13 @@ function unwrap(reply) {
74
75
  if (reply && reply.ok) return reply.result;
75
76
  throw mapProviderError(reply?.error ?? "Unknown wallet error", reply?.code);
76
77
  }
78
+ function unwrapWrite(reply) {
79
+ const result = unwrap(reply);
80
+ if (result && typeof result === "object" && result.ok === false) {
81
+ throw mapSubmitResultError(result);
82
+ }
83
+ return result;
84
+ }
77
85
  var WalletConnection = class {
78
86
  provider;
79
87
  _addr = null;
@@ -140,12 +148,18 @@ var WalletConnection = class {
140
148
  return null;
141
149
  }
142
150
  }
143
- /** Atomic fill (CairnX DvP): pay + attest in ONE tx. Always prompts with clear-signing. */
151
+ /**
152
+ * CairnX fill: pay + attest in ONE tx (atomic SETTLEMENT SHAPE, both revert together). Always prompts with
153
+ * clear-signing. The payment recipient in `params.outputs` is RESOLVER-TRUSTED here: this SDK does NOT
154
+ * SPV-verify it, so a lying resolver can redirect the payment. A dApp settling real value MUST corroborate
155
+ * the offer on-chain before building `outputs` (F13). The wallet's own fill-SPV boundary (cairn-wallet
156
+ * 0.2.60+, which binds payment/rebate/fee to the merkle-proven offer) is the payment-grade check; see FillParams.
157
+ */
144
158
  fillOffer(params) {
145
159
  if (typeof this.provider.fillOffer !== "function") {
146
160
  return Promise.reject(new UnsupportedMethodError("this wallet predates fillOffer() \u2014 ask the user to update the Cairn Wallet"));
147
161
  }
148
- return Promise.resolve(this.provider.fillOffer(params)).then(unwrap);
162
+ return Promise.resolve(this.provider.fillOffer(params)).then(unwrapWrite);
149
163
  }
150
164
  /** This origin's current permission grant (EIP-2255-style). Silent; [] if none / unsupported. */
151
165
  async getPermissions() {
@@ -178,26 +192,26 @@ var WalletConnection = class {
178
192
  }
179
193
  /** Send CSD (always prompts with clear-signing; wallet picks inputs + returns change to itself). */
180
194
  send(params) {
181
- return Promise.resolve(this.provider.send(params)).then(unwrap);
195
+ return Promise.resolve(this.provider.send(params)).then(unwrapWrite);
182
196
  }
183
197
  /** Low-level Propose (always prompts). Prefer `cairn.board.propose()` which computes the hash/uri/expiry. */
184
198
  propose(params) {
185
- return Promise.resolve(this.provider.propose(params)).then(unwrap);
199
+ return Promise.resolve(this.provider.propose(params)).then(unwrapWrite);
186
200
  }
187
201
  /** Attest/support a proposal (always prompts). */
188
202
  attest(params) {
189
- return Promise.resolve(this.provider.attest(params)).then(unwrap);
203
+ return Promise.resolve(this.provider.attest(params)).then(unwrapWrite);
190
204
  }
191
205
  /** Seal a commit-reveal claim (always prompts; salt stays inside the wallet). */
192
206
  sealClaim(params) {
193
- return Promise.resolve(this.provider.sealClaim(params)).then(unwrap);
207
+ return Promise.resolve(this.provider.sealClaim(params)).then(unwrapWrite);
194
208
  }
195
209
  /** Reveal a previously sealed claim by its sealing txid (always prompts). */
196
210
  revealClaim(txid) {
197
211
  if (typeof txid !== "string" || !txid) {
198
212
  return Promise.reject(new UnsupportedMethodError("revealClaim requires the sealing txid"));
199
213
  }
200
- return Promise.resolve(this.provider.revealClaim(txid)).then(unwrap);
214
+ return Promise.resolve(this.provider.revealClaim(txid)).then(unwrapWrite);
201
215
  }
202
216
  };
203
217
  async function getWallet(opts = {}) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  getWallet
3
- } from "./chunk-TKZXUBDX.js";
3
+ } from "./chunk-QV2GIXO7.js";
4
4
 
5
5
  // src/controller.ts
6
6
  var DISCONNECTED = Object.freeze({ status: "disconnected", account: null, error: null });
package/dist/connect.cjs CHANGED
@@ -30,7 +30,7 @@ __export(connect_exports, {
30
30
  module.exports = __toCommonJS(connect_exports);
31
31
 
32
32
  // src/errors.ts
33
- var SDK_VERSION = "0.2.3";
33
+ var SDK_VERSION = "0.3.0";
34
34
  var DOCS_BASE = "https://cairn-substrate.com/docs/sdk";
35
35
  var CairnError = class extends Error {
36
36
  /** Stable machine code for programmatic branching. */
@@ -41,6 +41,12 @@ var CairnError = class extends Error {
41
41
  docsPath;
42
42
  /** The cairn-sdk version that produced this error. */
43
43
  version = SDK_VERSION;
44
+ /**
45
+ * Whether a dApp may safely AUTO-retry this failure. `false` for fund-safety refusals and user-intent
46
+ * declines (the default); `true` only for provably transient infra faults where nothing was signed.
47
+ * A `SubmitInFlightError` is `false` too: reconcile its `txid`, never blind-retry.
48
+ */
49
+ retryable;
44
50
  constructor(shortMessage, opts = {}) {
45
51
  const docs = opts.docsPath;
46
52
  super(
@@ -51,6 +57,7 @@ var CairnError = class extends Error {
51
57
  this.code = opts.code ?? "UNKNOWN";
52
58
  this.shortMessage = shortMessage;
53
59
  this.docsPath = docs;
60
+ this.retryable = opts.retryable ?? false;
54
61
  }
55
62
  /**
56
63
  * Walk the `cause` chain. With a predicate, returns the FIRST matching error (or null). Without one,
@@ -87,11 +94,43 @@ var UnsupportedMethodError = class extends CairnError {
87
94
  super(message, { code: "UNSUPPORTED_METHOD", docsPath: "/errors#unsupported-method" });
88
95
  }
89
96
  };
97
+ var SubmitInFlightError = class extends CairnError {
98
+ /** The locally-computed consensus txid to reconcile against the chain (may be undefined if the wallet omitted it). */
99
+ txid;
100
+ /** Always true: the tx MAY be in the mempool. Reconcile via `txid`; never blind-retry. */
101
+ maybeSent = true;
102
+ constructor(message, code, txid) {
103
+ super(message, { code, docsPath: "/errors#submit-inflight", retryable: false });
104
+ this.txid = txid;
105
+ }
106
+ };
90
107
  var NATIVE_CODES = /* @__PURE__ */ new Set(["ACCOUNT_CHANGED", "FIRST_PARTY_ONLY", "RATE_LIMITED", "APPROVAL_CLOSED", "FORBIDDEN", "INTERNAL"]);
108
+ var NESTED_TRANSIENT = /* @__PURE__ */ new Set(["VERIFY_UNAVAILABLE", "OFFER_UNKNOWN"]);
109
+ var NESTED_TERMINAL = /* @__PURE__ */ new Set([
110
+ "FILL_UNSAFE",
111
+ "FILL_WRONG_TARGET",
112
+ "SOURCE_DIVERGENCE",
113
+ "VERIFY_TAMPER",
114
+ "SUBMIT_REJECTED",
115
+ "BAD_REQUEST",
116
+ "BAD_FEE",
117
+ "BAD_OUTPUTS",
118
+ "NO_OUTPUTS",
119
+ "ZERO_ADDR_REFUSED",
120
+ "TOO_MANY_INPUTS",
121
+ "INSUFFICIENT",
122
+ "FEE_CAP",
123
+ "FEE_TOO_LOW",
124
+ "ACCOUNT_CHANGED",
125
+ "GHOST_INPUTS_SKIPPED",
126
+ "NOTHING_TO_CONSOLIDATE"
127
+ ]);
91
128
  function mapProviderError(error, code) {
92
129
  if (code === "USER_REJECTED" || code === "APPROVAL_CLOSED") return new UserRejectedError(error);
93
130
  if (code === "WALLET_LOCKED") return new WalletLockedError(error);
94
131
  if (code === "UNSUPPORTED_METHOD" || code === "UNKNOWN_KIND") return new UnsupportedMethodError(error);
132
+ if (code && NESTED_TRANSIENT.has(code)) return new CairnError(error || code, { code, retryable: true });
133
+ if (code && NESTED_TERMINAL.has(code)) return new CairnError(error || code, { code, retryable: false });
95
134
  if (code && NATIVE_CODES.has(code)) return new CairnError(error || code, { code });
96
135
  const e = String(error || "").toLowerCase();
97
136
  if (e.includes("rejected by user")) return new UserRejectedError(error);
@@ -99,6 +138,14 @@ function mapProviderError(error, code) {
99
138
  if (e.includes("unsupported dapp method") || e.includes("predates") || e.includes("too old")) return new UnsupportedMethodError(error);
100
139
  return new CairnError(error || "Unknown wallet error");
101
140
  }
141
+ function mapSubmitResultError(result) {
142
+ const code = result?.code;
143
+ const msg = typeof result?.error === "string" && result.error || code || "The wallet refused the transaction.";
144
+ if (code === "SUBMIT_MAYBE_INFLIGHT" || code === "SUBMIT_DUPLICATE") {
145
+ return new SubmitInFlightError(msg, code, typeof result?.txid === "string" ? result.txid : void 0);
146
+ }
147
+ return mapProviderError(msg, code);
148
+ }
102
149
 
103
150
  // src/connect.ts
104
151
  function discoverProviders(opts = {}) {
@@ -170,6 +217,13 @@ function unwrap(reply) {
170
217
  if (reply && reply.ok) return reply.result;
171
218
  throw mapProviderError(reply?.error ?? "Unknown wallet error", reply?.code);
172
219
  }
220
+ function unwrapWrite(reply) {
221
+ const result = unwrap(reply);
222
+ if (result && typeof result === "object" && result.ok === false) {
223
+ throw mapSubmitResultError(result);
224
+ }
225
+ return result;
226
+ }
173
227
  var WalletConnection = class {
174
228
  provider;
175
229
  _addr = null;
@@ -236,12 +290,18 @@ var WalletConnection = class {
236
290
  return null;
237
291
  }
238
292
  }
239
- /** Atomic fill (CairnX DvP): pay + attest in ONE tx. Always prompts with clear-signing. */
293
+ /**
294
+ * CairnX fill: pay + attest in ONE tx (atomic SETTLEMENT SHAPE, both revert together). Always prompts with
295
+ * clear-signing. The payment recipient in `params.outputs` is RESOLVER-TRUSTED here: this SDK does NOT
296
+ * SPV-verify it, so a lying resolver can redirect the payment. A dApp settling real value MUST corroborate
297
+ * the offer on-chain before building `outputs` (F13). The wallet's own fill-SPV boundary (cairn-wallet
298
+ * 0.2.60+, which binds payment/rebate/fee to the merkle-proven offer) is the payment-grade check; see FillParams.
299
+ */
240
300
  fillOffer(params) {
241
301
  if (typeof this.provider.fillOffer !== "function") {
242
302
  return Promise.reject(new UnsupportedMethodError("this wallet predates fillOffer() \u2014 ask the user to update the Cairn Wallet"));
243
303
  }
244
- return Promise.resolve(this.provider.fillOffer(params)).then(unwrap);
304
+ return Promise.resolve(this.provider.fillOffer(params)).then(unwrapWrite);
245
305
  }
246
306
  /** This origin's current permission grant (EIP-2255-style). Silent; [] if none / unsupported. */
247
307
  async getPermissions() {
@@ -274,26 +334,26 @@ var WalletConnection = class {
274
334
  }
275
335
  /** Send CSD (always prompts with clear-signing; wallet picks inputs + returns change to itself). */
276
336
  send(params) {
277
- return Promise.resolve(this.provider.send(params)).then(unwrap);
337
+ return Promise.resolve(this.provider.send(params)).then(unwrapWrite);
278
338
  }
279
339
  /** Low-level Propose (always prompts). Prefer `cairn.board.propose()` which computes the hash/uri/expiry. */
280
340
  propose(params) {
281
- return Promise.resolve(this.provider.propose(params)).then(unwrap);
341
+ return Promise.resolve(this.provider.propose(params)).then(unwrapWrite);
282
342
  }
283
343
  /** Attest/support a proposal (always prompts). */
284
344
  attest(params) {
285
- return Promise.resolve(this.provider.attest(params)).then(unwrap);
345
+ return Promise.resolve(this.provider.attest(params)).then(unwrapWrite);
286
346
  }
287
347
  /** Seal a commit-reveal claim (always prompts; salt stays inside the wallet). */
288
348
  sealClaim(params) {
289
- return Promise.resolve(this.provider.sealClaim(params)).then(unwrap);
349
+ return Promise.resolve(this.provider.sealClaim(params)).then(unwrapWrite);
290
350
  }
291
351
  /** Reveal a previously sealed claim by its sealing txid (always prompts). */
292
352
  revealClaim(txid) {
293
353
  if (typeof txid !== "string" || !txid) {
294
354
  return Promise.reject(new UnsupportedMethodError("revealClaim requires the sealing txid"));
295
355
  }
296
- return Promise.resolve(this.provider.revealClaim(txid)).then(unwrap);
356
+ return Promise.resolve(this.provider.revealClaim(txid)).then(unwrapWrite);
297
357
  }
298
358
  };
299
359
  async function getWallet(opts = {}) {
@@ -49,7 +49,16 @@ interface SealClaimParams {
49
49
  claim: string;
50
50
  fee?: number;
51
51
  }
52
- /** Atomic fill (CairnX delivery-vs-payment): an Attest + payment outputs in ONE tx. */
52
+ /**
53
+ * CairnX fill: an Attest plus the caller-supplied payment `outputs`, settled in ONE tx (both land or both
54
+ * revert). "Atomic" here describes only that single-tx SETTLEMENT SHAPE. It does NOT mean this SDK verifies
55
+ * that `outputs` pay the offer's true on-chain recipient: the payment legs are RESOLVER-TRUSTED unless the
56
+ * caller independently SPV-corroborates the offer. A lying/MITM'd resolver can return a wrong payment target,
57
+ * so a dApp settling real value MUST merkle-prove the offer and derive the recipient from its on-chain author
58
+ * before building `outputs`. Payment-grade offer verification is the wallet's on-device fill-SPV path (F13;
59
+ * added in cairn-wallet 0.2.60, which binds the fill payment/rebate/fee legs to the merkle-proven offer; see
60
+ * docs/SDK-GUIDE.md verifies-vs-trusts). An SPV pre-verify helper in this SDK is roadmapped.
61
+ */
53
62
  interface FillParams {
54
63
  proposalId: string;
55
64
  outputs: {
@@ -226,7 +235,13 @@ declare class WalletConnection {
226
235
  get supportsSiwc(): boolean;
227
236
  /** Feature/capability detection. Returns null if the wallet predates `getCapabilities`. */
228
237
  getCapabilities(): Promise<WalletCapabilities | null>;
229
- /** Atomic fill (CairnX DvP): pay + attest in ONE tx. Always prompts with clear-signing. */
238
+ /**
239
+ * CairnX fill: pay + attest in ONE tx (atomic SETTLEMENT SHAPE, both revert together). Always prompts with
240
+ * clear-signing. The payment recipient in `params.outputs` is RESOLVER-TRUSTED here: this SDK does NOT
241
+ * SPV-verify it, so a lying resolver can redirect the payment. A dApp settling real value MUST corroborate
242
+ * the offer on-chain before building `outputs` (F13). The wallet's own fill-SPV boundary (cairn-wallet
243
+ * 0.2.60+, which binds payment/rebate/fee to the merkle-proven offer) is the payment-grade check; see FillParams.
244
+ */
230
245
  fillOffer(params: FillParams): Promise<TxResult>;
231
246
  /** This origin's current permission grant (EIP-2255-style). Silent; [] if none / unsupported. */
232
247
  getPermissions(): Promise<WalletPermission[]>;
package/dist/connect.d.ts CHANGED
@@ -49,7 +49,16 @@ interface SealClaimParams {
49
49
  claim: string;
50
50
  fee?: number;
51
51
  }
52
- /** Atomic fill (CairnX delivery-vs-payment): an Attest + payment outputs in ONE tx. */
52
+ /**
53
+ * CairnX fill: an Attest plus the caller-supplied payment `outputs`, settled in ONE tx (both land or both
54
+ * revert). "Atomic" here describes only that single-tx SETTLEMENT SHAPE. It does NOT mean this SDK verifies
55
+ * that `outputs` pay the offer's true on-chain recipient: the payment legs are RESOLVER-TRUSTED unless the
56
+ * caller independently SPV-corroborates the offer. A lying/MITM'd resolver can return a wrong payment target,
57
+ * so a dApp settling real value MUST merkle-prove the offer and derive the recipient from its on-chain author
58
+ * before building `outputs`. Payment-grade offer verification is the wallet's on-device fill-SPV path (F13;
59
+ * added in cairn-wallet 0.2.60, which binds the fill payment/rebate/fee legs to the merkle-proven offer; see
60
+ * docs/SDK-GUIDE.md verifies-vs-trusts). An SPV pre-verify helper in this SDK is roadmapped.
61
+ */
53
62
  interface FillParams {
54
63
  proposalId: string;
55
64
  outputs: {
@@ -226,7 +235,13 @@ declare class WalletConnection {
226
235
  get supportsSiwc(): boolean;
227
236
  /** Feature/capability detection. Returns null if the wallet predates `getCapabilities`. */
228
237
  getCapabilities(): Promise<WalletCapabilities | null>;
229
- /** Atomic fill (CairnX DvP): pay + attest in ONE tx. Always prompts with clear-signing. */
238
+ /**
239
+ * CairnX fill: pay + attest in ONE tx (atomic SETTLEMENT SHAPE, both revert together). Always prompts with
240
+ * clear-signing. The payment recipient in `params.outputs` is RESOLVER-TRUSTED here: this SDK does NOT
241
+ * SPV-verify it, so a lying resolver can redirect the payment. A dApp settling real value MUST corroborate
242
+ * the offer on-chain before building `outputs` (F13). The wallet's own fill-SPV boundary (cairn-wallet
243
+ * 0.2.60+, which binds payment/rebate/fee to the merkle-proven offer) is the payment-grade check; see FillParams.
244
+ */
230
245
  fillOffer(params: FillParams): Promise<TxResult>;
231
246
  /** This origin's current permission grant (EIP-2255-style). Silent; [] if none / unsupported. */
232
247
  getPermissions(): Promise<WalletPermission[]>;
package/dist/connect.js CHANGED
@@ -5,8 +5,8 @@ import {
5
5
  discoverProviders,
6
6
  getWallet,
7
7
  isInstalled
8
- } from "./chunk-TKZXUBDX.js";
9
- import "./chunk-M6OSWJVC.js";
8
+ } from "./chunk-QV2GIXO7.js";
9
+ import "./chunk-E2Z3XSCW.js";
10
10
  export {
11
11
  WalletConnection,
12
12
  connect,
package/dist/content.cjs CHANGED
@@ -26,7 +26,7 @@ module.exports = __toCommonJS(content_exports);
26
26
  var import_csd_codec = require("@inversealtruism/csd-codec");
27
27
 
28
28
  // src/errors.ts
29
- var SDK_VERSION = "0.2.3";
29
+ var SDK_VERSION = "0.3.0";
30
30
  var DOCS_BASE = "https://cairn-substrate.com/docs/sdk";
31
31
  var CairnError = class extends Error {
32
32
  /** Stable machine code for programmatic branching. */
@@ -37,6 +37,12 @@ var CairnError = class extends Error {
37
37
  docsPath;
38
38
  /** The cairn-sdk version that produced this error. */
39
39
  version = SDK_VERSION;
40
+ /**
41
+ * Whether a dApp may safely AUTO-retry this failure. `false` for fund-safety refusals and user-intent
42
+ * declines (the default); `true` only for provably transient infra faults where nothing was signed.
43
+ * A `SubmitInFlightError` is `false` too: reconcile its `txid`, never blind-retry.
44
+ */
45
+ retryable;
40
46
  constructor(shortMessage, opts = {}) {
41
47
  const docs = opts.docsPath;
42
48
  super(
@@ -47,6 +53,7 @@ var CairnError = class extends Error {
47
53
  this.code = opts.code ?? "UNKNOWN";
48
54
  this.shortMessage = shortMessage;
49
55
  this.docsPath = docs;
56
+ this.retryable = opts.retryable ?? false;
50
57
  }
51
58
  /**
52
59
  * Walk the `cause` chain. With a predicate, returns the FIRST matching error (or null). Without one,
package/dist/content.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  ContentClient
3
- } from "./chunk-AAOETAUE.js";
4
- import "./chunk-M6OSWJVC.js";
3
+ } from "./chunk-4RDXEW35.js";
4
+ import "./chunk-E2Z3XSCW.js";
5
5
  export {
6
6
  ContentClient
7
7
  };