@axonfi/sdk 0.8.0 → 0.10.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
@@ -238,8 +238,8 @@ Interact with DeFi and Web3 protocols (Uniswap, Aave, GMX, Ostium, etc.) from yo
238
238
  const result = await axon.execute({
239
239
  protocol: '0xUniswapRouter',
240
240
  callData: '0x...',
241
- token: Token.USDC,
242
- amount: 100,
241
+ tokens: [Token.USDC],
242
+ amounts: [100],
243
243
  });
244
244
  ```
245
245
 
@@ -268,8 +268,8 @@ const OSTIUM_TRADING_STORAGE = '0x...'; // pulls USDC via transferFrom()
268
268
  await axon.execute({
269
269
  protocol: USDC, // call target: the token contract itself
270
270
  callData: encodeApprove(OSTIUM_TRADING_STORAGE, MaxUint256),
271
- token: USDC,
272
- amount: 0, // no token spend, just setting an allowance
271
+ tokens: [USDC],
272
+ amounts: [0], // no token spend, just setting an allowance
273
273
  protocolName: 'USDC Approve',
274
274
  });
275
275
 
@@ -277,8 +277,8 @@ await axon.execute({
277
277
  await axon.execute({
278
278
  protocol: OSTIUM_TRADING, // call target: the Trading contract
279
279
  callData: encodeOpenTrade(...),
280
- token: USDC,
281
- amount: 50_000_000, // 50 USDC — passed for dashboard/AI visibility
280
+ tokens: [USDC],
281
+ amounts: [50_000_000], // 50 USDC — passed for dashboard/AI visibility
282
282
  protocolName: 'Ostium',
283
283
  });
284
284
  ```
package/dist/index.cjs CHANGED
@@ -18,7 +18,7 @@ var PAYMENT_INTENT_TYPEHASH = viem.keccak256(
18
18
  );
19
19
  var EXECUTE_INTENT_TYPEHASH = viem.keccak256(
20
20
  viem.stringToBytes(
21
- "ExecuteIntent(address bot,address protocol,bytes32 calldataHash,address token,uint256 amount,uint256 value,address[] extraTokens,uint256[] extraAmounts,uint256 deadline,bytes32 ref)"
21
+ "ExecuteIntent(address bot,address protocol,bytes32 calldataHash,address[] tokens,uint256[] amounts,uint256 value,uint256 deadline,bytes32 ref)"
22
22
  )
23
23
  );
