@axonfi/sdk 0.4.4 → 0.5.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
@@ -24,23 +24,109 @@ Your agents pay. You stay in control.
24
24
  npm install @axonfi/sdk
25
25
  ```
26
26
 
27
- ## Prerequisites
27
+ ## Setup
28
28
 
29
- Before using the SDK, you need an Axon vault with a registered bot:
29
+ There are two ways to set up an Axon vault: through the **dashboard** (UI) or entirely through the **SDK** (programmatic). Both produce the same on-chain result.
30
30
 
31
- 1. **Deploy a vault** — Go to [app.axonfi.xyz](https://app.axonfi.xyz), connect your wallet, and deploy a vault on your target chain. The vault is a non-custodial smart contract — only you (the owner) can withdraw funds.
31
+ ### Option A: Dashboard Setup
32
32
 
33
- 2. **Fund the vault** — Send USDC (or any ERC-20) to your vault address. Anyone can deposit directly to the contract.
33
+ 1. Go to [app.axonfi.xyz](https://app.axonfi.xyz), connect your wallet, deploy a vault
34
+ 2. Fund the vault — send USDC, ETH, or any ERC-20 to the vault address
35
+ 3. Register a bot — generate a keypair or bring your own key
36
+ 4. Configure policies — per-tx caps, daily limits, AI threshold
37
+ 5. Give the bot key to your agent
34
38
 
35
- 3. **Register a bot** In the dashboard, go to your vault → Bots → Add Bot. You can either:
36
- - **Generate a new keypair** (recommended) — the dashboard creates a key and downloads an encrypted keystore JSON file. You set the passphrase.
37
- - **Bring your own key** — paste an existing public key if you manage keys externally.
39
+ ### Option B: Full SDK Setup (Programmatic)
38
40
 
39
- 4. **Configure policies** Set per-transaction caps, daily spending limits, velocity windows, and destination whitelists. The bot can only operate within these bounds.
41
+ Everything can be done from code no dashboard needed. An agent can bootstrap its own vault end-to-end.
40
42
 
41
- 5. **Get the bot key** — Your agent needs the bot's private key to sign payment intents. Use the keystore file + passphrase (recommended) or export the raw private key for quick testing.
43
+ ```typescript
44
+ import {
45
+ AxonClient, deployVault, addBot, deposit,
46
+ createAxonPublicClient, createAxonWalletClient,
47
+ NATIVE_ETH, USDC, WINDOW, Chain,
48
+ } from '@axonfi/sdk';
49
+ import { parseUnits } from 'viem';
50
+ import { generatePrivateKey, privateKeyToAccount } from 'viem/accounts';
51
+
52
+ // ── 1. Owner wallet (funded with ETH for gas) ─────────────────────
53
+ const ownerKey = '0x...'; // or generate: generatePrivateKey()
54
+ const chainId = Chain.BaseSepolia;
55
+ const ownerWallet = createAxonWalletClient(ownerKey, chainId);
56
+ const publicClient = createAxonPublicClient(chainId, 'https://sepolia.base.org');
57
+
58
+ // ── 2. Deploy vault (on-chain tx, ~0.001 ETH gas) ─────────────────
59
+ const FACTORY = '0x...'; // AxonVaultFactory address for your chain
60
+ const vaultAddress = await deployVault(ownerWallet, publicClient, FACTORY);
61
+ console.log('Vault deployed:', vaultAddress);
62
+
63
+ // ── 3. Generate a bot keypair ──────────────────────────────────────
64
+ const botKey = generatePrivateKey();
65
+ const botAddress = privateKeyToAccount(botKey).address;
66
+
67
+ // ── 4. Accept Terms of Service (wallet signature, no gas) ─────────
68
+ const axon = new AxonClient({ vaultAddress, chainId, botPrivateKey: botKey });
69
+ await axon.acceptTos(ownerWallet, ownerWallet.account!.address);
70
+
71
+ // ── 5. Register the bot on the vault (on-chain tx, ~0.0005 ETH gas)
72
+ await addBot(ownerWallet, publicClient, vaultAddress, botAddress, {
73
+ maxPerTxAmount: parseUnits('100', 6), // $100 hard cap per tx
74
+ maxRebalanceAmount: 0n, // no rebalance cap
75
+ spendingLimits: [{
76
+ amount: parseUnits('1000', 6), // $1,000/day rolling limit
77
+ maxCount: 0n, // no tx count limit
78
+ windowSeconds: WINDOW.ONE_DAY,
79
+ }],
80
+ aiTriggerThreshold: parseUnits('50', 6), // AI scan above $50
81
+ requireAiVerification: false,
82
+ });
83
+
84
+ // ── 6. Deposit funds (on-chain tx, ~0.0005 ETH gas) ───────────────
85
+ // Option A: Deposit ETH (vault accepts native ETH directly)
86
+ await deposit(ownerWallet, publicClient, vaultAddress,
87
+ NATIVE_ETH, parseUnits('0.1', 18));
88
+
89
+ // Option B: Deposit USDC (SDK handles approve + deposit)
90
+ await deposit(ownerWallet, publicClient, vaultAddress,
91
+ USDC[chainId], parseUnits('500', 6));
92
+
93
+ // ── 7. Bot is ready — gasless from here ────────────────────────────
94
+ // Save botKey securely. The bot never needs ETH.
95
+ ```
96
+
97
+ ### What Needs Gas vs. What's Gasless
98
+
99
+ | Step | Who pays gas | Notes |
100
+ |------|-------------|-------|
101
+ | Deploy vault | Owner | ~0.001 ETH. One-time. |
102
+ | Accept ToS | Owner | Wallet signature only (no gas). |
103
+ | Register bot | Owner | ~0.0005 ETH. One per bot. |
104
+ | Configure bot | Owner | ~0.0003 ETH. Only when changing limits. |
105
+ | Deposit ETH | Depositor | Anyone can deposit. ETH sent directly. |
106
+ | Deposit ERC-20 | Depositor | Anyone can deposit. SDK handles approve + deposit. |
107
+ | **Pay** | **Free (relayer)** | **Bot signs EIP-712 intent. Axon pays gas.** |
108
+ | **Execute (DeFi)** | **Free (relayer)** | **Bot signs intent. Axon pays gas.** |
109
+ | **Swap (rebalance)** | **Free (relayer)** | **Bot signs intent. Axon pays gas.** |
110
+ | Pause/unpause | Owner | ~0.0002 ETH. Emergency only. |
111
+ | Withdraw | Owner | ~0.0003 ETH. Owner-only. |
112
+
113
+ **The key insight:** Setup operations (deploy, add bot, deposit) require gas from the owner. Once setup is complete, all bot operations (payments, DeFi, swaps) are gasless — the bot never needs ETH. The relayer pays all execution gas.
114
+
115
+ ### Depositing ETH
116
+
117
+ Vaults accept native ETH directly — no wrapping needed. You can start a vault with only ETH:
118
+
119
+ ```typescript
120
+ // Deploy vault + deposit ETH — no USDC needed
121
+ const vault = await deployVault(ownerWallet, publicClient, factory);
122
+ await addBot(ownerWallet, publicClient, vault, botAddress, config);
123
+ await deposit(ownerWallet, publicClient, vault, NATIVE_ETH, parseUnits('0.5', 18));
124
+
125
+ // Bot can now pay in any token — the relayer swaps ETH → USDC automatically
126
+ await axon.pay({ to: '0x...', token: 'USDC', amount: 10 });
127
+ ```
42
128
 
43
- The vault owner's wallet stays secure the bot key can only sign intents within the policies you configure, and can be revoked instantly from the dashboard.
129
+ When a bot pays in a token the vault doesn't hold directly (e.g., USDC when the vault only has ETH), the relayer automatically routes through a swap. The bot doesn't need to know or care what tokens are in the vault.
44
130
 
45
131
  ## Quick Start
46
132
 
package/dist/index.cjs CHANGED
@@ -2546,8 +2546,6 @@ var AxonVaultFactoryAbi = [
2546
2546
  "inputs": []
2547
2547
  }
2548
2548
  ];
2549
-
2550
- // src/vault.ts
2551
2549
  function getChain(chainId) {
2552
2550
  switch (chainId) {
2553
2551
  case 8453:
@@ -2751,6 +2749,79 @@ async function deployVault(walletClient, publicClient, factoryAddress) {
2751
2749
  }
2752
2750
  throw new Error("VaultDeployed event not found in transaction receipt");
2753
2751
  }
2752
+ async function addBot(walletClient, publicClient, vaultAddress, botAddress, config) {
2753
+ if (!walletClient.account) {
2754
+ throw new Error("walletClient has no account attached");
2755
+ }
2756
+ const hash = await walletClient.writeContract({
2757
+ address: vaultAddress,
2758
+ abi: AxonVaultAbi,
2759
+ functionName: "addBot",
2760
+ args: [botAddress, config],
2761
+ account: walletClient.account,
2762
+ chain: walletClient.chain ?? null
2763
+ });
2764
+ await publicClient.waitForTransactionReceipt({ hash });
2765
+ return hash;
2766
+ }
2767
+ async function updateBotConfig(walletClient, publicClient, vaultAddress, botAddress, config) {
2768
+ if (!walletClient.account) {
2769
+ throw new Error("walletClient has no account attached");
2770
+ }
2771
+ const hash = await walletClient.writeContract({
2772
+ address: vaultAddress,
2773
+ abi: AxonVaultAbi,
2774
+ functionName: "updateBotConfig",
2775
+ args: [botAddress, config],
2776
+ account: walletClient.account,
2777
+ chain: walletClient.chain ?? null
2778
+ });
2779
+ await publicClient.waitForTransactionReceipt({ hash });
2780
+ return hash;
2781
+ }
2782
+ async function removeBot(walletClient, publicClient, vaultAddress, botAddress) {
2783
+ if (!walletClient.account) {
2784
+ throw new Error("walletClient has no account attached");
2785
+ }
2786
+ const hash = await walletClient.writeContract({
2787
+ address: vaultAddress,
2788
+ abi: AxonVaultAbi,
2789
+ functionName: "removeBot",
2790
+ args: [botAddress],
2791
+ account: walletClient.account,
2792
+ chain: walletClient.chain ?? null
2793
+ });
2794
+ await publicClient.waitForTransactionReceipt({ hash });
2795
+ return hash;
2796
+ }
2797
+ async function deposit(walletClient, publicClient, vaultAddress, token, amount, ref = "0x0000000000000000000000000000000000000000000000000000000000000000") {
2798
+ if (!walletClient.account) {
2799
+ throw new Error("walletClient has no account attached");
2800
+ }
2801
+ const isEth = token.toLowerCase() === NATIVE_ETH.toLowerCase();
2802
+ if (!isEth) {
2803
+ const approveTx = await walletClient.writeContract({
2804
+ address: token,
2805
+ abi: viem.erc20Abi,
2806
+ functionName: "approve",
2807
+ args: [vaultAddress, amount],
2808
+ account: walletClient.account,
2809
+ chain: walletClient.chain ?? null
2810
+ });
2811
+ await publicClient.waitForTransactionReceipt({ hash: approveTx });
2812
+ }
2813
+ const hash = await walletClient.writeContract({
2814
+ address: vaultAddress,
2815
+ abi: AxonVaultAbi,
2816
+ functionName: "deposit",
2817
+ args: [token, amount, ref],
2818
+ account: walletClient.account,
2819
+ chain: walletClient.chain ?? null,
2820
+ ...isEth ? { value: amount } : {}
2821
+ });
2822
+ await publicClient.waitForTransactionReceipt({ hash });
2823
+ return hash;
2824
+ }
2754
2825
 
2755
2826
  // src/tokens.ts
2756
2827
  var Token = /* @__PURE__ */ ((Token2) => {
@@ -4402,10 +4473,12 @@ exports.USDC_EIP712_DOMAIN = USDC_EIP712_DOMAIN;
4402
4473
  exports.WINDOW = WINDOW;
4403
4474
  exports.WITNESS_TYPE_STRING = WITNESS_TYPE_STRING;
4404
4475
  exports.X402_PROXY_ADDRESS = X402_PROXY_ADDRESS;
4476
+ exports.addBot = addBot;
4405
4477
  exports.createAxonPublicClient = createAxonPublicClient;
4406
4478
  exports.createAxonWalletClient = createAxonWalletClient;
4407
4479
  exports.decryptKeystore = decryptKeystore;
4408
4480
  exports.deployVault = deployVault;
4481
+ exports.deposit = deposit;
4409
4482
  exports.encodeRef = encodeRef;
4410
4483
  exports.encryptKeystore = encryptKeystore;
4411
4484
  exports.extractX402Metadata = extractX402Metadata;
@@ -4432,6 +4505,7 @@ exports.parseChainId = parseChainId;
4432
4505
  exports.parsePaymentRequired = parsePaymentRequired;
4433
4506
  exports.randomNonce = randomNonce;
4434
4507
  exports.randomPermit2Nonce = randomPermit2Nonce;
4508
+ exports.removeBot = removeBot;
4435
4509
  exports.resolveToken = resolveToken;
4436
4510
  exports.resolveTokenDecimals = resolveTokenDecimals;
4437
4511
  exports.signExecuteIntent = signExecuteIntent;
@@ -4439,5 +4513,6 @@ exports.signPayment = signPayment;
4439
4513
  exports.signPermit2WitnessTransfer = signPermit2WitnessTransfer;
4440
4514
  exports.signSwapIntent = signSwapIntent;
4441
4515
  exports.signTransferWithAuthorization = signTransferWithAuthorization;
4516
+ exports.updateBotConfig = updateBotConfig;
4442
4517
  //# sourceMappingURL=index.cjs.map
4443
4518
  //# sourceMappingURL=index.cjs.map