@veil-cash/sdk 0.2.0 → 0.4.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 +177 -44
- package/dist/cli/index.cjs +453 -129
- package/dist/index.cjs +155 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +117 -1
- package/dist/index.d.ts +117 -1
- package/dist/index.js +153 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/abi.ts +18 -0
- package/src/addresses.ts +29 -1
- package/src/balance.ts +22 -15
- package/src/cli/commands/balance.ts +114 -54
- package/src/cli/commands/deposit.ts +72 -33
- package/src/cli/commands/init.ts +52 -8
- package/src/cli/commands/private-balance.ts +6 -1
- package/src/cli/commands/queue-balance.ts +5 -1
- package/src/cli/commands/register.ts +47 -12
- package/src/cli/commands/transfer.ts +23 -10
- package/src/cli/commands/withdraw.ts +13 -5
- package/src/cli/index.ts +1 -1
- package/src/deposit.ts +36 -0
- package/src/index.ts +6 -2
- package/src/keypair.ts +79 -0
- package/src/transfer.ts +14 -11
- package/src/types.ts +4 -0
- package/src/withdraw.ts +7 -6
package/dist/cli/index.cjs
CHANGED
|
@@ -5,9 +5,9 @@ var readline = require('readline');
|
|
|
5
5
|
var fs = require('fs');
|
|
6
6
|
var path = require('path');
|
|
7
7
|
var ethers = require('ethers');
|
|
8
|
+
var accounts = require('viem/accounts');
|
|
8
9
|
var crypto = require('crypto');
|
|
9
10
|
var viem = require('viem');
|
|
10
|
-
var accounts = require('viem/accounts');
|
|
11
11
|
var chains = require('viem/chains');
|
|
12
12
|
var MerkleTree = require('fixed-merkle-tree-legacy');
|
|
13
13
|
var snarkjs = require('snarkjs');
|
|
@@ -3996,6 +3996,7 @@ function shuffle(array) {
|
|
|
3996
3996
|
}
|
|
3997
3997
|
|
|
3998
3998
|
// src/keypair.ts
|
|
3999
|
+
var VEIL_SIGNED_MESSAGE = "Sign this message to create your Veil Wallet private key. This will be used to decrypt your balances. Ensure you are signing this message on the Veil Cash website.";
|
|
3999
4000
|
var ethSigUtil = __require("eth-sig-util");
|
|
4000
4001
|
function packEncryptedMessage(encryptedMessage) {
|
|
4001
4002
|
const nonceBuf = Buffer.from(encryptedMessage.nonce, "base64");
|
|
@@ -4075,6 +4076,69 @@ var Keypair = class _Keypair {
|
|
|
4075
4076
|
encryptionKey: Buffer.from(str.slice(64, 128), "hex").toString("base64")
|
|
4076
4077
|
});
|
|
4077
4078
|
}
|
|
4079
|
+
/**
|
|
4080
|
+
* Derive a Keypair from an EIP-191 personal_sign signature.
|
|
4081
|
+
* The private key is keccak256(signature) -- matching the frontend derivation.
|
|
4082
|
+
*
|
|
4083
|
+
* @param signature - Raw ECDSA signature (0x-prefixed, 132 hex chars)
|
|
4084
|
+
* @returns Keypair derived from the signature
|
|
4085
|
+
*
|
|
4086
|
+
* @example
|
|
4087
|
+
* ```typescript
|
|
4088
|
+
* const keypair = Keypair.fromSignature(signature);
|
|
4089
|
+
* ```
|
|
4090
|
+
*/
|
|
4091
|
+
static fromSignature(signature) {
|
|
4092
|
+
const privkey = ethers.ethers.keccak256(signature);
|
|
4093
|
+
return new _Keypair(privkey);
|
|
4094
|
+
}
|
|
4095
|
+
/**
|
|
4096
|
+
* Derive a Keypair from an Ethereum wallet private key.
|
|
4097
|
+
* Signs VEIL_SIGNED_MESSAGE with the wallet, then derives via keccak256(signature).
|
|
4098
|
+
* Produces the same keypair as the frontend for the same wallet.
|
|
4099
|
+
*
|
|
4100
|
+
* @param walletPrivateKey - Ethereum EOA private key (0x-prefixed)
|
|
4101
|
+
* @returns Promise resolving to the derived Keypair
|
|
4102
|
+
*
|
|
4103
|
+
* @example
|
|
4104
|
+
* ```typescript
|
|
4105
|
+
* const keypair = await Keypair.fromWalletKey('0xYOUR_WALLET_PRIVATE_KEY');
|
|
4106
|
+
* console.log(keypair.depositKey()); // Same as frontend login with this wallet
|
|
4107
|
+
* ```
|
|
4108
|
+
*/
|
|
4109
|
+
static async fromWalletKey(walletPrivateKey) {
|
|
4110
|
+
const account = accounts.privateKeyToAccount(walletPrivateKey);
|
|
4111
|
+
const signature = await account.signMessage({ message: VEIL_SIGNED_MESSAGE });
|
|
4112
|
+
return _Keypair.fromSignature(signature);
|
|
4113
|
+
}
|
|
4114
|
+
/**
|
|
4115
|
+
* Derive a Keypair using any external signer that supports personal_sign (EIP-191).
|
|
4116
|
+
* The signer function receives VEIL_SIGNED_MESSAGE and must return a 0x-prefixed signature.
|
|
4117
|
+
* Works with any signing backend: Bankr, MPC wallets, custodial services, hardware wallets, etc.
|
|
4118
|
+
*
|
|
4119
|
+
* @param signer - Async function that signs a message and returns a 0x-prefixed signature
|
|
4120
|
+
* @returns Promise resolving to the derived Keypair
|
|
4121
|
+
*
|
|
4122
|
+
* @example
|
|
4123
|
+
* ```typescript
|
|
4124
|
+
* // With Bankr
|
|
4125
|
+
* const keypair = await Keypair.fromSigner(async (message) => {
|
|
4126
|
+
* const res = await fetch('https://api.bankr.bot/agent/sign', {
|
|
4127
|
+
* method: 'POST',
|
|
4128
|
+
* headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },
|
|
4129
|
+
* body: JSON.stringify({ signatureType: 'personal_sign', message }),
|
|
4130
|
+
* });
|
|
4131
|
+
* return (await res.json()).signature;
|
|
4132
|
+
* });
|
|
4133
|
+
*
|
|
4134
|
+
* // With any custom signer
|
|
4135
|
+
* const keypair = await Keypair.fromSigner(async (msg) => myService.personalSign(msg));
|
|
4136
|
+
* ```
|
|
4137
|
+
*/
|
|
4138
|
+
static async fromSigner(signer) {
|
|
4139
|
+
const signature = await signer(VEIL_SIGNED_MESSAGE);
|
|
4140
|
+
return _Keypair.fromSignature(signature);
|
|
4141
|
+
}
|
|
4078
4142
|
/**
|
|
4079
4143
|
* Sign a message using the private key
|
|
4080
4144
|
* @param commitment - Commitment hash
|
|
@@ -4165,28 +4229,55 @@ function saveVeilKeypair(veilKey, depositKey, envPath) {
|
|
|
4165
4229
|
content = updateEnvVar(content, "DEPOSIT_KEY", depositKey);
|
|
4166
4230
|
fs.writeFileSync(envPath, content);
|
|
4167
4231
|
}
|
|
4232
|
+
function resolveWalletKey(options) {
|
|
4233
|
+
const raw = options.walletKey || process.env.WALLET_KEY;
|
|
4234
|
+
if (!raw) {
|
|
4235
|
+
throw new Error("Wallet key required for --sign-message. Use --wallet-key <key> or set WALLET_KEY env var.");
|
|
4236
|
+
}
|
|
4237
|
+
const key = raw.startsWith("0x") ? raw : `0x${raw}`;
|
|
4238
|
+
if (key.length !== 66) {
|
|
4239
|
+
throw new Error("Invalid wallet key format. Must be a 0x-prefixed 64-character hex string.");
|
|
4240
|
+
}
|
|
4241
|
+
return key;
|
|
4242
|
+
}
|
|
4168
4243
|
function createInitCommand() {
|
|
4169
|
-
const init = new Command("init").description("Generate a new Veil keypair").option("--force", "Overwrite existing keypair without prompting").option("--json", "Output as JSON (no prompts, no file save)").option("--
|
|
4170
|
-
const envPath =
|
|
4244
|
+
const init = new Command("init").description("Generate a new Veil keypair").option("--force", "Overwrite existing keypair without prompting").option("--json", "Output as JSON (no prompts, no file save)").option("--no-save", "Print keypair without saving to file").option("--sign-message", "Derive keypair from wallet signature (same as frontend login)").option("--wallet-key <key>", "Ethereum wallet private key (or set WALLET_KEY env var)").option("--signature <sig>", "Derive keypair from a pre-computed EIP-191 personal_sign signature").action(async (options) => {
|
|
4245
|
+
const envPath = getDefaultEnvPath();
|
|
4246
|
+
async function createKp() {
|
|
4247
|
+
if (options.signMessage) {
|
|
4248
|
+
const walletKey = resolveWalletKey(options);
|
|
4249
|
+
return Keypair.fromWalletKey(walletKey);
|
|
4250
|
+
}
|
|
4251
|
+
if (options.signature) {
|
|
4252
|
+
return Keypair.fromSignature(options.signature);
|
|
4253
|
+
}
|
|
4254
|
+
return new Keypair();
|
|
4255
|
+
}
|
|
4256
|
+
const derivation = options.signMessage ? "wallet-signature" : options.signature ? "provided-signature" : "random";
|
|
4257
|
+
const derivationLabel = options.signMessage ? "Derived Veil keypair from wallet signature" : options.signature ? "Derived Veil keypair from provided signature" : "Generated new Veil keypair";
|
|
4171
4258
|
if (options.json) {
|
|
4172
|
-
const kp2 =
|
|
4259
|
+
const kp2 = await createKp();
|
|
4173
4260
|
console.log(JSON.stringify({
|
|
4174
4261
|
veilKey: kp2.privkey,
|
|
4175
|
-
|
|
4262
|
+
veilPrivateKey: kp2.privkey,
|
|
4263
|
+
depositKey: kp2.depositKey(),
|
|
4264
|
+
derivation
|
|
4176
4265
|
}, null, 2));
|
|
4177
4266
|
process.exit(0);
|
|
4178
4267
|
return;
|
|
4179
4268
|
}
|
|
4180
4269
|
if (!options.save) {
|
|
4181
|
-
const kp2 =
|
|
4182
|
-
console.log(
|
|
4270
|
+
const kp2 = await createKp();
|
|
4271
|
+
console.log(`
|
|
4272
|
+
${derivationLabel}:
|
|
4273
|
+
`);
|
|
4183
4274
|
console.log("Veil Private Key:");
|
|
4184
4275
|
console.log(` ${kp2.privkey}
|
|
4185
4276
|
`);
|
|
4186
4277
|
console.log("Deposit Key (register this on-chain):");
|
|
4187
4278
|
console.log(` ${kp2.depositKey()}
|
|
4188
4279
|
`);
|
|
4189
|
-
console.log("(Not saved -
|
|
4280
|
+
console.log("(Not saved - run without --no-save to save to .env.veil)");
|
|
4190
4281
|
process.exit(0);
|
|
4191
4282
|
return;
|
|
4192
4283
|
}
|
|
@@ -4201,8 +4292,10 @@ WARNING: A Veil key already exists in ${envPath}`);
|
|
|
4201
4292
|
return;
|
|
4202
4293
|
}
|
|
4203
4294
|
}
|
|
4204
|
-
const kp =
|
|
4205
|
-
console.log(
|
|
4295
|
+
const kp = await createKp();
|
|
4296
|
+
console.log(`
|
|
4297
|
+
${derivationLabel}:
|
|
4298
|
+
`);
|
|
4206
4299
|
console.log("Veil Private Key:");
|
|
4207
4300
|
console.log(` ${kp.privkey}
|
|
4208
4301
|
`);
|
|
@@ -4250,10 +4343,43 @@ var ADDRESSES = {
|
|
|
4250
4343
|
};
|
|
4251
4344
|
var POOL_CONFIG = {
|
|
4252
4345
|
eth: {
|
|
4253
|
-
decimals: 18
|
|
4346
|
+
decimals: 18,
|
|
4347
|
+
displayDecimals: 4,
|
|
4348
|
+
symbol: "ETH",
|
|
4349
|
+
name: "Ethereum"
|
|
4350
|
+
},
|
|
4351
|
+
usdc: {
|
|
4352
|
+
decimals: 6,
|
|
4353
|
+
displayDecimals: 2,
|
|
4354
|
+
symbol: "USDC",
|
|
4355
|
+
name: "USD Coin"
|
|
4356
|
+
}
|
|
4357
|
+
};
|
|
4254
4358
|
function getAddresses() {
|
|
4255
4359
|
return ADDRESSES;
|
|
4256
4360
|
}
|
|
4361
|
+
function getPoolAddress(pool) {
|
|
4362
|
+
const addresses = getAddresses();
|
|
4363
|
+
switch (pool) {
|
|
4364
|
+
case "eth":
|
|
4365
|
+
return addresses.ethPool;
|
|
4366
|
+
case "usdc":
|
|
4367
|
+
return addresses.usdcPool;
|
|
4368
|
+
default:
|
|
4369
|
+
throw new Error(`Unknown pool: ${pool}`);
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
function getQueueAddress(pool) {
|
|
4373
|
+
const addresses = getAddresses();
|
|
4374
|
+
switch (pool) {
|
|
4375
|
+
case "eth":
|
|
4376
|
+
return addresses.ethQueue;
|
|
4377
|
+
case "usdc":
|
|
4378
|
+
return addresses.usdcQueue;
|
|
4379
|
+
default:
|
|
4380
|
+
throw new Error(`Unknown pool: ${pool}`);
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4257
4383
|
function getRelayUrl() {
|
|
4258
4384
|
return ADDRESSES.relayUrl;
|
|
4259
4385
|
}
|
|
@@ -4315,6 +4441,23 @@ var ENTRY_ABI = [
|
|
|
4315
4441
|
stateMutability: "nonpayable",
|
|
4316
4442
|
type: "function"
|
|
4317
4443
|
},
|
|
4444
|
+
// Change deposit key (must already be registered)
|
|
4445
|
+
{
|
|
4446
|
+
inputs: [
|
|
4447
|
+
{
|
|
4448
|
+
components: [
|
|
4449
|
+
{ name: "owner", type: "address" },
|
|
4450
|
+
{ name: "depositKey", type: "bytes" }
|
|
4451
|
+
],
|
|
4452
|
+
name: "_account",
|
|
4453
|
+
type: "tuple"
|
|
4454
|
+
}
|
|
4455
|
+
],
|
|
4456
|
+
name: "changeDepositKey",
|
|
4457
|
+
outputs: [],
|
|
4458
|
+
stateMutability: "nonpayable",
|
|
4459
|
+
type: "function"
|
|
4460
|
+
},
|
|
4318
4461
|
// Queue ETH deposit
|
|
4319
4462
|
{
|
|
4320
4463
|
inputs: [{ name: "_depositKey", type: "bytes" }],
|
|
@@ -4828,6 +4971,35 @@ var POOL_ABI = [
|
|
|
4828
4971
|
// ============ RECEIVE ============
|
|
4829
4972
|
{ stateMutability: "payable", type: "receive" }
|
|
4830
4973
|
];
|
|
4974
|
+
var ERC20_ABI = [
|
|
4975
|
+
{
|
|
4976
|
+
inputs: [
|
|
4977
|
+
{ name: "spender", type: "address" },
|
|
4978
|
+
{ name: "amount", type: "uint256" }
|
|
4979
|
+
],
|
|
4980
|
+
name: "approve",
|
|
4981
|
+
outputs: [{ name: "", type: "bool" }],
|
|
4982
|
+
stateMutability: "nonpayable",
|
|
4983
|
+
type: "function"
|
|
4984
|
+
},
|
|
4985
|
+
{
|
|
4986
|
+
inputs: [{ name: "account", type: "address" }],
|
|
4987
|
+
name: "balanceOf",
|
|
4988
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
4989
|
+
stateMutability: "view",
|
|
4990
|
+
type: "function"
|
|
4991
|
+
},
|
|
4992
|
+
{
|
|
4993
|
+
inputs: [
|
|
4994
|
+
{ name: "owner", type: "address" },
|
|
4995
|
+
{ name: "spender", type: "address" }
|
|
4996
|
+
],
|
|
4997
|
+
name: "allowance",
|
|
4998
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
4999
|
+
stateMutability: "view",
|
|
5000
|
+
type: "function"
|
|
5001
|
+
}
|
|
5002
|
+
];
|
|
4831
5003
|
|
|
4832
5004
|
// src/deposit.ts
|
|
4833
5005
|
function buildRegisterTx(depositKey, ownerAddress) {
|
|
@@ -4845,6 +5017,21 @@ function buildRegisterTx(depositKey, ownerAddress) {
|
|
|
4845
5017
|
data
|
|
4846
5018
|
};
|
|
4847
5019
|
}
|
|
5020
|
+
function buildChangeDepositKeyTx(depositKey, ownerAddress) {
|
|
5021
|
+
const addresses = getAddresses();
|
|
5022
|
+
const data = viem.encodeFunctionData({
|
|
5023
|
+
abi: ENTRY_ABI,
|
|
5024
|
+
functionName: "changeDepositKey",
|
|
5025
|
+
args: [{
|
|
5026
|
+
owner: ownerAddress,
|
|
5027
|
+
depositKey
|
|
5028
|
+
}]
|
|
5029
|
+
});
|
|
5030
|
+
return {
|
|
5031
|
+
to: addresses.entry,
|
|
5032
|
+
data
|
|
5033
|
+
};
|
|
5034
|
+
}
|
|
4848
5035
|
function buildDepositETHTx(options) {
|
|
4849
5036
|
const { depositKey, amount } = options;
|
|
4850
5037
|
const addresses = getAddresses();
|
|
@@ -4860,6 +5047,34 @@ function buildDepositETHTx(options) {
|
|
|
4860
5047
|
value
|
|
4861
5048
|
};
|
|
4862
5049
|
}
|
|
5050
|
+
function buildApproveUSDCTx(options) {
|
|
5051
|
+
const { amount } = options;
|
|
5052
|
+
const addresses = getAddresses();
|
|
5053
|
+
const amountWei = viem.parseUnits(amount, POOL_CONFIG.usdc.decimals);
|
|
5054
|
+
const data = viem.encodeFunctionData({
|
|
5055
|
+
abi: ERC20_ABI,
|
|
5056
|
+
functionName: "approve",
|
|
5057
|
+
args: [addresses.entry, amountWei]
|
|
5058
|
+
});
|
|
5059
|
+
return {
|
|
5060
|
+
to: addresses.usdcToken,
|
|
5061
|
+
data
|
|
5062
|
+
};
|
|
5063
|
+
}
|
|
5064
|
+
function buildDepositUSDCTx(options) {
|
|
5065
|
+
const { depositKey, amount } = options;
|
|
5066
|
+
const addresses = getAddresses();
|
|
5067
|
+
const amountWei = viem.parseUnits(amount, POOL_CONFIG.usdc.decimals);
|
|
5068
|
+
const data = viem.encodeFunctionData({
|
|
5069
|
+
abi: ENTRY_ABI,
|
|
5070
|
+
functionName: "queueUSDC",
|
|
5071
|
+
args: [amountWei, depositKey]
|
|
5072
|
+
});
|
|
5073
|
+
return {
|
|
5074
|
+
to: addresses.entry,
|
|
5075
|
+
data
|
|
5076
|
+
};
|
|
5077
|
+
}
|
|
4863
5078
|
function createWallet(config) {
|
|
4864
5079
|
const { privateKey, rpcUrl } = config;
|
|
4865
5080
|
const account = accounts.privateKeyToAccount(privateKey);
|
|
@@ -5076,7 +5291,7 @@ function handleCLIError(error) {
|
|
|
5076
5291
|
|
|
5077
5292
|
// src/cli/commands/register.ts
|
|
5078
5293
|
function createRegisterCommand() {
|
|
5079
|
-
const register = new Command("register").description("Register your deposit key on-chain
|
|
5294
|
+
const register = new Command("register").description("Register or update your deposit key on-chain").option("--deposit-key <key>", "Your Veil deposit key (or set DEPOSIT_KEY env)").option("--wallet-key <key>", "Ethereum wallet key for signing (or set WALLET_KEY env)").option("--address <address>", "Owner address (required with --unsigned)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--unsigned", "Output unsigned transaction payload (Bankr-compatible format)").option("--force", "Change deposit key even if already registered").option("--json", "Output as JSON").action(async (options) => {
|
|
5080
5295
|
const jsonOutput = options.json;
|
|
5081
5296
|
try {
|
|
5082
5297
|
const depositKey = options.depositKey || process.env.DEPOSIT_KEY;
|
|
@@ -5094,8 +5309,9 @@ function createRegisterCommand() {
|
|
|
5094
5309
|
}
|
|
5095
5310
|
address2 = getAddress(walletKey);
|
|
5096
5311
|
}
|
|
5097
|
-
const tx2 = buildRegisterTx(depositKey, address2);
|
|
5312
|
+
const tx2 = options.force ? buildChangeDepositKeyTx(depositKey, address2) : buildRegisterTx(depositKey, address2);
|
|
5098
5313
|
const payload = {
|
|
5314
|
+
action: options.force ? "changeDepositKey" : "register",
|
|
5099
5315
|
to: tx2.to,
|
|
5100
5316
|
data: tx2.data,
|
|
5101
5317
|
value: "0",
|
|
@@ -5109,43 +5325,69 @@ function createRegisterCommand() {
|
|
|
5109
5325
|
const address = getAddress(config.privateKey);
|
|
5110
5326
|
if (!jsonOutput) console.log("\nChecking registration status...");
|
|
5111
5327
|
const { registered, depositKey: existingKey } = await isRegistered(address, config.rpcUrl);
|
|
5112
|
-
|
|
5328
|
+
const keysMatch = registered && existingKey === depositKey;
|
|
5329
|
+
const isChange = registered && !keysMatch;
|
|
5330
|
+
if (registered && keysMatch) {
|
|
5113
5331
|
if (jsonOutput) {
|
|
5114
5332
|
console.log(JSON.stringify({
|
|
5115
5333
|
success: true,
|
|
5116
5334
|
alreadyRegistered: true,
|
|
5335
|
+
keysMatch: true,
|
|
5117
5336
|
address,
|
|
5118
5337
|
depositKey: existingKey
|
|
5119
5338
|
}, null, 2));
|
|
5120
5339
|
} else {
|
|
5121
5340
|
console.log(`
|
|
5122
|
-
Address ${address} is already registered.`);
|
|
5341
|
+
Address ${address} is already registered with this deposit key.`);
|
|
5123
5342
|
console.log(`
|
|
5124
|
-
|
|
5125
|
-
console.log(` ${existingKey}`);
|
|
5343
|
+
Deposit key: ${existingKey.slice(0, 40)}...`);
|
|
5126
5344
|
}
|
|
5127
5345
|
process.exit(0);
|
|
5128
5346
|
return;
|
|
5129
5347
|
}
|
|
5348
|
+
if (isChange && !options.force) {
|
|
5349
|
+
if (jsonOutput) {
|
|
5350
|
+
console.log(JSON.stringify({
|
|
5351
|
+
success: false,
|
|
5352
|
+
alreadyRegistered: true,
|
|
5353
|
+
keysMatch: false,
|
|
5354
|
+
address,
|
|
5355
|
+
onChainKey: existingKey,
|
|
5356
|
+
localKey: depositKey.slice(0, 40) + "...",
|
|
5357
|
+
hint: "Use --force to change deposit key"
|
|
5358
|
+
}, null, 2));
|
|
5359
|
+
} else {
|
|
5360
|
+
console.log(`
|
|
5361
|
+
Address ${address} is already registered with a different deposit key.`);
|
|
5362
|
+
console.log(`
|
|
5363
|
+
On-chain key: ${existingKey.slice(0, 40)}...`);
|
|
5364
|
+
console.log(` Local key: ${depositKey.slice(0, 40)}...`);
|
|
5365
|
+
console.log(`
|
|
5366
|
+
Use --force to change your deposit key on-chain.`);
|
|
5367
|
+
}
|
|
5368
|
+
process.exit(1);
|
|
5369
|
+
return;
|
|
5370
|
+
}
|
|
5371
|
+
const action = isChange ? "Changing deposit key" : "Registering deposit key";
|
|
5130
5372
|
if (!jsonOutput) {
|
|
5131
|
-
console.log(
|
|
5373
|
+
console.log(`${action}...`);
|
|
5132
5374
|
console.log(` Address: ${address}`);
|
|
5133
5375
|
console.log(` Deposit Key: ${depositKey.slice(0, 40)}...`);
|
|
5134
5376
|
}
|
|
5135
|
-
const tx = buildRegisterTx(depositKey, address);
|
|
5377
|
+
const tx = isChange ? buildChangeDepositKeyTx(depositKey, address) : buildRegisterTx(depositKey, address);
|
|
5136
5378
|
const result = await sendTransaction(config, tx);
|
|
5137
5379
|
if (result.receipt.status === "success") {
|
|
5138
5380
|
if (jsonOutput) {
|
|
5139
5381
|
console.log(JSON.stringify({
|
|
5140
5382
|
success: true,
|
|
5141
|
-
|
|
5383
|
+
action: isChange ? "changed" : "registered",
|
|
5142
5384
|
address,
|
|
5143
5385
|
transactionHash: result.hash,
|
|
5144
5386
|
blockNumber: result.receipt.blockNumber.toString(),
|
|
5145
5387
|
gasUsed: result.receipt.gasUsed.toString()
|
|
5146
5388
|
}, null, 2));
|
|
5147
5389
|
} else {
|
|
5148
|
-
console.log("\nRegistration successful!");
|
|
5390
|
+
console.log(isChange ? "\nDeposit key changed successfully!" : "\nRegistration successful!");
|
|
5149
5391
|
console.log(` Transaction: ${result.hash}`);
|
|
5150
5392
|
console.log(` Block: ${result.receipt.blockNumber}`);
|
|
5151
5393
|
console.log(` Gas used: ${result.receipt.gasUsed}`);
|
|
@@ -5161,25 +5403,35 @@ Existing deposit key:`);
|
|
|
5161
5403
|
});
|
|
5162
5404
|
return register;
|
|
5163
5405
|
}
|
|
5164
|
-
var MINIMUM_DEPOSIT_ETH = 0.01;
|
|
5165
5406
|
var DEPOSIT_FEE_PERCENT = 0.3;
|
|
5166
|
-
var
|
|
5407
|
+
var MINIMUM_DEPOSITS = {
|
|
5408
|
+
ETH: 0.01,
|
|
5409
|
+
USDC: 10
|
|
5410
|
+
};
|
|
5411
|
+
function getMinimumWithFee(asset) {
|
|
5412
|
+
const min = MINIMUM_DEPOSITS[asset] || 0;
|
|
5413
|
+
return min / (1 - DEPOSIT_FEE_PERCENT / 100);
|
|
5414
|
+
}
|
|
5415
|
+
var SUPPORTED_ASSETS = ["ETH", "USDC"];
|
|
5167
5416
|
function progress(msg, quiet) {
|
|
5168
5417
|
if (!quiet) {
|
|
5169
5418
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
5170
5419
|
}
|
|
5171
5420
|
}
|
|
5172
5421
|
function createDepositCommand() {
|
|
5173
|
-
const deposit = new Command("deposit").description("Deposit ETH into Veil").argument("<asset>", "Asset to deposit (ETH)").argument("<amount>", "Amount to deposit (e.g., 0.1)").option("--deposit-key <key>", "Your Veil deposit key (or set DEPOSIT_KEY env)").option("--wallet-key <key>", "Ethereum wallet key for signing (or set WALLET_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--unsigned", "Output unsigned transaction payload (Bankr-compatible format)").option("--quiet", "Suppress progress output").action(async (asset, amount, options) => {
|
|
5422
|
+
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 (e.g., 0.1)").option("--deposit-key <key>", "Your Veil deposit key (or set DEPOSIT_KEY env)").option("--wallet-key <key>", "Ethereum wallet key for signing (or set WALLET_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--unsigned", "Output unsigned transaction payload (Bankr-compatible format)").option("--quiet", "Suppress progress output").action(async (asset, amount, options) => {
|
|
5174
5423
|
try {
|
|
5175
|
-
|
|
5176
|
-
|
|
5424
|
+
const assetUpper = asset.toUpperCase();
|
|
5425
|
+
if (!SUPPORTED_ASSETS.includes(assetUpper)) {
|
|
5426
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported asset: ${asset}. Supported: ${SUPPORTED_ASSETS.join(", ")}`);
|
|
5177
5427
|
}
|
|
5178
5428
|
const amountNum = parseFloat(amount);
|
|
5179
|
-
|
|
5429
|
+
const minimumWithFee = getMinimumWithFee(assetUpper);
|
|
5430
|
+
const minimumNet = MINIMUM_DEPOSITS[assetUpper];
|
|
5431
|
+
if (amountNum < minimumWithFee) {
|
|
5180
5432
|
throw new CLIError(
|
|
5181
5433
|
ErrorCode.INVALID_AMOUNT,
|
|
5182
|
-
`Minimum deposit is ${
|
|
5434
|
+
`Minimum deposit is ${minimumNet} ${assetUpper} (net). With ${DEPOSIT_FEE_PERCENT}% fee, send at least ${minimumWithFee.toFixed(assetUpper === "ETH" ? 5 : 8)} ${assetUpper}.`
|
|
5183
5435
|
);
|
|
5184
5436
|
}
|
|
5185
5437
|
const depositKey = options.depositKey || process.env.DEPOSIT_KEY;
|
|
@@ -5187,38 +5439,59 @@ function createDepositCommand() {
|
|
|
5187
5439
|
throw new CLIError(ErrorCode.DEPOSIT_KEY_MISSING, "Deposit key required. Use --deposit-key or set DEPOSIT_KEY in .env (run: veil init)");
|
|
5188
5440
|
}
|
|
5189
5441
|
progress("Building transaction...", options.quiet);
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5442
|
+
let tx;
|
|
5443
|
+
let approveTx = null;
|
|
5444
|
+
if (assetUpper === "USDC") {
|
|
5445
|
+
approveTx = buildApproveUSDCTx({ amount });
|
|
5446
|
+
tx = buildDepositUSDCTx({ depositKey, amount });
|
|
5447
|
+
} else {
|
|
5448
|
+
tx = buildDepositETHTx({ depositKey, amount });
|
|
5449
|
+
}
|
|
5194
5450
|
if (options.unsigned) {
|
|
5195
5451
|
progress("", options.quiet);
|
|
5196
|
-
const
|
|
5452
|
+
const payloads = [];
|
|
5453
|
+
if (approveTx) {
|
|
5454
|
+
payloads.push({
|
|
5455
|
+
step: "approve",
|
|
5456
|
+
to: approveTx.to,
|
|
5457
|
+
data: approveTx.data,
|
|
5458
|
+
value: "0",
|
|
5459
|
+
chainId: 8453
|
|
5460
|
+
});
|
|
5461
|
+
}
|
|
5462
|
+
payloads.push({
|
|
5463
|
+
step: "deposit",
|
|
5197
5464
|
to: tx.to,
|
|
5198
5465
|
data: tx.data,
|
|
5199
5466
|
value: tx.value ? tx.value.toString() : "0",
|
|
5200
5467
|
chainId: 8453
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
5468
|
+
});
|
|
5469
|
+
console.log(JSON.stringify(payloads.length === 1 ? payloads[0] : payloads, null, 2));
|
|
5204
5470
|
return;
|
|
5205
5471
|
}
|
|
5206
5472
|
const config = getConfig(options);
|
|
5207
5473
|
const address = getAddress(config.privateKey);
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5474
|
+
if (assetUpper === "ETH") {
|
|
5475
|
+
progress("Checking balance...", options.quiet);
|
|
5476
|
+
const balance = await getBalance(address, config.rpcUrl);
|
|
5477
|
+
const amountWei = viem.parseEther(amount);
|
|
5478
|
+
if (balance < amountWei) {
|
|
5479
|
+
progress("", options.quiet);
|
|
5480
|
+
throw new CLIError(ErrorCode.INSUFFICIENT_BALANCE, `Insufficient ETH balance. Have: ${viem.formatEther(balance)} ETH, Need: ${amount} ETH`);
|
|
5481
|
+
}
|
|
5482
|
+
}
|
|
5483
|
+
if (approveTx) {
|
|
5484
|
+
progress(`Approving ${assetUpper}...`, options.quiet);
|
|
5485
|
+
await sendTransaction(config, approveTx);
|
|
5214
5486
|
}
|
|
5215
|
-
progress("Sending transaction...", options.quiet);
|
|
5487
|
+
progress("Sending deposit transaction...", options.quiet);
|
|
5216
5488
|
const result = await sendTransaction(config, tx);
|
|
5217
5489
|
progress("Confirming...", options.quiet);
|
|
5218
5490
|
progress("", options.quiet);
|
|
5219
5491
|
console.log(JSON.stringify({
|
|
5220
5492
|
success: result.receipt.status === "success",
|
|
5221
5493
|
hash: result.hash,
|
|
5494
|
+
asset: assetUpper,
|
|
5222
5495
|
amount,
|
|
5223
5496
|
blockNumber: result.receipt.blockNumber.toString(),
|
|
5224
5497
|
gasUsed: result.receipt.gasUsed.toString()
|
|
@@ -5315,15 +5588,16 @@ var DEPOSIT_STATUS_MAP = {
|
|
|
5315
5588
|
3: "refunded"
|
|
5316
5589
|
};
|
|
5317
5590
|
async function getQueueBalance(options) {
|
|
5318
|
-
const { address, rpcUrl, onProgress } = options;
|
|
5319
|
-
const
|
|
5591
|
+
const { address, pool = "eth", rpcUrl, onProgress } = options;
|
|
5592
|
+
const queueAddress = getQueueAddress(pool);
|
|
5593
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
5320
5594
|
const publicClient = viem.createPublicClient({
|
|
5321
5595
|
chain: chains.base,
|
|
5322
5596
|
transport: viem.http(rpcUrl)
|
|
5323
5597
|
});
|
|
5324
5598
|
onProgress?.("Fetching pending deposits...");
|
|
5325
5599
|
const pendingNonces = await publicClient.readContract({
|
|
5326
|
-
address:
|
|
5600
|
+
address: queueAddress,
|
|
5327
5601
|
abi: QUEUE_ABI,
|
|
5328
5602
|
functionName: "getPendingDeposits"
|
|
5329
5603
|
});
|
|
@@ -5334,7 +5608,7 @@ async function getQueueBalance(options) {
|
|
|
5334
5608
|
const nonce = pendingNonces[i];
|
|
5335
5609
|
onProgress?.("Checking deposit", `${i + 1}/${pendingNonces.length}`);
|
|
5336
5610
|
const deposit = await publicClient.readContract({
|
|
5337
|
-
address:
|
|
5611
|
+
address: queueAddress,
|
|
5338
5612
|
abi: QUEUE_ABI,
|
|
5339
5613
|
functionName: "getDeposit",
|
|
5340
5614
|
args: [nonce]
|
|
@@ -5344,7 +5618,7 @@ async function getQueueBalance(options) {
|
|
|
5344
5618
|
pendingDeposits.push({
|
|
5345
5619
|
nonce: nonce.toString(),
|
|
5346
5620
|
status: DEPOSIT_STATUS_MAP[deposit.status] || "pending",
|
|
5347
|
-
amount: viem.
|
|
5621
|
+
amount: viem.formatUnits(deposit.amountIn, poolConfig.decimals),
|
|
5348
5622
|
amountWei: deposit.amountIn.toString(),
|
|
5349
5623
|
timestamp: new Date(Number(deposit.timestamp) * 1e3).toISOString()
|
|
5350
5624
|
});
|
|
@@ -5355,15 +5629,16 @@ async function getQueueBalance(options) {
|
|
|
5355
5629
|
}
|
|
5356
5630
|
return {
|
|
5357
5631
|
address,
|
|
5358
|
-
queueBalance: viem.
|
|
5632
|
+
queueBalance: viem.formatUnits(totalQueueBalance, poolConfig.decimals),
|
|
5359
5633
|
queueBalanceWei: totalQueueBalance.toString(),
|
|
5360
5634
|
pendingDeposits,
|
|
5361
5635
|
pendingCount: pendingDeposits.length
|
|
5362
5636
|
};
|
|
5363
5637
|
}
|
|
5364
5638
|
async function getPrivateBalance(options) {
|
|
5365
|
-
const { keypair, rpcUrl, onProgress } = options;
|
|
5366
|
-
const
|
|
5639
|
+
const { keypair, pool = "eth", rpcUrl, onProgress } = options;
|
|
5640
|
+
const poolAddress = getPoolAddress(pool);
|
|
5641
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
5367
5642
|
if (!keypair.privkey) {
|
|
5368
5643
|
throw new Error("Keypair must have a private key to calculate private balance");
|
|
5369
5644
|
}
|
|
@@ -5373,7 +5648,7 @@ async function getPrivateBalance(options) {
|
|
|
5373
5648
|
});
|
|
5374
5649
|
onProgress?.("Fetching pool index...");
|
|
5375
5650
|
const nextIndex = await publicClient.readContract({
|
|
5376
|
-
address:
|
|
5651
|
+
address: poolAddress,
|
|
5377
5652
|
abi: POOL_ABI,
|
|
5378
5653
|
functionName: "nextIndex"
|
|
5379
5654
|
});
|
|
@@ -5396,7 +5671,7 @@ async function getPrivateBalance(options) {
|
|
|
5396
5671
|
const batchNum = Math.floor(start / BATCH_SIZE) + 1;
|
|
5397
5672
|
onProgress?.("Fetching encrypted outputs", `batch ${batchNum}/${totalBatches} (${start}-${end})`);
|
|
5398
5673
|
const batch = await publicClient.readContract({
|
|
5399
|
-
address:
|
|
5674
|
+
address: poolAddress,
|
|
5400
5675
|
abi: POOL_ABI,
|
|
5401
5676
|
functionName: "getEncryptedOutputs",
|
|
5402
5677
|
args: [BigInt(start), BigInt(end)]
|
|
@@ -5426,14 +5701,14 @@ async function getPrivateBalance(options) {
|
|
|
5426
5701
|
const nullifier = utxo.getNullifier();
|
|
5427
5702
|
const nullifierHex = toFixedHex(nullifier);
|
|
5428
5703
|
const isSpent = await publicClient.readContract({
|
|
5429
|
-
address:
|
|
5704
|
+
address: poolAddress,
|
|
5430
5705
|
abi: POOL_ABI,
|
|
5431
5706
|
functionName: "isSpent",
|
|
5432
5707
|
args: [nullifierHex]
|
|
5433
5708
|
});
|
|
5434
5709
|
utxoInfos.push({
|
|
5435
5710
|
index,
|
|
5436
|
-
amount: viem.
|
|
5711
|
+
amount: viem.formatUnits(utxo.amount, poolConfig.decimals),
|
|
5437
5712
|
amountWei: utxo.amount.toString(),
|
|
5438
5713
|
isSpent
|
|
5439
5714
|
});
|
|
@@ -5445,7 +5720,7 @@ async function getPrivateBalance(options) {
|
|
|
5445
5720
|
}
|
|
5446
5721
|
}
|
|
5447
5722
|
return {
|
|
5448
|
-
privateBalance: viem.
|
|
5723
|
+
privateBalance: viem.formatUnits(totalBalance, poolConfig.decimals),
|
|
5449
5724
|
privateBalanceWei: totalBalance.toString(),
|
|
5450
5725
|
utxoCount: decryptedUtxos.length,
|
|
5451
5726
|
spentCount,
|
|
@@ -5453,9 +5728,62 @@ async function getPrivateBalance(options) {
|
|
|
5453
5728
|
utxos: utxoInfos
|
|
5454
5729
|
};
|
|
5455
5730
|
}
|
|
5731
|
+
var SUPPORTED_POOLS = ["eth", "usdc"];
|
|
5732
|
+
async function fetchPoolBalance(pool, address, keypair, rpcUrl, onProgress) {
|
|
5733
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
5734
|
+
const poolProgress = onProgress ? (stage, detail) => onProgress(`[${pool.toUpperCase()}] ${stage}`, detail) : void 0;
|
|
5735
|
+
const queueResult = await getQueueBalance({ address, pool, rpcUrl, onProgress: poolProgress });
|
|
5736
|
+
let privateResult = null;
|
|
5737
|
+
if (keypair) {
|
|
5738
|
+
privateResult = await getPrivateBalance({ keypair, pool, rpcUrl, onProgress: poolProgress });
|
|
5739
|
+
}
|
|
5740
|
+
const queueBalanceWei = BigInt(queueResult.queueBalanceWei);
|
|
5741
|
+
const privateBalanceWei = privateResult ? BigInt(privateResult.privateBalanceWei) : 0n;
|
|
5742
|
+
const totalBalanceWei = queueBalanceWei + privateBalanceWei;
|
|
5743
|
+
const result = {
|
|
5744
|
+
pool: pool.toUpperCase(),
|
|
5745
|
+
symbol: poolConfig.symbol,
|
|
5746
|
+
totalBalance: viem.formatUnits(totalBalanceWei, poolConfig.decimals),
|
|
5747
|
+
totalBalanceWei: totalBalanceWei.toString()
|
|
5748
|
+
};
|
|
5749
|
+
if (privateResult) {
|
|
5750
|
+
const unspentUtxos = privateResult.utxos.filter((u) => !u.isSpent);
|
|
5751
|
+
result.private = {
|
|
5752
|
+
balance: privateResult.privateBalance,
|
|
5753
|
+
balanceWei: privateResult.privateBalanceWei,
|
|
5754
|
+
utxoCount: privateResult.unspentCount,
|
|
5755
|
+
utxos: unspentUtxos.map((u) => ({
|
|
5756
|
+
index: u.index,
|
|
5757
|
+
amount: u.amount
|
|
5758
|
+
}))
|
|
5759
|
+
};
|
|
5760
|
+
} else {
|
|
5761
|
+
result.private = {
|
|
5762
|
+
balance: null,
|
|
5763
|
+
note: "Set VEIL_KEY to see private balance"
|
|
5764
|
+
};
|
|
5765
|
+
}
|
|
5766
|
+
result.queue = {
|
|
5767
|
+
balance: queueResult.queueBalance,
|
|
5768
|
+
balanceWei: queueResult.queueBalanceWei,
|
|
5769
|
+
count: queueResult.pendingCount,
|
|
5770
|
+
deposits: queueResult.pendingDeposits.map((d) => ({
|
|
5771
|
+
nonce: d.nonce,
|
|
5772
|
+
amount: d.amount,
|
|
5773
|
+
status: d.status,
|
|
5774
|
+
timestamp: d.timestamp
|
|
5775
|
+
}))
|
|
5776
|
+
};
|
|
5777
|
+
return result;
|
|
5778
|
+
}
|
|
5456
5779
|
function createBalanceCommand() {
|
|
5457
|
-
const balance = new Command("balance").description("Show queue and private balances").option("--wallet-key <key>", "Ethereum wallet key (or set WALLET_KEY env)").option("--address <address>", "Address to check (or derived from wallet key)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (options) => {
|
|
5780
|
+
const balance = new Command("balance").description("Show queue and private balances (all pools by default)").option("--pool <pool>", "Pool to check (eth, usdc, or all)", "all").option("--wallet-key <key>", "Ethereum wallet key (or set WALLET_KEY env)").option("--address <address>", "Address to check (or derived from wallet key)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (options) => {
|
|
5458
5781
|
try {
|
|
5782
|
+
const poolArg = (options.pool || "all").toLowerCase();
|
|
5783
|
+
if (poolArg !== "all" && !SUPPORTED_POOLS.includes(poolArg)) {
|
|
5784
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported pool: ${options.pool}. Supported: ${SUPPORTED_POOLS.join(", ")}, all`);
|
|
5785
|
+
}
|
|
5786
|
+
const poolsToQuery = poolArg === "all" ? [...SUPPORTED_POOLS] : [poolArg];
|
|
5459
5787
|
let address;
|
|
5460
5788
|
if (options.address) {
|
|
5461
5789
|
address = options.address;
|
|
@@ -5473,51 +5801,28 @@ function createBalanceCommand() {
|
|
|
5473
5801
|
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
5474
5802
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
5475
5803
|
};
|
|
5476
|
-
const
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5804
|
+
const depositKey = process.env.DEPOSIT_KEY || (keypair ? keypair.depositKey() : null);
|
|
5805
|
+
if (poolsToQuery.length === 1) {
|
|
5806
|
+
const poolResult = await fetchPoolBalance(poolsToQuery[0], address, keypair, rpcUrl, onProgress);
|
|
5807
|
+
if (!options.quiet) process.stderr.write("\r\x1B[K");
|
|
5808
|
+
const output2 = {
|
|
5809
|
+
address,
|
|
5810
|
+
depositKey: depositKey || null,
|
|
5811
|
+
...poolResult
|
|
5812
|
+
};
|
|
5813
|
+
console.log(JSON.stringify(output2, null, 2));
|
|
5814
|
+
return;
|
|
5480
5815
|
}
|
|
5481
|
-
|
|
5482
|
-
|
|
5816
|
+
const pools = [];
|
|
5817
|
+
for (const pool of poolsToQuery) {
|
|
5818
|
+
const poolResult = await fetchPoolBalance(pool, address, keypair, rpcUrl, onProgress);
|
|
5819
|
+
pools.push(poolResult);
|
|
5483
5820
|
}
|
|
5484
|
-
|
|
5485
|
-
const privateBalanceWei = privateResult ? BigInt(privateResult.privateBalanceWei) : 0n;
|
|
5486
|
-
const totalBalanceWei = queueBalanceWei + privateBalanceWei;
|
|
5487
|
-
const depositKey = process.env.DEPOSIT_KEY || (keypair ? keypair.depositKey() : null);
|
|
5821
|
+
if (!options.quiet) process.stderr.write("\r\x1B[K");
|
|
5488
5822
|
const output = {
|
|
5489
5823
|
address,
|
|
5490
5824
|
depositKey: depositKey || null,
|
|
5491
|
-
|
|
5492
|
-
totalBalanceWei: totalBalanceWei.toString()
|
|
5493
|
-
};
|
|
5494
|
-
if (privateResult) {
|
|
5495
|
-
const unspentUtxos = privateResult.utxos.filter((u) => !u.isSpent);
|
|
5496
|
-
output.private = {
|
|
5497
|
-
balance: privateResult.privateBalance,
|
|
5498
|
-
balanceWei: privateResult.privateBalanceWei,
|
|
5499
|
-
utxoCount: privateResult.unspentCount,
|
|
5500
|
-
utxos: unspentUtxos.map((u) => ({
|
|
5501
|
-
index: u.index,
|
|
5502
|
-
amount: u.amount
|
|
5503
|
-
}))
|
|
5504
|
-
};
|
|
5505
|
-
} else {
|
|
5506
|
-
output.private = {
|
|
5507
|
-
balance: null,
|
|
5508
|
-
note: "Set VEIL_KEY to see private balance"
|
|
5509
|
-
};
|
|
5510
|
-
}
|
|
5511
|
-
output.queue = {
|
|
5512
|
-
balance: queueResult.queueBalance,
|
|
5513
|
-
balanceWei: queueResult.queueBalanceWei,
|
|
5514
|
-
count: queueResult.pendingCount,
|
|
5515
|
-
deposits: queueResult.pendingDeposits.map((d) => ({
|
|
5516
|
-
nonce: d.nonce,
|
|
5517
|
-
amount: d.amount,
|
|
5518
|
-
status: d.status,
|
|
5519
|
-
timestamp: d.timestamp
|
|
5520
|
-
}))
|
|
5825
|
+
pools
|
|
5521
5826
|
};
|
|
5522
5827
|
console.log(JSON.stringify(output, null, 2));
|
|
5523
5828
|
} catch (error) {
|
|
@@ -5530,8 +5835,9 @@ function createBalanceCommand() {
|
|
|
5530
5835
|
|
|
5531
5836
|
// src/cli/commands/queue-balance.ts
|
|
5532
5837
|
function createQueueBalanceCommand() {
|
|
5533
|
-
const balance = new Command("queue-balance").description("Show queue balance and pending deposits").option("--wallet-key <key>", "Ethereum wallet key (or set WALLET_KEY env)").option("--address <address>", "Address to check (or derived from wallet key)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (options) => {
|
|
5838
|
+
const balance = new Command("queue-balance").description("Show queue balance and pending deposits").option("--pool <pool>", "Pool to check (eth or usdc)", "eth").option("--wallet-key <key>", "Ethereum wallet key (or set WALLET_KEY env)").option("--address <address>", "Address to check (or derived from wallet key)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (options) => {
|
|
5534
5839
|
try {
|
|
5840
|
+
const pool = (options.pool || "eth").toLowerCase();
|
|
5535
5841
|
let address;
|
|
5536
5842
|
if (options.address) {
|
|
5537
5843
|
address = options.address;
|
|
@@ -5547,7 +5853,7 @@ function createQueueBalanceCommand() {
|
|
|
5547
5853
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
5548
5854
|
};
|
|
5549
5855
|
const rpcUrl = options.rpcUrl || process.env.RPC_URL;
|
|
5550
|
-
const result = await getQueueBalance({ address, rpcUrl, onProgress });
|
|
5856
|
+
const result = await getQueueBalance({ address, pool, rpcUrl, onProgress });
|
|
5551
5857
|
if (!options.quiet) {
|
|
5552
5858
|
process.stderr.write("\r\x1B[K");
|
|
5553
5859
|
}
|
|
@@ -5564,8 +5870,9 @@ function createQueueBalanceCommand() {
|
|
|
5564
5870
|
|
|
5565
5871
|
// src/cli/commands/private-balance.ts
|
|
5566
5872
|
function createPrivateBalanceCommand() {
|
|
5567
|
-
const privateBalance = new Command("private-balance").description("Show private balance (requires VEIL_KEY)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--show-utxos", "Show individual UTXO details").option("--quiet", "Suppress progress output").action(async (options) => {
|
|
5873
|
+
const privateBalance = new Command("private-balance").description("Show private balance (requires VEIL_KEY)").option("--pool <pool>", "Pool to check (eth or usdc)", "eth").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--show-utxos", "Show individual UTXO details").option("--quiet", "Suppress progress output").action(async (options) => {
|
|
5568
5874
|
try {
|
|
5875
|
+
const pool = (options.pool || "eth").toLowerCase();
|
|
5569
5876
|
const veilKey = options.veilKey || process.env.VEIL_KEY;
|
|
5570
5877
|
if (!veilKey) {
|
|
5571
5878
|
throw new Error("Must provide --veil-key or set VEIL_KEY env");
|
|
@@ -5576,11 +5883,12 @@ function createPrivateBalanceCommand() {
|
|
|
5576
5883
|
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
5577
5884
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
5578
5885
|
};
|
|
5579
|
-
const result = await getPrivateBalance({ keypair, rpcUrl, onProgress });
|
|
5886
|
+
const result = await getPrivateBalance({ keypair, pool, rpcUrl, onProgress });
|
|
5580
5887
|
if (!options.quiet) {
|
|
5581
5888
|
process.stderr.write("\r\x1B[K");
|
|
5582
5889
|
}
|
|
5583
5890
|
const output = {
|
|
5891
|
+
pool: pool.toUpperCase(),
|
|
5584
5892
|
privateBalance: result.privateBalance,
|
|
5585
5893
|
privateBalanceWei: result.privateBalanceWei,
|
|
5586
5894
|
utxoCount: result.utxoCount,
|
|
@@ -5916,15 +6224,16 @@ async function buildWithdrawProof(options) {
|
|
|
5916
6224
|
amount,
|
|
5917
6225
|
recipient,
|
|
5918
6226
|
keypair,
|
|
6227
|
+
pool = "eth",
|
|
5919
6228
|
rpcUrl,
|
|
5920
6229
|
onProgress
|
|
5921
6230
|
} = options;
|
|
5922
|
-
const
|
|
5923
|
-
const
|
|
5924
|
-
const poolAddress = addresses.ethPool;
|
|
6231
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
6232
|
+
const poolAddress = getPoolAddress(pool);
|
|
5925
6233
|
onProgress?.("Fetching your UTXOs...");
|
|
5926
6234
|
const balanceResult = await getPrivateBalance({
|
|
5927
6235
|
keypair,
|
|
6236
|
+
pool,
|
|
5928
6237
|
rpcUrl,
|
|
5929
6238
|
onProgress
|
|
5930
6239
|
});
|
|
@@ -5998,12 +6307,12 @@ async function buildWithdrawProof(options) {
|
|
|
5998
6307
|
};
|
|
5999
6308
|
}
|
|
6000
6309
|
async function withdraw(options) {
|
|
6001
|
-
const { amount, recipient, onProgress } = options;
|
|
6310
|
+
const { amount, recipient, pool = "eth", onProgress } = options;
|
|
6002
6311
|
const proof = await buildWithdrawProof(options);
|
|
6003
6312
|
onProgress?.("Submitting to relay...");
|
|
6004
6313
|
const relayResult = await submitRelay({
|
|
6005
6314
|
type: "withdraw",
|
|
6006
|
-
pool
|
|
6315
|
+
pool,
|
|
6007
6316
|
proofArgs: proof.proofArgs,
|
|
6008
6317
|
extData: proof.extData,
|
|
6009
6318
|
metadata: {
|
|
@@ -6023,16 +6332,18 @@ async function withdraw(options) {
|
|
|
6023
6332
|
}
|
|
6024
6333
|
|
|
6025
6334
|
// src/cli/commands/withdraw.ts
|
|
6335
|
+
var SUPPORTED_ASSETS2 = ["ETH", "USDC"];
|
|
6026
6336
|
function progress2(msg, quiet) {
|
|
6027
6337
|
if (!quiet) {
|
|
6028
6338
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
6029
6339
|
}
|
|
6030
6340
|
}
|
|
6031
6341
|
function createWithdrawCommand() {
|
|
6032
|
-
const withdrawCmd = new Command("withdraw").description("Withdraw from private pool to a public address").argument("<asset>", "Asset to withdraw (ETH)").argument("<amount>", "Amount to withdraw (e.g., 0.1)").argument("<recipient>", "Recipient address (e.g., 0x...)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (asset, amount, recipient, options) => {
|
|
6342
|
+
const withdrawCmd = new Command("withdraw").description("Withdraw from private pool to a public address").argument("<asset>", "Asset to withdraw (ETH or USDC)").argument("<amount>", "Amount to withdraw (e.g., 0.1)").argument("<recipient>", "Recipient address (e.g., 0x...)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (asset, amount, recipient, options) => {
|
|
6033
6343
|
try {
|
|
6034
|
-
|
|
6035
|
-
|
|
6344
|
+
const assetUpper = asset.toUpperCase();
|
|
6345
|
+
if (!SUPPORTED_ASSETS2.includes(assetUpper)) {
|
|
6346
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported asset: ${asset}. Supported: ${SUPPORTED_ASSETS2.join(", ")}`);
|
|
6036
6347
|
}
|
|
6037
6348
|
if (!/^0x[a-fA-F0-9]{40}$/.test(recipient)) {
|
|
6038
6349
|
throw new CLIError(ErrorCode.INVALID_ADDRESS, "Invalid recipient address format");
|
|
@@ -6043,15 +6354,17 @@ function createWithdrawCommand() {
|
|
|
6043
6354
|
}
|
|
6044
6355
|
const keypair = new Keypair(veilKey);
|
|
6045
6356
|
const rpcUrl = options.rpcUrl || process.env.RPC_URL;
|
|
6357
|
+
const pool = assetUpper.toLowerCase();
|
|
6046
6358
|
const onProgress = options.quiet ? void 0 : (stage, detail) => {
|
|
6047
6359
|
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
6048
6360
|
progress2(msg, options.quiet);
|
|
6049
6361
|
};
|
|
6050
|
-
progress2(
|
|
6362
|
+
progress2(`Starting ${assetUpper} withdrawal...`, options.quiet);
|
|
6051
6363
|
const result = await withdraw({
|
|
6052
6364
|
amount,
|
|
6053
6365
|
recipient,
|
|
6054
6366
|
keypair,
|
|
6367
|
+
pool,
|
|
6055
6368
|
rpcUrl,
|
|
6056
6369
|
onProgress
|
|
6057
6370
|
});
|
|
@@ -6060,6 +6373,7 @@ function createWithdrawCommand() {
|
|
|
6060
6373
|
success: result.success,
|
|
6061
6374
|
transactionHash: result.transactionHash,
|
|
6062
6375
|
blockNumber: result.blockNumber,
|
|
6376
|
+
asset: assetUpper,
|
|
6063
6377
|
amount: result.amount,
|
|
6064
6378
|
recipient: result.recipient
|
|
6065
6379
|
}, null, 2));
|
|
@@ -6125,12 +6439,12 @@ async function buildTransferProof(options) {
|
|
|
6125
6439
|
amount,
|
|
6126
6440
|
recipientAddress,
|
|
6127
6441
|
senderKeypair,
|
|
6442
|
+
pool = "eth",
|
|
6128
6443
|
rpcUrl,
|
|
6129
6444
|
onProgress
|
|
6130
6445
|
} = options;
|
|
6131
|
-
const
|
|
6132
|
-
const
|
|
6133
|
-
const poolAddress = addresses.ethPool;
|
|
6446
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
6447
|
+
const poolAddress = getPoolAddress(pool);
|
|
6134
6448
|
onProgress?.("Checking recipient registration...");
|
|
6135
6449
|
const { isRegistered: isRegistered2, depositKey } = await checkRecipientRegistration(
|
|
6136
6450
|
recipientAddress,
|
|
@@ -6142,6 +6456,7 @@ async function buildTransferProof(options) {
|
|
|
6142
6456
|
onProgress?.("Fetching your UTXOs...");
|
|
6143
6457
|
const balanceResult = await getPrivateBalance({
|
|
6144
6458
|
keypair: senderKeypair,
|
|
6459
|
+
pool,
|
|
6145
6460
|
rpcUrl,
|
|
6146
6461
|
onProgress
|
|
6147
6462
|
});
|
|
@@ -6222,12 +6537,12 @@ async function buildTransferProof(options) {
|
|
|
6222
6537
|
};
|
|
6223
6538
|
}
|
|
6224
6539
|
async function transfer(options) {
|
|
6225
|
-
const { amount, recipientAddress, onProgress } = options;
|
|
6540
|
+
const { amount, recipientAddress, pool = "eth", onProgress } = options;
|
|
6226
6541
|
const proof = await buildTransferProof(options);
|
|
6227
6542
|
onProgress?.("Submitting to relay...");
|
|
6228
6543
|
const relayResult = await submitRelay({
|
|
6229
6544
|
type: "transfer",
|
|
6230
|
-
pool
|
|
6545
|
+
pool,
|
|
6231
6546
|
proofArgs: proof.proofArgs,
|
|
6232
6547
|
extData: proof.extData,
|
|
6233
6548
|
metadata: {
|
|
@@ -6246,13 +6561,13 @@ async function transfer(options) {
|
|
|
6246
6561
|
};
|
|
6247
6562
|
}
|
|
6248
6563
|
async function mergeUtxos(options) {
|
|
6249
|
-
const { amount, keypair, rpcUrl, onProgress } = options;
|
|
6250
|
-
const
|
|
6251
|
-
const
|
|
6252
|
-
const poolAddress = addresses.ethPool;
|
|
6564
|
+
const { amount, keypair, pool = "eth", rpcUrl, onProgress } = options;
|
|
6565
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
6566
|
+
const poolAddress = getPoolAddress(pool);
|
|
6253
6567
|
onProgress?.("Fetching your UTXOs...");
|
|
6254
6568
|
const balanceResult = await getPrivateBalance({
|
|
6255
6569
|
keypair,
|
|
6570
|
+
pool,
|
|
6256
6571
|
rpcUrl,
|
|
6257
6572
|
onProgress
|
|
6258
6573
|
});
|
|
@@ -6319,7 +6634,7 @@ async function mergeUtxos(options) {
|
|
|
6319
6634
|
onProgress?.("Submitting to relay...");
|
|
6320
6635
|
const relayResult = await submitRelay({
|
|
6321
6636
|
type: "transfer",
|
|
6322
|
-
pool
|
|
6637
|
+
pool,
|
|
6323
6638
|
proofArgs: {
|
|
6324
6639
|
proof: result.args.proof,
|
|
6325
6640
|
root: result.args.root,
|
|
@@ -6345,16 +6660,18 @@ async function mergeUtxos(options) {
|
|
|
6345
6660
|
}
|
|
6346
6661
|
|
|
6347
6662
|
// src/cli/commands/transfer.ts
|
|
6663
|
+
var SUPPORTED_ASSETS3 = ["ETH", "USDC"];
|
|
6348
6664
|
function progress3(msg, quiet) {
|
|
6349
6665
|
if (!quiet) {
|
|
6350
6666
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
6351
6667
|
}
|
|
6352
6668
|
}
|
|
6353
6669
|
function createTransferCommand() {
|
|
6354
|
-
const transferCmd = new Command("transfer").description("Transfer privately within the pool to another registered address").argument("<asset>", "Asset to transfer (ETH)").argument("<amount>", "Amount to transfer (e.g., 0.1)").argument("<recipient>", "Recipient address (must be registered)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (asset, amount, recipient, options) => {
|
|
6670
|
+
const transferCmd = new Command("transfer").description("Transfer privately within the pool to another registered address").argument("<asset>", "Asset to transfer (ETH or USDC)").argument("<amount>", "Amount to transfer (e.g., 0.1)").argument("<recipient>", "Recipient address (must be registered)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (asset, amount, recipient, options) => {
|
|
6355
6671
|
try {
|
|
6356
|
-
|
|
6357
|
-
|
|
6672
|
+
const assetUpper = asset.toUpperCase();
|
|
6673
|
+
if (!SUPPORTED_ASSETS3.includes(assetUpper)) {
|
|
6674
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported asset: ${asset}. Supported: ${SUPPORTED_ASSETS3.join(", ")}`);
|
|
6358
6675
|
}
|
|
6359
6676
|
if (!/^0x[a-fA-F0-9]{40}$/.test(recipient)) {
|
|
6360
6677
|
throw new CLIError(ErrorCode.INVALID_ADDRESS, "Invalid recipient address format");
|
|
@@ -6365,15 +6682,17 @@ function createTransferCommand() {
|
|
|
6365
6682
|
}
|
|
6366
6683
|
const senderKeypair = new Keypair(veilKey);
|
|
6367
6684
|
const rpcUrl = options.rpcUrl || process.env.RPC_URL;
|
|
6685
|
+
const pool = assetUpper.toLowerCase();
|
|
6368
6686
|
const onProgress = options.quiet ? void 0 : (stage, detail) => {
|
|
6369
6687
|
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
6370
6688
|
progress3(msg, options.quiet);
|
|
6371
6689
|
};
|
|
6372
|
-
progress3(
|
|
6690
|
+
progress3(`Starting ${assetUpper} transfer...`, options.quiet);
|
|
6373
6691
|
const result = await transfer({
|
|
6374
6692
|
amount,
|
|
6375
6693
|
recipientAddress: recipient,
|
|
6376
6694
|
senderKeypair,
|
|
6695
|
+
pool,
|
|
6377
6696
|
rpcUrl,
|
|
6378
6697
|
onProgress
|
|
6379
6698
|
});
|
|
@@ -6382,6 +6701,7 @@ function createTransferCommand() {
|
|
|
6382
6701
|
success: result.success,
|
|
6383
6702
|
transactionHash: result.transactionHash,
|
|
6384
6703
|
blockNumber: result.blockNumber,
|
|
6704
|
+
asset: assetUpper,
|
|
6385
6705
|
amount: result.amount,
|
|
6386
6706
|
recipient: result.recipient,
|
|
6387
6707
|
type: "transfer"
|
|
@@ -6395,10 +6715,11 @@ function createTransferCommand() {
|
|
|
6395
6715
|
return transferCmd;
|
|
6396
6716
|
}
|
|
6397
6717
|
function createMergeCommand() {
|
|
6398
|
-
const mergeCmd = new Command("merge").description("Merge UTXOs by self-transfer (consolidate small UTXOs)").argument("<asset>", "Asset to merge (ETH)").argument("<amount>", "Amount to merge (e.g., 0.5)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (asset, amount, options) => {
|
|
6718
|
+
const mergeCmd = new Command("merge").description("Merge UTXOs by self-transfer (consolidate small UTXOs)").argument("<asset>", "Asset to merge (ETH or USDC)").argument("<amount>", "Amount to merge (e.g., 0.5)").option("--veil-key <key>", "Veil private key (or set VEIL_KEY env)").option("--rpc-url <url>", "RPC URL (or set RPC_URL env)").option("--quiet", "Suppress progress output").action(async (asset, amount, options) => {
|
|
6399
6719
|
try {
|
|
6400
|
-
|
|
6401
|
-
|
|
6720
|
+
const assetUpper = asset.toUpperCase();
|
|
6721
|
+
if (!SUPPORTED_ASSETS3.includes(assetUpper)) {
|
|
6722
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported asset: ${asset}. Supported: ${SUPPORTED_ASSETS3.join(", ")}`);
|
|
6402
6723
|
}
|
|
6403
6724
|
const veilKey = options.veilKey || process.env.VEIL_KEY;
|
|
6404
6725
|
if (!veilKey) {
|
|
@@ -6406,14 +6727,16 @@ function createMergeCommand() {
|
|
|
6406
6727
|
}
|
|
6407
6728
|
const keypair = new Keypair(veilKey);
|
|
6408
6729
|
const rpcUrl = options.rpcUrl || process.env.RPC_URL;
|
|
6730
|
+
const pool = assetUpper.toLowerCase();
|
|
6409
6731
|
const onProgress = options.quiet ? void 0 : (stage, detail) => {
|
|
6410
6732
|
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
6411
6733
|
progress3(msg, options.quiet);
|
|
6412
6734
|
};
|
|
6413
|
-
progress3(
|
|
6735
|
+
progress3(`Starting ${assetUpper} merge (self-transfer)...`, options.quiet);
|
|
6414
6736
|
const result = await mergeUtxos({
|
|
6415
6737
|
amount,
|
|
6416
6738
|
keypair,
|
|
6739
|
+
pool,
|
|
6417
6740
|
rpcUrl,
|
|
6418
6741
|
onProgress
|
|
6419
6742
|
});
|
|
@@ -6422,6 +6745,7 @@ function createMergeCommand() {
|
|
|
6422
6745
|
success: result.success,
|
|
6423
6746
|
transactionHash: result.transactionHash,
|
|
6424
6747
|
blockNumber: result.blockNumber,
|
|
6748
|
+
asset: assetUpper,
|
|
6425
6749
|
amount: result.amount,
|
|
6426
6750
|
type: "merge"
|
|
6427
6751
|
}, null, 2));
|
|
@@ -6506,7 +6830,7 @@ function createStatusCommand() {
|
|
|
6506
6830
|
// src/cli/index.ts
|
|
6507
6831
|
loadEnv();
|
|
6508
6832
|
var program2 = new Command();
|
|
6509
|
-
program2.name("veil").description("CLI for Veil Cash privacy pools on Base").version("0.
|
|
6833
|
+
program2.name("veil").description("CLI for Veil Cash privacy pools on Base").version("0.3.0");
|
|
6510
6834
|
program2.addCommand(createInitCommand());
|
|
6511
6835
|
program2.addCommand(createKeypairCommand());
|
|
6512
6836
|
program2.addCommand(createRegisterCommand());
|