@defuse-protocol/intents-sdk 0.32.2 → 0.33.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/README.md CHANGED
@@ -23,6 +23,7 @@ interacting with various bridge implementations across multiple blockchains.
23
23
  - [Intent Publishing Hooks](#intent-publishing-hooks)
24
24
  - [Batch Withdrawals](#batch-withdrawals)
25
25
  - [Intent Management](#intent-management)
26
+ - [Nonce Invalidation](#nonce-invalidation)
26
27
  - [Configure Withdrawal Routes](#configure-withdrawal-routes)
27
28
  - [Asset Information Parsing](#asset-information-parsing)
28
29
  - [Waiting for Completion](#waiting-for-completion)
@@ -572,6 +573,17 @@ if (status.status === 'SETTLED') {
572
573
  - `SETTLED` - Intent successfully completed
573
574
  - `NOT_FOUND_OR_NOT_VALID` - Intent not found or invalid, it isn't executed onchain
574
575
 
576
+ ### Nonce Invalidation
577
+
578
+ Invalidate nonces to prevent execution of previously created intent payloads. Primarily used by **solvers** to revoke quotes due to price volatility, liquidity changes, or risk management.
579
+
580
+ ```typescript
581
+ await sdk.invalidateNonces({
582
+ nonces: ['VigoxLwmUGf35MGLVBG9Fh5cCtJw3D68pSKFcqGCkHU='],
583
+ signer: customIntentSigner, // optional - uses SDK default if not provided
584
+ });
585
+ ```
586
+
575
587
  ### Configure Withdrawal Routes
576
588
 
577
589
  **Recommended**: Use factory functions to create route configurations. The SDK provides factory functions for type-safe
@@ -1,6 +1,8 @@
1
1
  const require_rolldown_runtime = require('../../_virtual/rolldown_runtime.cjs');
2
2
  let __scure_base = require("@scure/base");
3
3
  __scure_base = require_rolldown_runtime.__toESM(__scure_base);
4
+ let valibot = require("valibot");
5
+ valibot = require_rolldown_runtime.__toESM(valibot);
4
6
  let near_api_js_lib_utils_serialize = require("near-api-js/lib/utils/serialize");
5
7
  near_api_js_lib_utils_serialize = require_rolldown_runtime.__toESM(near_api_js_lib_utils_serialize);
6
8
 
@@ -12,6 +14,17 @@ const VERSIONED_MAGIC_PREFIX = new Uint8Array([
12
14
  198
13
15
  ]);
14
16
  const LATEST_VERSION = 0;
17
+ /**
18
+ * Schema for validating decoded salted nonce structure.
19
+ * The decoded value from `VersionedNonceBuilder.decodeNonce()` should match this structure.
20
+ */
21
+ const saltedNonceSchema = valibot.object({
22
+ salt: valibot.array(valibot.number()),
23
+ inner: valibot.object({
24
+ deadline: valibot.bigint(),
25
+ nonce: valibot.array(valibot.number())
26
+ })
27
+ });
15
28
  var SaltedNonce = class {
16
29
  constructor(salt, inner) {
17
30
  this.salt = salt;
@@ -80,4 +93,5 @@ Object.defineProperty(exports, 'VersionedNonceBuilder', {
80
93
  get: function () {
81
94
  return VersionedNonceBuilder;
82
95
  }
83
- });
96
+ });
97
+ exports.saltedNonceSchema = saltedNonceSchema;
@@ -1,5 +1,6 @@
1
- //#region src/intents/expirable-nonce.d.ts
1
+ import "valibot";
2
2
 
3
+ //#region src/intents/expirable-nonce.d.ts
3
4
  type Salt = Uint8Array;
4
5
  declare class ExpirableNonce {
5
6
  deadline: bigint;
@@ -1,4 +1,5 @@
1
1
  import { base64 } from "@scure/base";
2
+ import * as v from "valibot";
2
3
  import { deserialize, serialize } from "near-api-js/lib/utils/serialize";
3
4
 
4
5
  //#region src/intents/expirable-nonce.ts
@@ -9,6 +10,17 @@ const VERSIONED_MAGIC_PREFIX = new Uint8Array([
9
10
  198
10
11
  ]);
11
12
  const LATEST_VERSION = 0;
13
+ /**
14
+ * Schema for validating decoded salted nonce structure.
15
+ * The decoded value from `VersionedNonceBuilder.decodeNonce()` should match this structure.
16
+ */
17
+ const saltedNonceSchema = v.object({
18
+ salt: v.array(v.number()),
19
+ inner: v.object({
20
+ deadline: v.bigint(),
21
+ nonce: v.array(v.number())
22
+ })
23
+ });
12
24
  var SaltedNonce = class {
13
25
  constructor(salt, inner) {
14
26
  this.salt = salt;
@@ -72,4 +84,4 @@ let VersionedNonceBuilder;
72
84
  })(VersionedNonceBuilder || (VersionedNonceBuilder = {}));
73
85
 
74
86
  //#endregion
75
- export { VersionedNonceBuilder };
87
+ export { VersionedNonceBuilder, saltedNonceSchema };
@@ -37,7 +37,7 @@ async function computeIntentHashHashBytes(signed) {
37
37
  case "webauthn": return require_webauthn.computeSignedWebAuthnHash(signed);
38
38
  case "ton_connect": return require_ton_connect.computeSignedTonConnectHash(signed);
39
39
  case "sep53": return require_sep53.computeSignedSep53Hash(signed);
40
- default: throw new Error(`Unknown payload standard: ${signed.standard}`);
40
+ default: throw new Error(`Unknown payload standard: ${standard}`);
41
41
  }
42
42
  }
43
43
  async function computeIntentHash(multiPayload) {
@@ -35,7 +35,7 @@ async function computeIntentHashHashBytes(signed) {
35
35
  case "webauthn": return computeSignedWebAuthnHash(signed);
36
36
  case "ton_connect": return computeSignedTonConnectHash(signed);
37
37
  case "sep53": return computeSignedSep53Hash(signed);
38
- default: throw new Error(`Unknown payload standard: ${signed.standard}`);
38
+ default: throw new Error(`Unknown payload standard: ${standard}`);
39
39
  }
40
40
  }
41
41
  async function computeIntentHash(multiPayload) {
package/dist/src/sdk.cjs CHANGED
@@ -9,6 +9,8 @@ const require_intents_bridge = require('./bridges/intents-bridge/intents-bridge.
9
9
  const require_omni_bridge = require('./bridges/omni-bridge/omni-bridge.cjs');
10
10
  const require_poa_bridge = require('./bridges/poa-bridge/poa-bridge.cjs');
11
11
  const require_public_rpc_urls = require('./constants/public-rpc-urls.cjs');
12
+ const require_expirable_nonce = require('./intents/expirable-nonce.cjs');
13
+ const require_intent_payload_factory = require('./intents/intent-payload-factory.cjs');
12
14
  const require_intent_executer = require('./intents/intent-executer-impl/intent-executer.cjs');
13
15
  const require_intent_relayer_public = require('./intents/intent-relayer-impl/intent-relayer-public.cjs');
14
16
  const require_intent_signer_noop = require('./intents/intent-signer-impl/intent-signer-noop.cjs');
@@ -23,6 +25,8 @@ let __hot_labs_omni_sdk = require("@hot-labs/omni-sdk");
23
25
  __hot_labs_omni_sdk = require_rolldown_runtime.__toESM(__hot_labs_omni_sdk);
24
26
  let viem = require("viem");
25
27
  viem = require_rolldown_runtime.__toESM(viem);
28
+ let valibot = require("valibot");
29
+ valibot = require_rolldown_runtime.__toESM(valibot);
26
30
 
27
31
  //#region src/sdk.ts
28
32
  var IntentsSDK = class {
@@ -115,6 +119,50 @@ var IntentsSDK = class {
115
119
  saltManager: this.saltManager
116
120
  });
117
121
  }
122
+ /**
123
+ * Invalidate multiple nonces by creating and sending empty signed intents.
124
+ * This prevents previously created but unused intent payloads from being executed.
125
+ *
126
+ * For expirable nonces (versioned nonces with embedded deadlines), the intent's
127
+ * deadline is automatically set to the minimum of:
128
+ * 1. The nonce's embedded deadline (can't exceed this)
129
+ * 2. 1 minute from now (for quick invalidation when possible)
130
+ *
131
+ * @param args.nonces - Array of nonce strings to invalidate (up to 400 nonces per call, but depends on gas consumption)
132
+ * @param args.signer - Optional intent signer to use (defaults to SDK's configured signer)
133
+ * @param args.logger - Optional logger for debugging
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * // Invalidate unused nonces
138
+ * await sdk.invalidateNonces({
139
+ * nonces: ['nonce1', 'nonce2', 'nonce3']
140
+ * });
141
+ * ```
142
+ */
143
+ async invalidateNonces(args) {
144
+ if (args.nonces.length === 0) return;
145
+ const intentSigner = args.signer ?? this.intentSigner;
146
+ (0, __defuse_protocol_internal_utils.assert)(intentSigner != null, "Intent signer is not provided");
147
+ const signedIntents = await Promise.all(args.nonces.map(async (nonce) => {
148
+ const builder = this.intentBuilder().setNonce(nonce);
149
+ try {
150
+ const decoded = require_expirable_nonce.VersionedNonceBuilder.decodeNonce(nonce);
151
+ if (valibot.is(require_expirable_nonce.saltedNonceSchema, decoded.value)) {
152
+ const nonceDeadlineMs = Number(decoded.value.inner.deadline / 1000000n);
153
+ const nonceDeadline = new Date(nonceDeadlineMs);
154
+ const oneMinuteFromNow = new Date(Date.now() + require_intent_payload_factory.DEFAULT_DEADLINE_MS);
155
+ const deadline = oneMinuteFromNow < nonceDeadline ? oneMinuteFromNow : nonceDeadline;
156
+ builder.setDeadline(deadline);
157
+ } else args.logger?.warn?.("Decoded nonce has unexpected structure, using default deadline");
158
+ } catch {}
159
+ return builder.buildAndSign(intentSigner);
160
+ }));
161
+ await this.intentRelayer.publishIntents({
162
+ multiPayloads: signedIntents,
163
+ quoteHashes: []
164
+ }, { logger: args.logger });
165
+ }
118
166
  async createWithdrawalIntents(args) {
119
167
  for (const bridge of this.bridges) if (await bridge.supports(args.withdrawalParams)) {
120
168
  const actualAmount = args.withdrawalParams.feeInclusive ? args.withdrawalParams.amount - args.feeEstimation.amount : args.withdrawalParams.amount;
@@ -49,6 +49,32 @@ declare class IntentsSDK implements IIntentsSDK {
49
49
  * ```
50
50
  */
51
51
  intentBuilder(): IntentPayloadBuilder;
52
+ /**
53
+ * Invalidate multiple nonces by creating and sending empty signed intents.
54
+ * This prevents previously created but unused intent payloads from being executed.
55
+ *
56
+ * For expirable nonces (versioned nonces with embedded deadlines), the intent's
57
+ * deadline is automatically set to the minimum of:
58
+ * 1. The nonce's embedded deadline (can't exceed this)
59
+ * 2. 1 minute from now (for quick invalidation when possible)
60
+ *
61
+ * @param args.nonces - Array of nonce strings to invalidate (up to 400 nonces per call, but depends on gas consumption)
62
+ * @param args.signer - Optional intent signer to use (defaults to SDK's configured signer)
63
+ * @param args.logger - Optional logger for debugging
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * // Invalidate unused nonces
68
+ * await sdk.invalidateNonces({
69
+ * nonces: ['nonce1', 'nonce2', 'nonce3']
70
+ * });
71
+ * ```
72
+ */
73
+ invalidateNonces(args: {
74
+ nonces: string[];
75
+ signer?: IIntentSigner;
76
+ logger?: ILogger;
77
+ }): Promise<void>;
52
78
  createWithdrawalIntents(args: {
53
79
  withdrawalParams: WithdrawalParams;
54
80
  feeEstimation: FeeEstimation;
package/dist/src/sdk.d.ts CHANGED
@@ -49,6 +49,32 @@ declare class IntentsSDK implements IIntentsSDK {
49
49
  * ```
50
50
  */
51
51
  intentBuilder(): IntentPayloadBuilder;
52
+ /**
53
+ * Invalidate multiple nonces by creating and sending empty signed intents.
54
+ * This prevents previously created but unused intent payloads from being executed.
55
+ *
56
+ * For expirable nonces (versioned nonces with embedded deadlines), the intent's
57
+ * deadline is automatically set to the minimum of:
58
+ * 1. The nonce's embedded deadline (can't exceed this)
59
+ * 2. 1 minute from now (for quick invalidation when possible)
60
+ *
61
+ * @param args.nonces - Array of nonce strings to invalidate (up to 400 nonces per call, but depends on gas consumption)
62
+ * @param args.signer - Optional intent signer to use (defaults to SDK's configured signer)
63
+ * @param args.logger - Optional logger for debugging
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * // Invalidate unused nonces
68
+ * await sdk.invalidateNonces({
69
+ * nonces: ['nonce1', 'nonce2', 'nonce3']
70
+ * });
71
+ * ```
72
+ */
73
+ invalidateNonces(args: {
74
+ nonces: string[];
75
+ signer?: IIntentSigner;
76
+ logger?: ILogger;
77
+ }): Promise<void>;
52
78
  createWithdrawalIntents(args: {
53
79
  withdrawalParams: WithdrawalParams;
54
80
  feeEstimation: FeeEstimation;
package/dist/src/sdk.js CHANGED
@@ -8,6 +8,8 @@ import { IntentsBridge } from "./bridges/intents-bridge/intents-bridge.js";
8
8
  import { OmniBridge } from "./bridges/omni-bridge/omni-bridge.js";
9
9
  import { PoaBridge } from "./bridges/poa-bridge/poa-bridge.js";
10
10
  import { PUBLIC_EVM_RPC_URLS, PUBLIC_STELLAR_RPC_URLS } from "./constants/public-rpc-urls.js";
11
+ import { VersionedNonceBuilder, saltedNonceSchema } from "./intents/expirable-nonce.js";
12
+ import { DEFAULT_DEADLINE_MS } from "./intents/intent-payload-factory.js";
11
13
  import { IntentExecuter } from "./intents/intent-executer-impl/intent-executer.js";
12
14
  import { IntentRelayerPublic } from "./intents/intent-relayer-impl/intent-relayer-public.js";
13
15
  import { noopIntentSigner } from "./intents/intent-signer-impl/intent-signer-noop.js";
@@ -19,6 +21,7 @@ import { IntentPayloadBuilder } from "./intents/intent-payload-builder.js";
19
21
  import { PUBLIC_NEAR_RPC_URLS, RETRY_CONFIGS, RelayPublishError, assert, configsByEnvironment, nearFailoverRpcProvider, solverRelay } from "@defuse-protocol/internal-utils";
20
22
  import { HotBridge } from "@hot-labs/omni-sdk";
21
23
  import { stringify } from "viem";
24
+ import * as v from "valibot";
22
25
 
23
26
  //#region src/sdk.ts
24
27
  var IntentsSDK = class {
@@ -111,6 +114,50 @@ var IntentsSDK = class {
111
114
  saltManager: this.saltManager
112
115
  });
113
116
  }
117
+ /**
118
+ * Invalidate multiple nonces by creating and sending empty signed intents.
119
+ * This prevents previously created but unused intent payloads from being executed.
120
+ *
121
+ * For expirable nonces (versioned nonces with embedded deadlines), the intent's
122
+ * deadline is automatically set to the minimum of:
123
+ * 1. The nonce's embedded deadline (can't exceed this)
124
+ * 2. 1 minute from now (for quick invalidation when possible)
125
+ *
126
+ * @param args.nonces - Array of nonce strings to invalidate (up to 400 nonces per call, but depends on gas consumption)
127
+ * @param args.signer - Optional intent signer to use (defaults to SDK's configured signer)
128
+ * @param args.logger - Optional logger for debugging
129
+ *
130
+ * @example
131
+ * ```typescript
132
+ * // Invalidate unused nonces
133
+ * await sdk.invalidateNonces({
134
+ * nonces: ['nonce1', 'nonce2', 'nonce3']
135
+ * });
136
+ * ```
137
+ */
138
+ async invalidateNonces(args) {
139
+ if (args.nonces.length === 0) return;
140
+ const intentSigner = args.signer ?? this.intentSigner;
141
+ assert(intentSigner != null, "Intent signer is not provided");
142
+ const signedIntents = await Promise.all(args.nonces.map(async (nonce) => {
143
+ const builder = this.intentBuilder().setNonce(nonce);
144
+ try {
145
+ const decoded = VersionedNonceBuilder.decodeNonce(nonce);
146
+ if (v.is(saltedNonceSchema, decoded.value)) {
147
+ const nonceDeadlineMs = Number(decoded.value.inner.deadline / 1000000n);
148
+ const nonceDeadline = new Date(nonceDeadlineMs);
149
+ const oneMinuteFromNow = new Date(Date.now() + DEFAULT_DEADLINE_MS);
150
+ const deadline = oneMinuteFromNow < nonceDeadline ? oneMinuteFromNow : nonceDeadline;
151
+ builder.setDeadline(deadline);
152
+ } else args.logger?.warn?.("Decoded nonce has unexpected structure, using default deadline");
153
+ } catch {}
154
+ return builder.buildAndSign(intentSigner);
155
+ }));
156
+ await this.intentRelayer.publishIntents({
157
+ multiPayloads: signedIntents,
158
+ quoteHashes: []
159
+ }, { logger: args.logger });
160
+ }
114
161
  async createWithdrawalIntents(args) {
115
162
  for (const bridge of this.bridges) if (await bridge.supports(args.withdrawalParams)) {
116
163
  const actualAmount = args.withdrawalParams.feeInclusive ? args.withdrawalParams.amount - args.feeEstimation.amount : args.withdrawalParams.amount;
@@ -120,6 +120,11 @@ interface IIntentsSDK {
120
120
  intentHash: IntentHash;
121
121
  logger?: ILogger;
122
122
  }): Promise<IntentSettlementStatus>;
123
+ invalidateNonces(args: {
124
+ nonces: string[];
125
+ signer?: IIntentSigner;
126
+ logger?: ILogger;
127
+ }): Promise<void>;
123
128
  estimateWithdrawalFee(args: {
124
129
  withdrawalParams: WithdrawalParams;
125
130
  quoteOptions?: QuoteOptions;
@@ -120,6 +120,11 @@ interface IIntentsSDK {
120
120
  intentHash: IntentHash;
121
121
  logger?: ILogger;
122
122
  }): Promise<IntentSettlementStatus>;
123
+ invalidateNonces(args: {
124
+ nonces: string[];
125
+ signer?: IIntentSigner;
126
+ logger?: ILogger;
127
+ }): Promise<void>;
123
128
  estimateWithdrawalFee(args: {
124
129
  withdrawalParams: WithdrawalParams;
125
130
  quoteOptions?: QuoteOptions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defuse-protocol/intents-sdk",
3
- "version": "0.32.2",
3
+ "version": "0.33.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -38,8 +38,8 @@
38
38
  "ripple-address-codec": "^5.0.0",
39
39
  "valibot": "^1.0.0",
40
40
  "viem": "^2.0.0",
41
- "@defuse-protocol/contract-types": "0.3.0",
42
- "@defuse-protocol/internal-utils": "0.19.0"
41
+ "@defuse-protocol/contract-types": "0.3.1",
42
+ "@defuse-protocol/internal-utils": "0.19.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "tsdown": "0.15.5",