@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 +7 -6
- package/SDK.md +18 -5
- package/dist/cli/index.cjs +227 -168
- package/dist/index.cjs +28 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +38 -1
- package/dist/index.d.ts +38 -1
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/veil/SKILL.md +6 -4
- package/skills/veil/reference.md +5 -5
- package/src/abi.ts +8 -0
- package/src/balance.ts +48 -0
- package/src/cli/commands/deposit.ts +61 -15
- package/src/index.ts +1 -0
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.
|
|
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
|
|
149
|
-
veil deposit USDC 100 # 100 USDC lands in pool
|
|
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%
|
|
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
|
|
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
|
package/dist/cli/index.cjs
CHANGED
|
@@ -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;
|