@veil-cash/sdk 0.6.2 → 0.6.3

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
@@ -93,7 +93,7 @@ veil subaccount recover --slot 0 --asset usdc --to 0xRecipientAddress --amount 2
93
93
 
94
94
  # 9. Use JSON or unsigned modes when you need automation
95
95
  veil status --json
96
- veil deposit ETH 0.1 --unsigned
96
+ veil deposit ETH 0.1 --unsigned --address 0x...
97
97
  veil subaccount status --slot 0 --json
98
98
  ```
99
99
 
@@ -142,13 +142,14 @@ SIGNER_ADDRESS=0x... veil register --unsigned
142
142
 
143
143
  In `--unsigned` mode, `--address` is optional when `SIGNER_ADDRESS` is set. `veil register --force` checks on-chain state first and emits a `changeDepositKey` payload only if the address is already registered; otherwise it emits a normal `register` payload.
144
144
 
145
- Deposit ETH or USDC into Veil. The amount you specify is the **net** amount that arrives in your Veil balance. The 0.3% protocol fee is calculated on-chain and added automatically:
145
+ Deposit ETH or USDC into Veil. The amount you specify is the **net** amount that arrives in your Veil balance. A 0.3% protocol fee is normally added on top, but each address gets free daily deposits (fee waived). The CLI checks automatically:
146
146
 
147
147
  ```bash
148
- veil deposit ETH 0.1 # 0.1 ETH lands in pool, ~0.1003 ETH sent
149
- veil deposit USDC 100 # 100 USDC lands in pool, ~100.30 USDC sent
148
+ veil deposit ETH 0.1 # 0.1 ETH lands in pool (free or ~0.1003 ETH sent)
149
+ veil deposit USDC 100 # 100 USDC lands in pool (free or ~100.30 USDC sent)
150
150
  veil deposit ETH 0.1 --json
151
- veil deposit ETH 0.1 --unsigned
151
+ veil deposit ETH 0.1 --unsigned --address 0x...
152
+ SIGNER_ADDRESS=0x... veil deposit ETH 0.1 --unsigned
152
153
  ```
153
154
 
154
155
  ### Balances
@@ -295,7 +296,7 @@ The CLI is the main entrypoint for most users. If you are integrating Veil progr
295
296
  2. **Derive Keypair**: Run `veil init` to derive and save your Veil keypair
296
297
  3. **Register**: Run `veil register` to link your deposit key on-chain (one-time)
297
298
  4. **Check Status**: Run `veil status` to verify your setup
298
- 5. **Deposit**: Run `veil deposit <asset> <amount>` — the amount is what lands in your balance (e.g., `veil deposit ETH 0.1` deposits 0.1 ETH; the 0.3% fee is added automatically)
299
+ 5. **Deposit**: Run `veil deposit <asset> <amount>` — the amount is what lands in your balance (e.g., `veil deposit ETH 0.1` deposits 0.1 ETH; the fee is waived if you have daily free deposits remaining, otherwise 0.3% is added automatically)
299
300
  6. **Wait**: The Veil deposit engine processes your deposit
300
301
  7. **Done**: Your deposit is accepted into the privacy pool
301
302
 
package/SDK.md CHANGED
@@ -109,6 +109,11 @@ keypair.privkey; // '0x...'
109
109
 
110
110
  ### Transaction Builders
111
111
 
112
+ > **Daily free deposits**: Each address gets a configurable number of fee-free
113
+ > deposits per UTC day. The CLI handles this automatically. If you use the
114
+ > builders programmatically, call `getDailyFreeRemaining()` first — when the
115
+ > user has free slots, pass the net amount directly (no fee markup needed).
116
+
112
117
  ```typescript