24
24
  var SWAP_INTENT_TYPEHASH = viem.keccak256(
@@ -153,11 +153,9 @@ var EXECUTE_INTENT_TYPES = {
153
153
  { name: "bot", type: "address" },
154
154
  { name: "protocol", type: "address" },
155
155
  { name: "calldataHash", type: "bytes32" },
156
- { name: "token", type: "address" },
157
- { name: "amount", type: "uint256" },
156
+ { name: "tokens", type: "address[]" },
157
+ { name: "amounts", type: "uint256[]" },
158
158
  { name: "value", type: "uint256" },
159
- { name: "extraTokens", type: "address[]" },
160
- { name: "extraAmounts", type: "uint256[]" },
161
159
  { name: "deadline", type: "uint256" },
162
160
  { name: "ref", type: "bytes32" }
163
161
  ]
@@ -211,11 +209,9 @@ async function signExecuteIntent(walletClient, vaultAddress, chainId, intent) {
211
209
  bot: intent.bot,
212
210
  protocol: intent.protocol,
213
211
  calldataHash: intent.calldataHash,
214
- token: intent.token,
215
- amount: intent.amount,
212
+ tokens: intent.tokens,
213
+ amounts: intent.amounts,
216
214
  value: intent.value,
217
- extraTokens: intent.extraTokens,
218
- extraAmounts: intent.extraAmounts,
219
215
  deadline: intent.deadline,
220
216
  ref: intent.ref
221
217
  }
@@ -726,30 +722,20 @@ var AxonVaultAbi = [
726
722
  "internalType": "bytes32"
727
723
  },
728
724
  {
729
- "name": "token",
730
- "type": "address",
731
- "internalType": "address"
725
+ "name": "tokens",
726
+ "type": "address[]",
727
+ "internalType": "address[]"
732
728
  },
733
729
  {
734
- "name": "amount",
735
- "type": "uint256",
736
- "internalType": "uint256"
730
+ "name": "amounts",
731
+ "type": "uint256[]",
732
+ "internalType": "uint256[]"
737
733
  },
738
734
  {
739
735
  "name": "value",
740
736
  "type": "uint256",
741
737
  "internalType": "uint256"
742
738
  },
743
- {
744
- "name": "extraTokens",
745
- "type": "address[]",
746
- "internalType": "address[]"
747
- },
748
- {
749
- "name": "extraAmounts",
750
- "type": "uint256[]",
751
- "internalType": "uint256[]"
752
- },
753
739
  {
754
740
  "name": "deadline",
755
741
  "type": "uint256",
@@ -2599,6 +2585,11 @@ var AxonVaultAbi = [
2599
2585
  "name": "TooManySpendingLimits",
2600
2586
  "inputs": []
2601
2587
  },
2588
+ {
2589
+ "type": "error",
2590
+ "name": "TooManyTokens",
2591
+ "inputs": []
2592
+ },
2602
2593
  {
2603
2594
  "type": "error",
2604
2595
  "name": "UnexpectedETH",
@@ -3984,11 +3975,30 @@ var AxonClient = class {
3984
3975
  * - `"approved"`: fast path — txHash available immediately
3985
3976
  * - `"pending_review"`: AI scan or human review in progress — poll for status
3986
3977
  * - `"rejected"`: payment was rejected — reason field explains why
3978
+ *
3979
+ * If the vault doesn't hold enough of the payment token, the relayer returns
3980
+ * `errorCode: 'SWAP_REQUIRED'`. The SDK automatically signs a SwapIntent and
3981
+ * resubmits the payment with swap fields — no action needed from the caller.
3987
3982
  */
3988
3983
  async pay(input) {
3989
3984
  const intent = this._buildPaymentIntent(input);
3990
3985
  const signature = await signPayment(this.walletClient, this.vaultAddress, this.chainId, intent);
3991
- return this._submitPayment(intent, signature, input);
3986
+ const result = await this._submitPayment(intent, signature, input);
3987
+ if (result.status === "rejected" && result.errorCode === "SWAP_REQUIRED") {
3988
+ const swapIntent = {
3989
+ bot: this.botAddress,
3990
+ toToken: intent.token,
3991
+ // swap TO the payment token
3992
+ minToAmount: intent.amount,
3993
+ // need at least the payment amount
3994
+ deadline: intent.deadline,
3995
+ // same deadline
3996
+ ref: intent.ref
3997
+ };
3998
+ const swapSig = await signSwapIntent(this.walletClient, this.vaultAddress, this.chainId, swapIntent);
3999
+ return this._submitPaymentWithSwap(intent, signature, input, swapIntent, swapSig);
4000
+ }
4001
+ return result;
3992
4002
  }
3993
4003
  // ============================================================================
3994
4004
  // execute()
@@ -4224,15 +4234,30 @@ Timestamp: ${timestamp}`;
4224
4234
  }
4225
4235
  _buildExecuteIntent(input) {
4226
4236
  _rejectBurnAddress(input.protocol, "Protocol address");
4237
+ const inputTokens = input.tokens ?? [];
4238
+ const inputAmounts = input.amounts ?? [];
4239
+ if (inputTokens.length !== inputAmounts.length) {
4240
+ throw new Error(`tokens length (${inputTokens.length}) must match amounts length (${inputAmounts.length})`);
4241
+ }
4242
+ if (inputTokens.length > 5) {
4243
+ throw new Error(`Too many tokens (${inputTokens.length}): maximum 5 allowed. Contact Axon if you need more.`);
4244
+ }
4245
+ const resolvedTokens = inputTokens.map((t) => resolveToken(t, this.chainId));
4246
+ const zeroAddr = "0x0000000000000000000000000000000000000000";
4247
+ for (const t of resolvedTokens) {
4248
+ if (t.toLowerCase() === zeroAddr) throw new Error("Zero address not allowed in tokens array");
4249
+ }
4250
+ const uniqueTokens = new Set(resolvedTokens.map((t) => t.toLowerCase()));
4251
+ if (uniqueTokens.size !== resolvedTokens.length) {
4252
+ throw new Error("Duplicate token addresses in tokens array");
4253
+ }
4227
4254
  return {
4228
4255
  bot: this.botAddress,
4229
4256
  protocol: input.protocol,
4230
4257
  calldataHash: viem.keccak256(input.callData),
4231
- token: resolveToken(input.token, this.chainId),
4232
- amount: parseAmount(input.amount, input.token, this.chainId),
4258
+ tokens: resolvedTokens,
4259
+ amounts: inputTokens.map((t, i) => parseAmount(inputAmounts[i], t, this.chainId)),
4233
4260
  value: input.value ?? 0n,
4234
- extraTokens: input.extraTokens ?? [],
4235
- extraAmounts: input.extraAmounts ?? [],
4236
4261
  deadline: input.deadline ?? this._defaultDeadline(),
4237
4262
  ref: this._resolveRef(input.memo, input.ref)
4238
4263
  };
@@ -4246,6 +4271,38 @@ Timestamp: ${timestamp}`;
4246
4271
  ref: this._resolveRef(input.memo, input.ref)
4247
4272
  };
4248
4273
  }
4274
+ async _submitPaymentWithSwap(intent, signature, input, swapIntent, swapSignature) {
4275
+ const idempotencyKey = generateUuid();
4276
+ const body = {
4277
+ // Routing
4278
+ chainId: this.chainId,
4279
+ vaultAddress: this.vaultAddress,
4280
+ // Flat intent fields (matches relayer DTO)
4281
+ bot: intent.bot,
4282
+ to: intent.to,
4283
+ token: intent.token,
4284
+ amount: intent.amount.toString(),
4285
+ deadline: intent.deadline.toString(),
4286
+ ref: intent.ref,
4287
+ signature,
4288
+ // Swap fields
4289
+ swapSignature,
4290
+ swapToToken: swapIntent.toToken,
4291
+ swapMinToAmount: swapIntent.minToAmount.toString(),
4292
+ swapDeadline: swapIntent.deadline.toString(),
4293
+ swapRef: swapIntent.ref,
4294
+ // Off-chain metadata
4295
+ idempotencyKey,
4296
+ ...input.memo !== void 0 && { memo: input.memo },
4297
+ ...input.resourceUrl !== void 0 && { resourceUrl: input.resourceUrl },
4298
+ ...input.invoiceId !== void 0 && { invoiceId: input.invoiceId },
4299
+ ...input.orderId !== void 0 && { orderId: input.orderId },
4300
+ ...input.recipientLabel !== void 0 && { recipientLabel: input.recipientLabel },
4301
+ ...input.metadata !== void 0 && { metadata: input.metadata },
4302
+ ...input.x402Funding !== void 0 && { x402Funding: input.x402Funding }
4303
+ };
4304
+ return this._post(RELAYER_API.PAYMENTS, idempotencyKey, body);
4305
+ }
4249
4306
  async _submitPayment(intent, signature, input) {
4250
4307
  const idempotencyKey = input.idempotencyKey ?? generateUuid();
4251
4308
  const body = {
@@ -4274,8 +4331,6 @@ Timestamp: ${timestamp}`;
4274
4331
  }
4275
4332
  async _submitExecute(intent, signature, input) {
4276
4333
  const idempotencyKey = input.idempotencyKey ?? generateUuid();
4277
- const fromToken = input.fromToken !== void 0 ? resolveToken(input.fromToken, this.chainId) : void 0;
4278
- const maxFromAmount = input.maxFromAmount !== void 0 ? parseAmount(input.maxFromAmount, input.fromToken ?? input.token, this.chainId) : void 0;
4279
4334
  const body = {
4280
4335
  chainId: this.chainId,
4281
4336
  vaultAddress: this.vaultAddress,
@@ -4283,17 +4338,14 @@ Timestamp: ${timestamp}`;
4283
4338
  bot: intent.bot,
4284
4339
  protocol: intent.protocol,
4285
4340
  calldataHash: intent.calldataHash,
4286
- token: intent.token,
4287
- amount: intent.amount.toString(),
4341
+ tokens: intent.tokens,
4342
+ amounts: intent.amounts.map((a) => a.toString()),
4288
4343
  value: intent.value.toString(),
4289
4344
  deadline: intent.deadline.toString(),
4290
4345
  ref: intent.ref,
4291
4346
  signature,
4292
4347
  // Protocol calldata
4293
4348
  callData: input.callData,
4294
- // Optional pre-swap
4295
- ...fromToken !== void 0 && { fromToken },
4296
- ...maxFromAmount !== void 0 && { maxFromAmount: maxFromAmount.toString() },
4297
4349
  // Off-chain metadata
4298
4350
  idempotencyKey,
4299
4351
  ...input.memo !== void 0 && { memo: input.memo },