113
118
  import {
114
119
  buildRegisterTx, buildChangeDepositKeyTx, buildDepositETHTx, buildDepositTx,
@@ -182,7 +187,7 @@ const mergeResult = await mergeUtxos({
182
187
  Balance functions accept an optional `pool` parameter (`'eth'` | `'usdc'`), defaulting to `'eth'`.
183
188
 
184
189
  ```typescript
185
- import { getQueueBalance, getPrivateBalance } from '@veil-cash/sdk';
190
+ import { getQueueBalance, getPrivateBalance, getDailyFreeRemaining } from '@veil-cash/sdk';
186
191
 
187
192
  // Check ETH queue balance (pending deposits)
188
193
  const queueBalance = await getQueueBalance({
@@ -195,6 +200,13 @@ const privateBalance = await getPrivateBalance({
195
200
  keypair,
196
201
  pool: 'usdc',
197
202
  });
203
+
204
+ // Check how many fee-free deposits the user has left today
205
+ const freeRemaining = await getDailyFreeRemaining({
206
+ address: '0x...',
207
+ pool: 'eth', // default
208
+ });
209
+ // freeRemaining: number — 0 when all free slots are used or the feature is disabled
198
210
  ```
199
211
 
200
212
  ### Subaccounts
@@ -291,8 +303,8 @@ veil init --json
291
303
 
292
304
  # Get unsigned transaction payloads for agent signing
293
305
  SIGNER_ADDRESS=0x... veil register --unsigned
294
- veil deposit ETH 0.1 --unsigned
295
- veil deposit USDC 100 --unsigned # Outputs approve + deposit payloads
306
+ SIGNER_ADDRESS=0x... veil deposit ETH 0.1 --unsigned
307
+ veil deposit USDC 100 --unsigned --address 0x... # Outputs approve + deposit payloads
296
308
 
297
309
  # Request machine-readable status or balances
298
310
  veil balance --json
@@ -344,12 +356,13 @@ Use `--unsigned` to get signer-compatible transaction payloads:
344
356
  ```bash
345
357
  SIGNER_ADDRESS=0x... veil register --unsigned
346
358
  SIGNER_ADDRESS=0x... veil register --unsigned --force
347
- veil deposit ETH 0.1 --unsigned
359
+ SIGNER_ADDRESS=0x... veil deposit ETH 0.1 --unsigned
360
+ veil deposit ETH 0.1 --unsigned --address 0x...
348
361
  # {"to":"0x...","data":"0x...","value":"100000000000000000","chainId":8453}
349
362
  ```
350
363
 
351
364
  The `--unsigned` flag outputs a standard `{to, data, value, chainId}` payload compatible with any signer that accepts arbitrary transactions.
352
- When `SIGNER_ADDRESS` is set, `veil register --unsigned` no longer requires the `--address` flag.
365
+ When `SIGNER_ADDRESS` is set, `veil register --unsigned` and `veil deposit --unsigned` no longer require the `--address` flag.
353
366
  For `veil register --unsigned --force`, the CLI checks on-chain registration state first and emits `changeDepositKey` only when the address is already registered; otherwise it falls back to `register`.
354
367
 
355
368
  ### Programmatic SDK Usage
@@ -4203,6 +4203,14 @@ var QUEUE_ABI = [
4203
4203
  outputs: [{ name: "count", type: "uint256" }],
4204
4204
  stateMutability: "view",
4205
4205
  type: "function"
4206
+ },
4207
+ // Get remaining daily free deposits for an address (V3+)
4208
+ {
4209
+ inputs: [{ name: "_depositor", type: "address" }],
4210
+ name: "getDailyFreeRemaining",
4211
+ outputs: [{ name: "remaining", type: "uint256" }],
4212
+ stateMutability: "view",
4213
+ type: "function"
4206
4214
  }
4207
4215
  ];
4208
4216
  var POOL_ABI = [
@@ -5784,174 +5792,6 @@ function createRegisterCommand() {
5784
5792
  });
5785
5793
  return register;
5786
5794
  }
5787
- var MINIMUM_NET = {
5788
- ETH: 0.01,
5789
- USDC: 10
5790
- };
5791
- async function getGrossAmount(netWei, rpcUrl) {
5792
- const publicClient = viem.createPublicClient({
5793
- chain: chains.base,
5794
- transport: viem.http(rpcUrl)
5795
- });
5796
- const grossWei = await publicClient.readContract({
5797
- address: getAddresses().entry,
5798
- abi: ENTRY_ABI,
5799
- functionName: "getDepositAmountWithFee",
5800
- args: [netWei]
5801
- });
5802
- return { grossWei, feeWei: grossWei - netWei };
5803
- }
5804
- var SUPPORTED_ASSETS = ["ETH", "USDC"];
5805
- function createDepositCommand() {
5806
- const deposit = new Command("deposit").description("Deposit ETH or USDC into Veil").argument("<asset>", "Asset to deposit (ETH or USDC)").argument("<amount>", "Amount to deposit \u2014 this is what arrives in your Veil balance").option("--unsigned", "Output unsigned transaction payload instead of sending").option("--json", "Output as JSON").addHelpText("after", `
5807
- The amount you specify is the net amount that lands in your Veil balance.
5808
- The 0.3% protocol fee is automatically added on top.
5809
-
5810
- Examples:
5811
- veil deposit ETH 0.1 # deposits 0.1 ETH (sends ~0.1003 ETH)
5812
- veil deposit USDC 100 # deposits 100 USDC (sends ~100.30 USDC)
5813
- veil deposit ETH 0.1 --unsigned
5814
- veil deposit ETH 0.1 --json
5815
- `).action(async (asset, amount, options) => {
5816
- try {
5817
- const assetUpper = asset.toUpperCase();
5818
- if (!SUPPORTED_ASSETS.includes(assetUpper)) {
5819
- throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported asset: ${asset}. Supported: ${SUPPORTED_ASSETS.join(", ")}`);
5820
- }
5821
- const amountNum = parseFloat(amount);
5822
- const minimumNet = MINIMUM_NET[assetUpper];
5823
- if (amountNum < minimumNet) {
5824
- throw new CLIError(
5825
- ErrorCode.INVALID_AMOUNT,
5826
- `Minimum deposit is ${minimumNet} ${assetUpper}.`
5827
- );
5828
- }
5829
- const rpcUrl = process.env.RPC_URL;
5830
- const poolConfig = POOL_CONFIG[assetUpper.toLowerCase()];
5831
- const netWei = assetUpper === "ETH" ? viem.parseEther(amount) : viem.parseUnits(amount, poolConfig.decimals);
5832
- const progress = createProgressReporter();
5833
- progress("Calculating fee...");
5834
- const { grossWei, feeWei } = await getGrossAmount(netWei, rpcUrl);
5835
- const grossStr = assetUpper === "ETH" ? viem.formatEther(grossWei) : viem.formatUnits(grossWei, poolConfig.decimals);
5836
- const feeStr = assetUpper === "ETH" ? viem.formatEther(feeWei) : viem.formatUnits(feeWei, poolConfig.decimals);
5837
- const depositKey = process.env.DEPOSIT_KEY;
5838
- if (!depositKey) {
5839
- throw new CLIError(ErrorCode.DEPOSIT_KEY_MISSING, 'DEPOSIT_KEY not set. Run "veil init" first.');
5840
- }
5841
- progress("Building transaction...");
5842
- let tx;
5843
- let approveTx = null;
5844
- if (assetUpper === "USDC") {
5845
- approveTx = buildApproveUSDCTx({ amount: grossStr });
5846
- tx = buildDepositUSDCTx({ depositKey, amount: grossStr });
5847
- } else {
5848
- tx = buildDepositETHTx({ depositKey, amount: grossStr });
5849
- }
5850
- if (options.unsigned) {
5851
- clearProgress();
5852
- const payloads = [];
5853
- if (approveTx) {
5854
- payloads.push({
5855
- step: "approve",
5856
- to: approveTx.to,
5857
- data: approveTx.data,
5858
- value: "0",
5859
- chainId: 8453
5860
- });
5861
- }
5862
- payloads.push({
5863
- step: "deposit",
5864
- to: tx.to,
5865
- data: tx.data,
5866
- value: tx.value ? tx.value.toString() : "0",
5867
- chainId: 8453
5868
- });
5869
- printJson(payloads.length === 1 ? payloads[0] : payloads);
5870
- return;
5871
- }
5872
- const config = getConfig(options);
5873
- const address = getAddress(config.privateKey);
5874
- if (assetUpper === "ETH") {
5875
- progress("Checking balance...");
5876
- const balance = await getBalance(address, config.rpcUrl);
5877
- if (balance < grossWei) {
5878
- clearProgress();
5879
- throw new CLIError(
5880
- ErrorCode.INSUFFICIENT_BALANCE,
5881
- `Insufficient ETH balance. Have: ${viem.formatEther(balance)} ETH, Need: ${grossStr} ETH (${amount} + fee)`
5882
- );
5883
- }
5884
- }
5885
- if (approveTx) {
5886
- progress(`Approving ${assetUpper}...`);
5887
- const approvalResult = await sendTransaction(config, approveTx);
5888
- if (assetUpper === "USDC") {
5889
- const publicClient = viem.createPublicClient({
5890
- chain: chains.base,
5891
- transport: viem.http(config.rpcUrl)
5892
- });
5893
- const addresses = getAddresses();
5894
- let allowance = await publicClient.readContract({
5895
- address: getAddresses().usdcToken,
5896
- abi: ERC20_ABI,
5897
- functionName: "allowance",
5898
- args: [address, addresses.entry]
5899
- });
5900
- for (let confirmations = 2; allowance < grossWei && confirmations <= 3; confirmations++) {
5901
- await publicClient.waitForTransactionReceipt({
5902
- hash: approvalResult.hash,
5903
- confirmations
5904
- });
5905
- allowance = await publicClient.readContract({
5906
- address: addresses.usdcToken,
5907
- abi: ERC20_ABI,
5908
- functionName: "allowance",
5909
- args: [address, addresses.entry]
5910
- });
5911
- }
5912
- if (allowance < grossWei) {
5913
- throw new CLIError(
5914
- ErrorCode.CONTRACT_ERROR,
5915
- `USDC approval is not yet visible on RPC after confirmation. Allowance ${allowance.toString()} < required ${grossWei.toString()}.`
5916
- );
5917
- }
5918
- }
5919
- }
5920
- progress("Sending deposit transaction...");
5921
- const result = await sendTransaction(config, tx);
5922
- progress("Confirming...");
5923
- clearProgress();
5924
- const output = {
5925
- success: result.receipt.status === "success",
5926
- hash: result.hash,
5927
- asset: assetUpper,
5928
- amount,
5929
- fee: feeStr,
5930
- totalSent: grossStr,
5931
- blockNumber: result.receipt.blockNumber.toString()
5932
- };
5933
- if (options.json) {
5934
- printJson(output);
5935
- return;
5936
- }
5937
- printHeader("Deposit Submitted");
5938
- printFields([
5939
- { label: "Asset", value: assetUpper },
5940
- { label: "Amount", value: `${amount} ${assetUpper}` },
5941
- { label: "Fee", value: `${feeStr} ${assetUpper} (0.3%)` },
5942
- { label: "Total sent", value: `${grossStr} ${assetUpper}` },
5943
- { label: "From", value: address },
5944
- { label: "Transaction", value: txUrl(result.hash) },
5945
- { label: "Block", value: result.receipt.blockNumber }
5946
- ]);
5947
- printLine();
5948
- } catch (error) {
5949
- clearProgress();
5950
- handleCLIError(error);
5951
- }
5952
- });
5953
- return deposit;
5954
- }
5955
5795
 
5956
5796
  // src/utxo.ts
5957
5797
  var Utxo = class _Utxo {
@@ -6084,6 +5924,25 @@ async function getQueueBalance(options) {
6084
5924
  pendingCount: pendingDeposits.length
6085
5925
  };
6086
5926
  }
5927
+ async function getDailyFreeRemaining(options) {
5928
+ const { address, pool = "eth", rpcUrl } = options;
5929
+ const queueAddress = getQueueAddress(pool);
5930
+ const publicClient = viem.createPublicClient({
5931
+ chain: chains.base,
5932
+ transport: viem.http(rpcUrl)
5933
+ });
5934
+ try {
5935
+ const remaining = await publicClient.readContract({
5936
+ address: queueAddress,
5937
+ abi: QUEUE_ABI,
5938
+ functionName: "getDailyFreeRemaining",
5939
+ args: [address]
5940
+ });
5941
+ return Number(remaining);
5942
+ } catch {
5943
+ return 0;
5944
+ }
5945
+ }
6087
5946
  async function getPrivateBalance(options) {
6088
5947
  const { keypair, pool = "eth", rpcUrl, onProgress } = options;
6089
5948
  const poolAddress = getPoolAddress(pool);
@@ -6177,6 +6036,206 @@ async function getPrivateBalance(options) {
6177
6036
  utxos: utxoInfos
6178
6037
  };
6179
6038
  }
6039
+ var MINIMUM_NET = {
6040
+ ETH: 0.01,
6041
+ USDC: 10
6042
+ };
6043
+ async function getGrossAmount(netWei, depositor, pool, rpcUrl) {
6044
+ const freeRemaining = await getDailyFreeRemaining({ address: depositor, pool, rpcUrl });
6045
+ if (freeRemaining > 0) {
6046
+ return { grossWei: netWei, feeWei: 0n, dailyFreeUsed: true, dailyFreeRemaining: freeRemaining - 1 };
6047
+ }
6048
+ const publicClient = viem.createPublicClient({
6049
+ chain: chains.base,
6050
+ transport: viem.http(rpcUrl)
6051
+ });
6052
+ const grossWei = await publicClient.readContract({
6053
+ address: getAddresses().entry,
6054
+ abi: ENTRY_ABI,
6055
+ functionName: "getDepositAmountWithFee",
6056
+ args: [netWei]
6057
+ });
6058
+ return { grossWei, feeWei: grossWei - netWei, dailyFreeUsed: false, dailyFreeRemaining: 0 };
6059
+ }
6060
+ var SUPPORTED_ASSETS = ["ETH", "USDC"];
6061
+ function createDepositCommand() {
6062
+ const deposit = new Command("deposit").description("Deposit ETH or USDC into Veil").argument("<asset>", "Asset to deposit (ETH or USDC)").argument("<amount>", "Amount to deposit \u2014 this is what arrives in your Veil balance").option("--address <address>", "Signer address (required in --unsigned mode unless SIGNER_ADDRESS or WALLET_KEY is set)").option("--unsigned", "Output unsigned transaction payload instead of sending").option("--json", "Output as JSON").addHelpText("after", `
6063
+ The amount you specify is the net amount that lands in your Veil balance.
6064
+ A 0.3% protocol fee is normally added on top, but each address gets
6065
+ free daily deposits (fee waived). The CLI checks automatically.
6066
+
6067
+ Examples:
6068
+ veil deposit ETH 0.1 # deposits 0.1 ETH (free or ~0.1003 ETH)
6069
+ veil deposit USDC 100 # deposits 100 USDC (free or ~100.30 USDC)
6070
+ veil deposit ETH 0.1 --unsigned --address 0x...
6071
+ SIGNER_ADDRESS=0x... veil deposit ETH 0.1 --unsigned
6072
+ veil deposit ETH 0.1 --json
6073
+ `).action(async (asset, amount, options) => {
6074
+ try {
6075
+ const assetUpper = asset.toUpperCase();
6076
+ if (!SUPPORTED_ASSETS.includes(assetUpper)) {
6077
+ throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported asset: ${asset}. Supported: ${SUPPORTED_ASSETS.join(", ")}`);
6078
+ }
6079
+ const amountNum = parseFloat(amount);
6080
+ const minimumNet = MINIMUM_NET[assetUpper];
6081
+ if (amountNum < minimumNet) {
6082
+ throw new CLIError(
6083
+ ErrorCode.INVALID_AMOUNT,
6084
+ `Minimum deposit is ${minimumNet} ${assetUpper}.`
6085
+ );
6086
+ }
6087
+ const rpcUrl = process.env.RPC_URL;
6088
+ const pool = assetUpper.toLowerCase();
6089
+ const poolConfig = POOL_CONFIG[pool];
6090
+ const netWei = assetUpper === "ETH" ? viem.parseEther(amount) : viem.parseUnits(amount, poolConfig.decimals);
6091
+ const progress = createProgressReporter();
6092
+ let config = null;
6093
+ let address;
6094
+ let feeRpcUrl = rpcUrl;
6095
+ if (options.unsigned) {
6096
+ const resolved = resolveAddress({ address: options.address }, { required: true });
6097
+ if (!resolved) {
6098
+ throw new CLIError(
6099
+ ErrorCode.WALLET_KEY_MISSING,
6100
+ "Must provide --address, set SIGNER_ADDRESS, or set WALLET_KEY env."
6101
+ );
6102
+ }
6103
+ address = resolved.address;
6104
+ } else {
6105
+ config = getConfig(options);
6106
+ address = getAddress(config.privateKey);
6107
+ feeRpcUrl = config.rpcUrl;
6108
+ }
6109
+ progress("Checking deposit fee...");
6110
+ const { grossWei, feeWei, dailyFreeUsed, dailyFreeRemaining } = await getGrossAmount(
6111
+ netWei,
6112
+ address,
6113
+ pool,
6114
+ feeRpcUrl
6115
+ );
6116
+ const grossStr = assetUpper === "ETH" ? viem.formatEther(grossWei) : viem.formatUnits(grossWei, poolConfig.decimals);
6117
+ const feeStr = assetUpper === "ETH" ? viem.formatEther(feeWei) : viem.formatUnits(feeWei, poolConfig.decimals);
6118
+ const depositKey = process.env.DEPOSIT_KEY;
6119
+ if (!depositKey) {
6120
+ throw new CLIError(ErrorCode.DEPOSIT_KEY_MISSING, 'DEPOSIT_KEY not set. Run "veil init" first.');
6121
+ }
6122
+ progress("Building transaction...");
6123
+ let tx;
6124
+ let approveTx = null;
6125
+ if (assetUpper === "USDC") {
6126
+ approveTx = buildApproveUSDCTx({ amount: grossStr });
6127
+ tx = buildDepositUSDCTx({ depositKey, amount: grossStr });
6128
+ } else {
6129
+ tx = buildDepositETHTx({ depositKey, amount: grossStr });
6130
+ }
6131
+ if (options.unsigned) {
6132
+ clearProgress();
6133
+ const payloads = [];
6134
+ if (approveTx) {
6135
+ payloads.push({
6136
+ step: "approve",
6137
+ to: approveTx.to,
6138
+ data: approveTx.data,
6139
+ value: "0",
6140
+ chainId: 8453
6141
+ });
6142
+ }
6143
+ payloads.push({
6144
+ step: "deposit",
6145
+ to: tx.to,
6146
+ data: tx.data,
6147
+ value: tx.value ? tx.value.toString() : "0",
6148
+ chainId: 8453
6149
+ });
6150
+ printJson(payloads.length === 1 ? payloads[0] : payloads);
6151
+ return;
6152
+ }
6153
+ if (!config) {
6154
+ throw new CLIError(ErrorCode.WALLET_KEY_MISSING, "WALLET_KEY env var required. Set it before running this command.");
6155
+ }
6156
+ if (assetUpper === "ETH") {
6157
+ progress("Checking balance...");
6158
+ const balance = await getBalance(address, config.rpcUrl);
6159
+ if (balance < grossWei) {
6160
+ clearProgress();
6161
+ throw new CLIError(
6162
+ ErrorCode.INSUFFICIENT_BALANCE,
6163
+ `Insufficient ETH balance. Have: ${viem.formatEther(balance)} ETH, Need: ${grossStr} ETH (${amount} + fee)`
6164
+ );
6165
+ }
6166
+ }
6167
+ if (approveTx) {
6168
+ progress(`Approving ${assetUpper}...`);
6169
+ const approvalResult = await sendTransaction(config, approveTx);
6170
+ if (assetUpper === "USDC") {
6171
+ const publicClient = viem.createPublicClient({
6172
+ chain: chains.base,
6173
+ transport: viem.http(config.rpcUrl)
6174
+ });
6175
+ const addresses = getAddresses();
6176
+ let allowance = await publicClient.readContract({
6177
+ address: getAddresses().usdcToken,
6178
+ abi: ERC20_ABI,
6179
+ functionName: "allowance",
6180
+ args: [address, addresses.entry]
6181
+ });
6182
+ for (let confirmations = 2; allowance < grossWei && confirmations <= 3; confirmations++) {
6183
+ await publicClient.waitForTransactionReceipt({
6184
+ hash: approvalResult.hash,
6185
+ confirmations
6186
+ });
6187
+ allowance = await publicClient.readContract({
6188
+ address: addresses.usdcToken,
6189
+ abi: ERC20_ABI,
6190
+ functionName: "allowance",
6191
+ args: [address, addresses.entry]
6192
+ });
6193
+ }
6194
+ if (allowance < grossWei) {
6195
+ throw new CLIError(
6196
+ ErrorCode.CONTRACT_ERROR,
6197
+ `USDC approval is not yet visible on RPC after confirmation. Allowance ${allowance.toString()} < required ${grossWei.toString()}.`
6198
+ );
6199
+ }
6200
+ }
6201
+ }
6202
+ progress("Sending deposit transaction...");
6203
+ const result = await sendTransaction(config, tx);
6204
+ progress("Confirming...");
6205
+ clearProgress();
6206
+ const output = {
6207
+ success: result.receipt.status === "success",
6208
+ hash: result.hash,
6209
+ asset: assetUpper,
6210
+ amount,
6211
+ fee: feeStr,
6212
+ dailyFreeUsed,
6213
+ totalSent: grossStr,
6214
+ blockNumber: result.receipt.blockNumber.toString()
6215
+ };
6216
+ if (options.json) {
6217
+ printJson(output);
6218
+ return;
6219
+ }
6220
+ const feeLabel = dailyFreeUsed ? `0 ${assetUpper} (free \u2014 ${dailyFreeRemaining} remaining today)` : `${feeStr} ${assetUpper} (0.3%)`;
6221
+ printHeader("Deposit Submitted");
6222
+ printFields([
6223
+ { label: "Asset", value: assetUpper },
6224
+ { label: "Amount", value: `${amount} ${assetUpper}` },
6225
+ { label: "Fee", value: feeLabel },
6226
+ { label: "Total sent", value: `${grossStr} ${assetUpper}` },
6227
+ { label: "From", value: address },
6228
+ { label: "Transaction", value: txUrl(result.hash) },
6229
+ { label: "Block", value: result.receipt.blockNumber }
6230
+ ]);
6231
+ printLine();
6232
+ } catch (error) {
6233
+ clearProgress();
6234
+ handleCLIError(error);
6235
+ }
6236
+ });
6237
+ return deposit;
6238
+ }
6180
6239
 
6181
6240
  // src/cli/commands/private-balance.ts
6182
6241
  var SUPPORTED_POOLS = ["eth", "usdc"];
package/dist/index.cjs CHANGED
@@ -625,6 +625,14 @@ var QUEUE_ABI = [
625
625
  outputs: [{ name: "count", type: "uint256" }],
626
626
  stateMutability: "view",
627
627
  type: "function"
628
+ },
629
+ // Get remaining daily free deposits for an address (V3+)
630
+ {
631
+ inputs: [{ name: "_depositor", type: "address" }],
632
+ name: "getDailyFreeRemaining",
633
+ outputs: [{ name: "remaining", type: "uint256" }],
634
+ stateMutability: "view",
635
+ type: "function"
628
636
  }
629
637
  ];
630
638
  var POOL_ABI = [
@@ -1342,6 +1350,25 @@ async function getQueueBalance(options) {
1342
1350
  pendingCount: pendingDeposits.length
1343
1351
  };
1344
1352
  }
1353
+ async function getDailyFreeRemaining(options) {
1354
+ const { address, pool = "eth", rpcUrl } = options;
1355
+ const queueAddress = getQueueAddress(pool);
1356
+ const publicClient = viem.createPublicClient({
1357
+ chain: chains.base,
1358
+ transport: viem.http(rpcUrl)
1359
+ });
1360
+ try {
1361
+ const remaining = await publicClient.readContract({
1362
+ address: queueAddress,
1363
+ abi: QUEUE_ABI,
1364
+ functionName: "getDailyFreeRemaining",
1365
+ args: [address]
1366
+ });
1367
+ return Number(remaining);
1368
+ } catch {
1369
+ return 0;
1370
+ }
1371
+ }
1345
1372
  async function getPrivateBalance(options) {
1346
1373
  const { keypair, pool = "eth", rpcUrl, onProgress } = options;
1347
1374
  const poolAddress = getPoolAddress(pool);
@@ -2720,6 +2747,7 @@ exports.deriveSubaccountSalt = deriveSubaccountSalt;
2720
2747
  exports.deriveSubaccountSlot = deriveSubaccountSlot;
2721
2748
  exports.findNextSubaccountWithdrawNonce = findNextSubaccountWithdrawNonce;
2722
2749
  exports.getAddresses = getAddresses;
2750
+ exports.getDailyFreeRemaining = getDailyFreeRemaining;
2723
2751
  exports.getExtDataHash = getExtDataHash;
2724
2752
  exports.getForwarderFactoryAddress = getForwarderFactoryAddress;
2725
2753
  exports.getMerklePath = getMerklePath;