@veil-cash/sdk 0.2.0 → 0.3.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 +218 -41
- package/dist/cli/index.cjs +507 -130
- package/dist/index.cjs +214 -30
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +172 -4
- package/dist/index.d.ts +172 -4
- package/dist/index.js +210 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/abi.ts +30 -0
- package/src/addresses.ts +40 -1
- package/src/balance.ts +22 -15
- package/src/cli/commands/balance.ts +114 -54
- package/src/cli/commands/deposit.ts +76 -33
- package/src/cli/commands/init.ts +45 -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 +106 -1
- package/src/index.ts +8 -2
- package/src/keypair.ts +79 -0
- package/src/relay.ts +2 -2
- package/src/transfer.ts +14 -11
- package/src/types.ts +9 -2
- 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,11 +4229,33 @@ 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 derivationLabel = options.signMessage ? "Derived Veil keypair from wallet signature" : options.signature ? "Derived Veil keypair from provided signature" : "Generated new Veil keypair";
|
|
4171
4257
|
if (options.json) {
|
|
4172
|
-
const kp2 =
|
|
4258
|
+
const kp2 = await createKp();
|
|
4173
4259
|
console.log(JSON.stringify({
|
|
4174
4260
|
veilKey: kp2.privkey,
|
|
4175
4261
|
depositKey: kp2.depositKey()
|
|
@@ -4178,15 +4264,17 @@ function createInitCommand() {
|
|
|
4178
4264
|
return;
|
|
4179
4265
|
}
|
|
4180
4266
|
if (!options.save) {
|
|
4181
|
-
const kp2 =
|
|
4182
|
-
console.log(
|
|
4267
|
+
const kp2 = await createKp();
|
|
4268
|
+
console.log(`
|
|
4269
|
+
${derivationLabel}:
|
|
4270
|
+
`);
|
|
4183
4271
|
console.log("Veil Private Key:");
|
|
4184
4272
|
console.log(` ${kp2.privkey}
|
|
4185
4273
|
`);
|
|
4186
4274
|
console.log("Deposit Key (register this on-chain):");
|
|
4187
4275
|
console.log(` ${kp2.depositKey()}
|
|
4188
4276
|
`);
|
|
4189
|
-
console.log("(Not saved -
|
|
4277
|
+
console.log("(Not saved - run without --no-save to save to .env.veil)");
|
|
4190
4278
|
process.exit(0);
|
|
4191
4279
|
return;
|
|
4192
4280
|
}
|
|
@@ -4201,8 +4289,10 @@ WARNING: A Veil key already exists in ${envPath}`);
|
|
|
4201
4289
|
return;
|
|
4202
4290
|
}
|
|
4203
4291
|
}
|
|
4204
|
-
const kp =
|
|
4205
|
-
console.log(
|
|
4292
|
+
const kp = await createKp();
|
|
4293
|
+
console.log(`
|
|
4294
|
+
${derivationLabel}:
|
|
4295
|
+
`);
|
|
4206
4296
|
console.log("Veil Private Key:");
|
|
4207
4297
|
console.log(` ${kp.privkey}
|
|
4208
4298
|
`);
|
|
@@ -4245,15 +4335,61 @@ var ADDRESSES = {
|
|
|
4245
4335
|
usdcPool: "0x5c50d58E49C59d112680c187De2Bf989d2a91242",
|
|
4246
4336
|
usdcQueue: "0x5530241b24504bF05C9a22e95A1F5458888e6a9B",
|
|
4247
4337
|
usdcToken: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
4338
|
+
cbbtcPool: "0x51A021da774b4bBB59B47f7CB4ccd631337680BA",
|
|
4339
|
+
cbbtcQueue: "0x977741CaDF8D1431c4816C0993D32b02094cD35C",
|
|
4340
|
+
cbbtcToken: "0xcbB7C0000aB88B473b1f5aFd9ef808440eed33Bf",
|
|
4248
4341
|
chainId: 8453,
|
|
4249
4342
|
relayUrl: "https://veil-relay.up.railway.app"
|
|
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
|
+
cbbtc: {
|
|
4358
|
+
decimals: 8,
|
|
4359
|
+
displayDecimals: 6,
|
|
4360
|
+
symbol: "cbBTC",
|
|
4361
|
+
name: "Coinbase Bitcoin"
|
|
4362
|
+
}
|
|
4363
|
+
};
|
|
4254
4364
|
function getAddresses() {
|
|
4255
4365
|
return ADDRESSES;
|
|
4256
4366
|
}
|
|
4367
|
+
function getPoolAddress(pool) {
|
|
4368
|
+
const addresses = getAddresses();
|
|
4369
|
+
switch (pool) {
|
|
4370
|
+
case "eth":
|
|
4371
|
+
return addresses.ethPool;
|
|
4372
|
+
case "usdc":
|
|
4373
|
+
return addresses.usdcPool;
|
|
4374
|
+
case "cbbtc":
|
|
4375
|
+
return addresses.cbbtcPool;
|
|
4376
|
+
default:
|
|
4377
|
+
throw new Error(`Unknown pool: ${pool}`);
|
|
4378
|
+
}
|
|
4379
|
+
}
|
|
4380
|
+
function getQueueAddress(pool) {
|
|
4381
|
+
const addresses = getAddresses();
|
|
4382
|
+
switch (pool) {
|
|
4383
|
+
case "eth":
|
|
4384
|
+
return addresses.ethQueue;
|
|
4385
|
+
case "usdc":
|
|
4386
|
+
return addresses.usdcQueue;
|
|
4387
|
+
case "cbbtc":
|
|
4388
|
+
return addresses.cbbtcQueue;
|
|
4389
|
+
default:
|
|
4390
|
+
throw new Error(`Unknown pool: ${pool}`);
|
|
4391
|
+
}
|
|
4392
|
+
}
|
|
4257
4393
|
function getRelayUrl() {
|
|
4258
4394
|
return ADDRESSES.relayUrl;
|
|
4259
4395
|
}
|
|
@@ -4315,6 +4451,23 @@ var ENTRY_ABI = [
|
|
|
4315
4451
|
stateMutability: "nonpayable",
|
|
4316
4452
|
type: "function"
|
|
4317
4453
|
},
|
|
4454
|
+
// Change deposit key (must already be registered)
|
|
4455
|
+
{
|
|
4456
|
+
inputs: [
|
|
4457
|
+
{
|
|
4458
|
+
components: [
|
|
4459
|
+
{ name: "owner", type: "address" },
|
|
4460
|
+
{ name: "depositKey", type: "bytes" }
|
|
4461
|
+
],
|
|
4462
|
+
name: "_account",
|
|
4463
|
+
type: "tuple"
|
|
4464
|
+
}
|
|
4465
|
+
],
|
|
4466
|
+
name: "changeDepositKey",
|
|
4467
|
+
outputs: [],
|
|
4468
|
+
stateMutability: "nonpayable",
|
|
4469
|
+
type: "function"
|
|
4470
|
+
},
|
|
4318
4471
|
// Queue ETH deposit
|
|
4319
4472
|
{
|
|
4320
4473
|
inputs: [{ name: "_depositKey", type: "bytes" }],
|
|
@@ -4334,6 +4487,17 @@ var ENTRY_ABI = [
|
|
|
4334
4487
|
stateMutability: "nonpayable",
|
|
4335
4488
|
type: "function"
|
|
4336
4489
|
},
|
|
4490
|
+
// Queue cbBTC deposit
|
|
4491
|
+
{
|
|
4492
|
+
inputs: [
|
|
4493
|
+
{ name: "_amount", type: "uint256" },
|
|
4494
|
+
{ name: "_depositKey", type: "bytes" }
|
|
4495
|
+
],
|
|
4496
|
+
name: "queueBTC",
|
|
4497
|
+
outputs: [],
|
|
4498
|
+
stateMutability: "nonpayable",
|
|
4499
|
+
type: "function"
|
|
4500
|
+
},
|
|
4337
4501
|
// Read deposit keys
|
|
4338
4502
|
{
|
|
4339
4503
|
inputs: [{ name: "", type: "address" }],
|
|
@@ -4828,6 +4992,35 @@ var POOL_ABI = [
|
|
|
4828
4992
|
// ============ RECEIVE ============
|
|
4829
4993
|
{ stateMutability: "payable", type: "receive" }
|
|
4830
4994
|
];
|
|
4995
|
+
var ERC20_ABI = [
|
|
4996
|
+
{
|
|
4997
|
+
inputs: [
|
|
4998
|
+
{ name: "spender", type: "address" },
|
|
4999
|
+
{ name: "amount", type: "uint256" }
|
|
5000
|
+
],
|
|
5001
|
+
name: "approve",
|
|
5002
|
+
outputs: [{ name: "", type: "bool" }],
|
|
5003
|
+
stateMutability: "nonpayable",
|
|
5004
|
+
type: "function"
|
|
5005
|
+
},
|
|
5006
|
+
{
|
|
5007
|
+
inputs: [{ name: "account", type: "address" }],
|
|
5008
|
+
name: "balanceOf",
|
|
5009
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
5010
|
+
stateMutability: "view",
|
|
5011
|
+
type: "function"
|
|
5012
|
+
},
|
|
5013
|
+
{
|
|
5014
|
+
inputs: [
|
|
5015
|
+
{ name: "owner", type: "address" },
|
|
5016
|
+
{ name: "spender", type: "address" }
|
|
5017
|
+
],
|
|
5018
|
+
name: "allowance",
|
|
5019
|
+
outputs: [{ name: "", type: "uint256" }],
|
|
5020
|
+
stateMutability: "view",
|
|
5021
|
+
type: "function"
|
|
5022
|
+
}
|
|
5023
|
+
];
|
|
4831
5024
|
|
|
4832
5025
|
// src/deposit.ts
|
|
4833
5026
|
function buildRegisterTx(depositKey, ownerAddress) {
|
|
@@ -4845,6 +5038,21 @@ function buildRegisterTx(depositKey, ownerAddress) {
|
|
|
4845
5038
|
data
|
|
4846
5039
|
};
|
|
4847
5040
|
}
|
|
5041
|
+
function buildChangeDepositKeyTx(depositKey, ownerAddress) {
|
|
5042
|
+
const addresses = getAddresses();
|
|
5043
|
+
const data = viem.encodeFunctionData({
|
|
5044
|
+
abi: ENTRY_ABI,
|
|
5045
|
+
functionName: "changeDepositKey",
|
|
5046
|
+
args: [{
|
|
5047
|
+
owner: ownerAddress,
|
|
5048
|
+
depositKey
|
|
5049
|
+
}]
|
|
5050
|
+
});
|
|
5051
|
+
return {
|
|
5052
|
+
to: addresses.entry,
|
|
5053
|
+
data
|
|
5054
|
+
};
|
|
5055
|
+
}
|
|
4848
5056
|
function buildDepositETHTx(options) {
|
|
4849
5057
|
const { depositKey, amount } = options;
|
|
4850
5058
|
const addresses = getAddresses();
|
|
@@ -4860,6 +5068,62 @@ function buildDepositETHTx(options) {
|
|
|
4860
5068
|
value
|
|
4861
5069
|
};
|
|
4862
5070
|
}
|
|
5071
|
+
function buildApproveUSDCTx(options) {
|
|
5072
|
+
const { amount } = options;
|
|
5073
|
+
const addresses = getAddresses();
|
|
5074
|
+
const amountWei = viem.parseUnits(amount, POOL_CONFIG.usdc.decimals);
|
|
5075
|
+
const data = viem.encodeFunctionData({
|
|
5076
|
+
abi: ERC20_ABI,
|
|
5077
|
+
functionName: "approve",
|
|
5078
|
+
args: [addresses.entry, amountWei]
|
|
5079
|
+
});
|
|
5080
|
+
return {
|
|
5081
|
+
to: addresses.usdcToken,
|
|
5082
|
+
data
|
|
5083
|
+
};
|
|
5084
|
+
}
|
|
5085
|
+
function buildDepositUSDCTx(options) {
|
|
5086
|
+
const { depositKey, amount } = options;
|
|
5087
|
+
const addresses = getAddresses();
|
|
5088
|
+
const amountWei = viem.parseUnits(amount, POOL_CONFIG.usdc.decimals);
|
|
5089
|
+
const data = viem.encodeFunctionData({
|
|
5090
|
+
abi: ENTRY_ABI,
|
|
5091
|
+
functionName: "queueUSDC",
|
|
5092
|
+
args: [amountWei, depositKey]
|
|
5093
|
+
});
|
|
5094
|
+
return {
|
|
5095
|
+
to: addresses.entry,
|
|
5096
|
+
data
|
|
5097
|
+
};
|
|
5098
|
+
}
|
|
5099
|
+
function buildApproveCBBTCTx(options) {
|
|
5100
|
+
const { amount } = options;
|
|
5101
|
+
const addresses = getAddresses();
|
|
5102
|
+
const amountWei = viem.parseUnits(amount, POOL_CONFIG.cbbtc.decimals);
|
|
5103
|
+
const data = viem.encodeFunctionData({
|
|
5104
|
+
abi: ERC20_ABI,
|
|
5105
|
+
functionName: "approve",
|
|
5106
|
+
args: [addresses.entry, amountWei]
|
|
5107
|
+
});
|
|
5108
|
+
return {
|
|
5109
|
+
to: addresses.cbbtcToken,
|
|
5110
|
+
data
|
|
5111
|
+
};
|
|
5112
|
+
}
|
|
5113
|
+
function buildDepositCBBTCTx(options) {
|
|
5114
|
+
const { depositKey, amount } = options;
|
|
5115
|
+
const addresses = getAddresses();
|
|
5116
|
+
const amountWei = viem.parseUnits(amount, POOL_CONFIG.cbbtc.decimals);
|
|
5117
|
+
const data = viem.encodeFunctionData({
|
|
5118
|
+
abi: ENTRY_ABI,
|
|
5119
|
+
functionName: "queueBTC",
|
|
5120
|
+
args: [amountWei, depositKey]
|
|
5121
|
+
});
|
|
5122
|
+
return {
|
|
5123
|
+
to: addresses.entry,
|
|
5124
|
+
data
|
|
5125
|
+
};
|
|
5126
|
+
}
|
|
4863
5127
|
function createWallet(config) {
|
|
4864
5128
|
const { privateKey, rpcUrl } = config;
|
|
4865
5129
|
const account = accounts.privateKeyToAccount(privateKey);
|
|
@@ -5076,7 +5340,7 @@ function handleCLIError(error) {
|
|
|
5076
5340
|
|
|
5077
5341
|
// src/cli/commands/register.ts
|
|
5078
5342
|
function createRegisterCommand() {
|
|
5079
|
-
const register = new Command("register").description("Register your deposit key on-chain
|
|
5343
|
+
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
5344
|
const jsonOutput = options.json;
|
|
5081
5345
|
try {
|
|
5082
5346
|
const depositKey = options.depositKey || process.env.DEPOSIT_KEY;
|
|
@@ -5094,8 +5358,9 @@ function createRegisterCommand() {
|
|
|
5094
5358
|
}
|
|
5095
5359
|
address2 = getAddress(walletKey);
|
|
5096
5360
|
}
|
|
5097
|
-
const tx2 = buildRegisterTx(depositKey, address2);
|
|
5361
|
+
const tx2 = options.force ? buildChangeDepositKeyTx(depositKey, address2) : buildRegisterTx(depositKey, address2);
|
|
5098
5362
|
const payload = {
|
|
5363
|
+
action: options.force ? "changeDepositKey" : "register",
|
|
5099
5364
|
to: tx2.to,
|
|
5100
5365
|
data: tx2.data,
|
|
5101
5366
|
value: "0",
|
|
@@ -5109,43 +5374,69 @@ function createRegisterCommand() {
|
|
|
5109
5374
|
const address = getAddress(config.privateKey);
|
|
5110
5375
|
if (!jsonOutput) console.log("\nChecking registration status...");
|
|
5111
5376
|
const { registered, depositKey: existingKey } = await isRegistered(address, config.rpcUrl);
|
|
5112
|
-
|
|
5377
|
+
const keysMatch = registered && existingKey === depositKey;
|
|
5378
|
+
const isChange = registered && !keysMatch;
|
|
5379
|
+
if (registered && keysMatch) {
|
|
5113
5380
|
if (jsonOutput) {
|
|
5114
5381
|
console.log(JSON.stringify({
|
|
5115
5382
|
success: true,
|
|
5116
5383
|
alreadyRegistered: true,
|
|
5384
|
+
keysMatch: true,
|
|
5117
5385
|
address,
|
|
5118
5386
|
depositKey: existingKey
|
|
5119
5387
|
}, null, 2));
|
|
5120
5388
|
} else {
|
|
5121
5389
|
console.log(`
|
|
5122
|
-
Address ${address} is already registered.`);
|
|
5390
|
+
Address ${address} is already registered with this deposit key.`);
|
|
5123
5391
|
console.log(`
|
|
5124
|
-
|
|
5125
|
-
console.log(` ${existingKey}`);
|
|
5392
|
+
Deposit key: ${existingKey.slice(0, 40)}...`);
|
|
5126
5393
|
}
|
|
5127
5394
|
process.exit(0);
|
|
5128
5395
|
return;
|
|
5129
5396
|
}
|
|
5397
|
+
if (isChange && !options.force) {
|
|
5398
|
+
if (jsonOutput) {
|
|
5399
|
+
console.log(JSON.stringify({
|
|
5400
|
+
success: false,
|
|
5401
|
+
alreadyRegistered: true,
|
|
5402
|
+
keysMatch: false,
|
|
5403
|
+
address,
|
|
5404
|
+
onChainKey: existingKey,
|
|
5405
|
+
localKey: depositKey.slice(0, 40) + "...",
|
|
5406
|
+
hint: "Use --force to change deposit key"
|
|
5407
|
+
}, null, 2));
|
|
5408
|
+
} else {
|
|
5409
|
+
console.log(`
|
|
5410
|
+
Address ${address} is already registered with a different deposit key.`);
|
|
5411
|
+
console.log(`
|
|
5412
|
+
On-chain key: ${existingKey.slice(0, 40)}...`);
|
|
5413
|
+
console.log(` Local key: ${depositKey.slice(0, 40)}...`);
|
|
5414
|
+
console.log(`
|
|
5415
|
+
Use --force to change your deposit key on-chain.`);
|
|
5416
|
+
}
|
|
5417
|
+
process.exit(1);
|
|
5418
|
+
return;
|
|
5419
|
+
}
|
|
5420
|
+
const action = isChange ? "Changing deposit key" : "Registering deposit key";
|
|
5130
5421
|
if (!jsonOutput) {
|
|
5131
|
-
console.log(
|
|
5422
|
+
console.log(`${action}...`);
|
|
5132
5423
|
console.log(` Address: ${address}`);
|
|
5133
5424
|
console.log(` Deposit Key: ${depositKey.slice(0, 40)}...`);
|
|
5134
5425
|
}
|
|
5135
|
-
const tx = buildRegisterTx(depositKey, address);
|
|
5426
|
+
const tx = isChange ? buildChangeDepositKeyTx(depositKey, address) : buildRegisterTx(depositKey, address);
|
|
5136
5427
|
const result = await sendTransaction(config, tx);
|
|
5137
5428
|
if (result.receipt.status === "success") {
|
|
5138
5429
|
if (jsonOutput) {
|
|
5139
5430
|
console.log(JSON.stringify({
|
|
5140
5431
|
success: true,
|
|
5141
|
-
|
|
5432
|
+
action: isChange ? "changed" : "registered",
|
|
5142
5433
|
address,
|
|
5143
5434
|
transactionHash: result.hash,
|
|
5144
5435
|
blockNumber: result.receipt.blockNumber.toString(),
|
|
5145
5436
|
gasUsed: result.receipt.gasUsed.toString()
|
|
5146
5437
|
}, null, 2));
|
|
5147
5438
|
} else {
|
|
5148
|
-
console.log("\nRegistration successful!");
|
|
5439
|
+
console.log(isChange ? "\nDeposit key changed successfully!" : "\nRegistration successful!");
|
|
5149
5440
|
console.log(` Transaction: ${result.hash}`);
|
|
5150
5441
|
console.log(` Block: ${result.receipt.blockNumber}`);
|
|
5151
5442
|
console.log(` Gas used: ${result.receipt.gasUsed}`);
|
|
@@ -5161,25 +5452,36 @@ Existing deposit key:`);
|
|
|
5161
5452
|
});
|
|
5162
5453
|
return register;
|
|
5163
5454
|
}
|
|
5164
|
-
var MINIMUM_DEPOSIT_ETH = 0.01;
|
|
5165
5455
|
var DEPOSIT_FEE_PERCENT = 0.3;
|
|
5166
|
-
var
|
|
5456
|
+
var MINIMUM_DEPOSITS = {
|
|
5457
|
+
ETH: 0.01,
|
|
5458
|
+
USDC: 10,
|
|
5459
|
+
CBBTC: 1e-4
|
|
5460
|
+
};
|
|
5461
|
+
function getMinimumWithFee(asset) {
|
|
5462
|
+
const min = MINIMUM_DEPOSITS[asset] || 0;
|
|
5463
|
+
return min / (1 - DEPOSIT_FEE_PERCENT / 100);
|
|
5464
|
+
}
|
|
5465
|
+
var SUPPORTED_ASSETS = ["ETH", "USDC", "CBBTC"];
|
|
5167
5466
|
function progress(msg, quiet) {
|
|
5168
5467
|
if (!quiet) {
|
|
5169
5468
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
5170
5469
|
}
|
|
5171
5470
|
}
|
|
5172
5471
|
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) => {
|
|
5472
|
+
const deposit = new Command("deposit").description("Deposit ETH, USDC, or cbBTC into Veil").argument("<asset>", "Asset to deposit (ETH, USDC, or CBBTC)").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
5473
|
try {
|
|
5175
|
-
|
|
5176
|
-
|
|
5474
|
+
const assetUpper = asset.toUpperCase();
|
|
5475
|
+
if (!SUPPORTED_ASSETS.includes(assetUpper)) {
|
|
5476
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported asset: ${asset}. Supported: ${SUPPORTED_ASSETS.join(", ")}`);
|
|
5177
5477
|
}
|
|
5178
5478
|
const amountNum = parseFloat(amount);
|
|
5179
|
-
|
|
5479
|
+
const minimumWithFee = getMinimumWithFee(assetUpper);
|
|
5480
|
+
const minimumNet = MINIMUM_DEPOSITS[assetUpper];
|
|
5481
|
+
if (amountNum < minimumWithFee) {
|
|
5180
5482
|
throw new CLIError(
|
|
5181
5483
|
ErrorCode.INVALID_AMOUNT,
|
|
5182
|
-
`Minimum deposit is ${
|
|
5484
|
+
`Minimum deposit is ${minimumNet} ${assetUpper} (net). With ${DEPOSIT_FEE_PERCENT}% fee, send at least ${minimumWithFee.toFixed(assetUpper === "ETH" ? 5 : 8)} ${assetUpper}.`
|
|
5183
5485
|
);
|
|
5184
5486
|
}
|
|
5185
5487
|
const depositKey = options.depositKey || process.env.DEPOSIT_KEY;
|
|
@@ -5187,38 +5489,62 @@ function createDepositCommand() {
|
|
|
5187
5489
|
throw new CLIError(ErrorCode.DEPOSIT_KEY_MISSING, "Deposit key required. Use --deposit-key or set DEPOSIT_KEY in .env (run: veil init)");
|
|
5188
5490
|
}
|
|
5189
5491
|
progress("Building transaction...", options.quiet);
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5492
|
+
let tx;
|
|
5493
|
+
let approveTx = null;
|
|
5494
|
+
if (assetUpper === "USDC") {
|
|
5495
|
+
approveTx = buildApproveUSDCTx({ amount });
|
|
5496
|
+
tx = buildDepositUSDCTx({ depositKey, amount });
|
|
5497
|
+
} else if (assetUpper === "CBBTC") {
|
|
5498
|
+
approveTx = buildApproveCBBTCTx({ amount });
|
|
5499
|
+
tx = buildDepositCBBTCTx({ depositKey, amount });
|
|
5500
|
+
} else {
|
|
5501
|
+
tx = buildDepositETHTx({ depositKey, amount });
|
|
5502
|
+
}
|
|
5194
5503
|
if (options.unsigned) {
|
|
5195
5504
|
progress("", options.quiet);
|
|
5196
|
-
const
|
|
5505
|
+
const payloads = [];
|
|
5506
|
+
if (approveTx) {
|
|
5507
|
+
payloads.push({
|
|
5508
|
+
step: "approve",
|
|
5509
|
+
to: approveTx.to,
|
|
5510
|
+
data: approveTx.data,
|
|
5511
|
+
value: "0",
|
|
5512
|
+
chainId: 8453
|
|
5513
|
+
});
|
|
5514
|
+
}
|
|
5515
|
+
payloads.push({
|
|
5516
|
+
step: "deposit",
|
|
5197
5517
|
to: tx.to,
|
|
5198
5518
|
data: tx.data,
|
|
5199
5519
|
value: tx.value ? tx.value.toString() : "0",
|
|
5200
5520
|
chainId: 8453
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
console.log(JSON.stringify(payload, null, 2));
|
|
5521
|
+
});
|
|
5522
|
+
console.log(JSON.stringify(payloads.length === 1 ? payloads[0] : payloads, null, 2));
|
|
5204
5523
|
return;
|
|
5205
5524
|
}
|
|
5206
5525
|
const config = getConfig(options);
|
|
5207
5526
|
const address = getAddress(config.privateKey);
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5527
|
+
if (assetUpper === "ETH") {
|
|
5528
|
+
progress("Checking balance...", options.quiet);
|
|
5529
|
+
const balance = await getBalance(address, config.rpcUrl);
|
|
5530
|
+
const amountWei = viem.parseEther(amount);
|
|
5531
|
+
if (balance < amountWei) {
|
|
5532
|
+
progress("", options.quiet);
|
|
5533
|
+
throw new CLIError(ErrorCode.INSUFFICIENT_BALANCE, `Insufficient ETH balance. Have: ${viem.formatEther(balance)} ETH, Need: ${amount} ETH`);
|
|
5534
|
+
}
|
|
5535
|
+
}
|
|
5536
|
+
if (approveTx) {
|
|
5537
|
+
progress(`Approving ${assetUpper}...`, options.quiet);
|
|
5538
|
+
await sendTransaction(config, approveTx);
|
|
5214
5539
|
}
|
|
5215
|
-
progress("Sending transaction...", options.quiet);
|
|
5540
|
+
progress("Sending deposit transaction...", options.quiet);
|
|
5216
5541
|
const result = await sendTransaction(config, tx);
|
|
5217
5542
|
progress("Confirming...", options.quiet);
|
|
5218
5543
|
progress("", options.quiet);
|
|
5219
5544
|
console.log(JSON.stringify({
|
|
5220
5545
|
success: result.receipt.status === "success",
|
|
5221
5546
|
hash: result.hash,
|
|
5547
|
+
asset: assetUpper,
|
|
5222
5548
|
amount,
|
|
5223
5549
|
blockNumber: result.receipt.blockNumber.toString(),
|
|
5224
5550
|
gasUsed: result.receipt.gasUsed.toString()
|
|
@@ -5315,15 +5641,16 @@ var DEPOSIT_STATUS_MAP = {
|
|
|
5315
5641
|
3: "refunded"
|
|
5316
5642
|
};
|
|
5317
5643
|
async function getQueueBalance(options) {
|
|
5318
|
-
const { address, rpcUrl, onProgress } = options;
|
|
5319
|
-
const
|
|
5644
|
+
const { address, pool = "eth", rpcUrl, onProgress } = options;
|
|
5645
|
+
const queueAddress = getQueueAddress(pool);
|
|
5646
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
5320
5647
|
const publicClient = viem.createPublicClient({
|
|
5321
5648
|
chain: chains.base,
|
|
5322
5649
|
transport: viem.http(rpcUrl)
|
|
5323
5650
|
});
|
|
5324
5651
|
onProgress?.("Fetching pending deposits...");
|
|
5325
5652
|
const pendingNonces = await publicClient.readContract({
|
|
5326
|
-
address:
|
|
5653
|
+
address: queueAddress,
|
|
5327
5654
|
abi: QUEUE_ABI,
|
|
5328
5655
|
functionName: "getPendingDeposits"
|
|
5329
5656
|
});
|
|
@@ -5334,7 +5661,7 @@ async function getQueueBalance(options) {
|
|
|
5334
5661
|
const nonce = pendingNonces[i];
|
|
5335
5662
|
onProgress?.("Checking deposit", `${i + 1}/${pendingNonces.length}`);
|
|
5336
5663
|
const deposit = await publicClient.readContract({
|
|
5337
|
-
address:
|
|
5664
|
+
address: queueAddress,
|
|
5338
5665
|
abi: QUEUE_ABI,
|
|
5339
5666
|
functionName: "getDeposit",
|
|
5340
5667
|
args: [nonce]
|
|
@@ -5344,7 +5671,7 @@ async function getQueueBalance(options) {
|
|
|
5344
5671
|
pendingDeposits.push({
|
|
5345
5672
|
nonce: nonce.toString(),
|
|
5346
5673
|
status: DEPOSIT_STATUS_MAP[deposit.status] || "pending",
|
|
5347
|
-
amount: viem.
|
|
5674
|
+
amount: viem.formatUnits(deposit.amountIn, poolConfig.decimals),
|
|
5348
5675
|
amountWei: deposit.amountIn.toString(),
|
|
5349
5676
|
timestamp: new Date(Number(deposit.timestamp) * 1e3).toISOString()
|
|
5350
5677
|
});
|
|
@@ -5355,15 +5682,16 @@ async function getQueueBalance(options) {
|
|
|
5355
5682
|
}
|
|
5356
5683
|
return {
|
|
5357
5684
|
address,
|
|
5358
|
-
queueBalance: viem.
|
|
5685
|
+
queueBalance: viem.formatUnits(totalQueueBalance, poolConfig.decimals),
|
|
5359
5686
|
queueBalanceWei: totalQueueBalance.toString(),
|
|
5360
5687
|
pendingDeposits,
|
|
5361
5688
|
pendingCount: pendingDeposits.length
|
|
5362
5689
|
};
|
|
5363
5690
|
}
|
|
5364
5691
|
async function getPrivateBalance(options) {
|
|
5365
|
-
const { keypair, rpcUrl, onProgress } = options;
|
|
5366
|
-
const
|
|
5692
|
+
const { keypair, pool = "eth", rpcUrl, onProgress } = options;
|
|
5693
|
+
const poolAddress = getPoolAddress(pool);
|
|
5694
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
5367
5695
|
if (!keypair.privkey) {
|
|
5368
5696
|
throw new Error("Keypair must have a private key to calculate private balance");
|
|
5369
5697
|
}
|
|
@@ -5373,7 +5701,7 @@ async function getPrivateBalance(options) {
|
|
|
5373
5701
|
});
|
|
5374
5702
|
onProgress?.("Fetching pool index...");
|
|
5375
5703
|
const nextIndex = await publicClient.readContract({
|
|
5376
|
-
address:
|
|
5704
|
+
address: poolAddress,
|
|
5377
5705
|
abi: POOL_ABI,
|
|
5378
5706
|
functionName: "nextIndex"
|
|
5379
5707
|
});
|
|
@@ -5396,7 +5724,7 @@ async function getPrivateBalance(options) {
|
|
|
5396
5724
|
const batchNum = Math.floor(start / BATCH_SIZE) + 1;
|
|
5397
5725
|
onProgress?.("Fetching encrypted outputs", `batch ${batchNum}/${totalBatches} (${start}-${end})`);
|
|
5398
5726
|
const batch = await publicClient.readContract({
|
|
5399
|
-
address:
|
|
5727
|
+
address: poolAddress,
|
|
5400
5728
|
abi: POOL_ABI,
|
|
5401
5729
|
functionName: "getEncryptedOutputs",
|
|
5402
5730
|
args: [BigInt(start), BigInt(end)]
|
|
@@ -5426,14 +5754,14 @@ async function getPrivateBalance(options) {
|
|
|
5426
5754
|
const nullifier = utxo.getNullifier();
|
|
5427
5755
|
const nullifierHex = toFixedHex(nullifier);
|
|
5428
5756
|
const isSpent = await publicClient.readContract({
|
|
5429
|
-
address:
|
|
5757
|
+
address: poolAddress,
|
|
5430
5758
|
abi: POOL_ABI,
|
|
5431
5759
|
functionName: "isSpent",
|
|
5432
5760
|
args: [nullifierHex]
|
|
5433
5761
|
});
|
|
5434
5762
|
utxoInfos.push({
|
|
5435
5763
|
index,
|
|
5436
|
-
amount: viem.
|
|
5764
|
+
amount: viem.formatUnits(utxo.amount, poolConfig.decimals),
|
|
5437
5765
|
amountWei: utxo.amount.toString(),
|
|
5438
5766
|
isSpent
|
|
5439
5767
|
});
|
|
@@ -5445,7 +5773,7 @@ async function getPrivateBalance(options) {
|
|
|
5445
5773
|
}
|
|
5446
5774
|
}
|
|
5447
5775
|
return {
|
|
5448
|
-
privateBalance: viem.
|
|
5776
|
+
privateBalance: viem.formatUnits(totalBalance, poolConfig.decimals),
|
|
5449
5777
|
privateBalanceWei: totalBalance.toString(),
|
|
5450
5778
|
utxoCount: decryptedUtxos.length,
|
|
5451
5779
|
spentCount,
|
|
@@ -5453,9 +5781,62 @@ async function getPrivateBalance(options) {
|
|
|
5453
5781
|
utxos: utxoInfos
|
|
5454
5782
|
};
|
|
5455
5783
|
}
|
|
5784
|
+
var SUPPORTED_POOLS = ["eth", "usdc", "cbbtc"];
|
|
5785
|
+
async function fetchPoolBalance(pool, address, keypair, rpcUrl, onProgress) {
|
|
5786
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
5787
|
+
const poolProgress = onProgress ? (stage, detail) => onProgress(`[${pool.toUpperCase()}] ${stage}`, detail) : void 0;
|
|
5788
|
+
const queueResult = await getQueueBalance({ address, pool, rpcUrl, onProgress: poolProgress });
|
|
5789
|
+
let privateResult = null;
|
|
5790
|
+
if (keypair) {
|
|
5791
|
+
privateResult = await getPrivateBalance({ keypair, pool, rpcUrl, onProgress: poolProgress });
|
|
5792
|
+
}
|
|
5793
|
+
const queueBalanceWei = BigInt(queueResult.queueBalanceWei);
|
|
5794
|
+
const privateBalanceWei = privateResult ? BigInt(privateResult.privateBalanceWei) : 0n;
|
|
5795
|
+
const totalBalanceWei = queueBalanceWei + privateBalanceWei;
|
|
5796
|
+
const result = {
|
|
5797
|
+
pool: pool.toUpperCase(),
|
|
5798
|
+
symbol: poolConfig.symbol,
|
|
5799
|
+
totalBalance: viem.formatUnits(totalBalanceWei, poolConfig.decimals),
|
|
5800
|
+
totalBalanceWei: totalBalanceWei.toString()
|
|
5801
|
+
};
|
|
5802
|
+
if (privateResult) {
|
|
5803
|
+
const unspentUtxos = privateResult.utxos.filter((u) => !u.isSpent);
|
|
5804
|
+
result.private = {
|
|
5805
|
+
balance: privateResult.privateBalance,
|
|
5806
|
+
balanceWei: privateResult.privateBalanceWei,
|
|
5807
|
+
utxoCount: privateResult.unspentCount,
|
|
5808
|
+
utxos: unspentUtxos.map((u) => ({
|
|
5809
|
+
index: u.index,
|
|
5810
|
+
amount: u.amount
|
|
5811
|
+
}))
|
|
5812
|
+
};
|
|
5813
|
+
} else {
|
|
5814
|
+
result.private = {
|
|
5815
|
+
balance: null,
|
|
5816
|
+
note: "Set VEIL_KEY to see private balance"
|
|
5817
|
+
};
|
|
5818
|
+
}
|
|
5819
|
+
result.queue = {
|
|
5820
|
+
balance: queueResult.queueBalance,
|
|
5821
|
+
balanceWei: queueResult.queueBalanceWei,
|
|
5822
|
+
count: queueResult.pendingCount,
|
|
5823
|
+
deposits: queueResult.pendingDeposits.map((d) => ({
|
|
5824
|
+
nonce: d.nonce,
|
|
5825
|
+
amount: d.amount,
|
|
5826
|
+
status: d.status,
|
|
5827
|
+
timestamp: d.timestamp
|
|
5828
|
+
}))
|
|
5829
|
+
};
|
|
5830
|
+
return result;
|
|
5831
|
+
}
|
|
5456
5832
|
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) => {
|
|
5833
|
+
const balance = new Command("balance").description("Show queue and private balances (all pools by default)").option("--pool <pool>", "Pool to check (eth, usdc, cbbtc, 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
5834
|
try {
|
|
5835
|
+
const poolArg = (options.pool || "all").toLowerCase();
|
|
5836
|
+
if (poolArg !== "all" && !SUPPORTED_POOLS.includes(poolArg)) {
|
|
5837
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported pool: ${options.pool}. Supported: ${SUPPORTED_POOLS.join(", ")}, all`);
|
|
5838
|
+
}
|
|
5839
|
+
const poolsToQuery = poolArg === "all" ? [...SUPPORTED_POOLS] : [poolArg];
|
|
5459
5840
|
let address;
|
|
5460
5841
|
if (options.address) {
|
|
5461
5842
|
address = options.address;
|
|
@@ -5473,51 +5854,28 @@ function createBalanceCommand() {
|
|
|
5473
5854
|
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
5474
5855
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
5475
5856
|
};
|
|
5476
|
-
const
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5857
|
+
const depositKey = process.env.DEPOSIT_KEY || (keypair ? keypair.depositKey() : null);
|
|
5858
|
+
if (poolsToQuery.length === 1) {
|
|
5859
|
+
const poolResult = await fetchPoolBalance(poolsToQuery[0], address, keypair, rpcUrl, onProgress);
|
|
5860
|
+
if (!options.quiet) process.stderr.write("\r\x1B[K");
|
|
5861
|
+
const output2 = {
|
|
5862
|
+
address,
|
|
5863
|
+
depositKey: depositKey || null,
|
|
5864
|
+
...poolResult
|
|
5865
|
+
};
|
|
5866
|
+
console.log(JSON.stringify(output2, null, 2));
|
|
5867
|
+
return;
|
|
5480
5868
|
}
|
|
5481
|
-
|
|
5482
|
-
|
|
5869
|
+
const pools = [];
|
|
5870
|
+
for (const pool of poolsToQuery) {
|
|
5871
|
+
const poolResult = await fetchPoolBalance(pool, address, keypair, rpcUrl, onProgress);
|
|
5872
|
+
pools.push(poolResult);
|
|
5483
5873
|
}
|
|
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);
|
|
5874
|
+
if (!options.quiet) process.stderr.write("\r\x1B[K");
|
|
5488
5875
|
const output = {
|
|
5489
5876
|
address,
|
|
5490
5877
|
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
|
-
}))
|
|
5878
|
+
pools
|
|
5521
5879
|
};
|
|
5522
5880
|
console.log(JSON.stringify(output, null, 2));
|
|
5523
5881
|
} catch (error) {
|
|
@@ -5530,8 +5888,9 @@ function createBalanceCommand() {
|
|
|
5530
5888
|
|
|
5531
5889
|
// src/cli/commands/queue-balance.ts
|
|
5532
5890
|
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) => {
|
|
5891
|
+
const balance = new Command("queue-balance").description("Show queue balance and pending deposits").option("--pool <pool>", "Pool to check (eth, usdc, or cbbtc)", "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
5892
|
try {
|
|
5893
|
+
const pool = (options.pool || "eth").toLowerCase();
|
|
5535
5894
|
let address;
|
|
5536
5895
|
if (options.address) {
|
|
5537
5896
|
address = options.address;
|
|
@@ -5547,7 +5906,7 @@ function createQueueBalanceCommand() {
|
|
|
5547
5906
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
5548
5907
|
};
|
|
5549
5908
|
const rpcUrl = options.rpcUrl || process.env.RPC_URL;
|
|
5550
|
-
const result = await getQueueBalance({ address, rpcUrl, onProgress });
|
|
5909
|
+
const result = await getQueueBalance({ address, pool, rpcUrl, onProgress });
|
|
5551
5910
|
if (!options.quiet) {
|
|
5552
5911
|
process.stderr.write("\r\x1B[K");
|
|
5553
5912
|
}
|
|
@@ -5564,8 +5923,9 @@ function createQueueBalanceCommand() {
|
|
|
5564
5923
|
|
|
5565
5924
|
// src/cli/commands/private-balance.ts
|
|
5566
5925
|
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) => {
|
|
5926
|
+
const privateBalance = new Command("private-balance").description("Show private balance (requires VEIL_KEY)").option("--pool <pool>", "Pool to check (eth, usdc, or cbbtc)", "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
5927
|
try {
|
|
5928
|
+
const pool = (options.pool || "eth").toLowerCase();
|
|
5569
5929
|
const veilKey = options.veilKey || process.env.VEIL_KEY;
|
|
5570
5930
|
if (!veilKey) {
|
|
5571
5931
|
throw new Error("Must provide --veil-key or set VEIL_KEY env");
|
|
@@ -5576,11 +5936,12 @@ function createPrivateBalanceCommand() {
|
|
|
5576
5936
|
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
5577
5937
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
5578
5938
|
};
|
|
5579
|
-
const result = await getPrivateBalance({ keypair, rpcUrl, onProgress });
|
|
5939
|
+
const result = await getPrivateBalance({ keypair, pool, rpcUrl, onProgress });
|
|
5580
5940
|
if (!options.quiet) {
|
|
5581
5941
|
process.stderr.write("\r\x1B[K");
|
|
5582
5942
|
}
|
|
5583
5943
|
const output = {
|
|
5944
|
+
pool: pool.toUpperCase(),
|
|
5584
5945
|
privateBalance: result.privateBalance,
|
|
5585
5946
|
privateBalanceWei: result.privateBalanceWei,
|
|
5586
5947
|
utxoCount: result.utxoCount,
|
|
@@ -5818,8 +6179,8 @@ async function submitRelay(options) {
|
|
|
5818
6179
|
if (type !== "withdraw" && type !== "transfer") {
|
|
5819
6180
|
throw new RelayError('Invalid type. Must be "withdraw" or "transfer"', 400);
|
|
5820
6181
|
}
|
|
5821
|
-
if (pool !== "eth" && pool !== "usdc") {
|
|
5822
|
-
throw new RelayError('Invalid pool. Must be "eth" or "
|
|
6182
|
+
if (pool !== "eth" && pool !== "usdc" && pool !== "cbbtc") {
|
|
6183
|
+
throw new RelayError('Invalid pool. Must be "eth", "usdc", or "cbbtc"', 400);
|
|
5823
6184
|
}
|
|
5824
6185
|
if (!proofArgs || !extData) {
|
|
5825
6186
|
throw new RelayError("Missing proofArgs or extData", 400);
|
|
@@ -5916,15 +6277,16 @@ async function buildWithdrawProof(options) {
|
|
|
5916
6277
|
amount,
|
|
5917
6278
|
recipient,
|
|
5918
6279
|
keypair,
|
|
6280
|
+
pool = "eth",
|
|
5919
6281
|
rpcUrl,
|
|
5920
6282
|
onProgress
|
|
5921
6283
|
} = options;
|
|
5922
|
-
const
|
|
5923
|
-
const
|
|
5924
|
-
const poolAddress = addresses.ethPool;
|
|
6284
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
6285
|
+
const poolAddress = getPoolAddress(pool);
|
|
5925
6286
|
onProgress?.("Fetching your UTXOs...");
|
|
5926
6287
|
const balanceResult = await getPrivateBalance({
|
|
5927
6288
|
keypair,
|
|
6289
|
+
pool,
|
|
5928
6290
|
rpcUrl,
|
|
5929
6291
|
onProgress
|
|
5930
6292
|
});
|
|
@@ -5998,12 +6360,12 @@ async function buildWithdrawProof(options) {
|
|
|
5998
6360
|
};
|
|
5999
6361
|
}
|
|
6000
6362
|
async function withdraw(options) {
|
|
6001
|
-
const { amount, recipient, onProgress } = options;
|
|
6363
|
+
const { amount, recipient, pool = "eth", onProgress } = options;
|
|
6002
6364
|
const proof = await buildWithdrawProof(options);
|
|
6003
6365
|
onProgress?.("Submitting to relay...");
|
|
6004
6366
|
const relayResult = await submitRelay({
|
|
6005
6367
|
type: "withdraw",
|
|
6006
|
-
pool
|
|
6368
|
+
pool,
|
|
6007
6369
|
proofArgs: proof.proofArgs,
|
|
6008
6370
|
extData: proof.extData,
|
|
6009
6371
|
metadata: {
|
|
@@ -6023,16 +6385,18 @@ async function withdraw(options) {
|
|
|
6023
6385
|
}
|
|
6024
6386
|
|
|
6025
6387
|
// src/cli/commands/withdraw.ts
|
|
6388
|
+
var SUPPORTED_ASSETS2 = ["ETH", "USDC", "CBBTC"];
|
|
6026
6389
|
function progress2(msg, quiet) {
|
|
6027
6390
|
if (!quiet) {
|
|
6028
6391
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
6029
6392
|
}
|
|
6030
6393
|
}
|
|
6031
6394
|
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) => {
|
|
6395
|
+
const withdrawCmd = new Command("withdraw").description("Withdraw from private pool to a public address").argument("<asset>", "Asset to withdraw (ETH, USDC, or CBBTC)").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
6396
|
try {
|
|
6034
|
-
|
|
6035
|
-
|
|
6397
|
+
const assetUpper = asset.toUpperCase();
|
|
6398
|
+
if (!SUPPORTED_ASSETS2.includes(assetUpper)) {
|
|
6399
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported asset: ${asset}. Supported: ${SUPPORTED_ASSETS2.join(", ")}`);
|
|
6036
6400
|
}
|
|
6037
6401
|
if (!/^0x[a-fA-F0-9]{40}$/.test(recipient)) {
|
|
6038
6402
|
throw new CLIError(ErrorCode.INVALID_ADDRESS, "Invalid recipient address format");
|
|
@@ -6043,15 +6407,17 @@ function createWithdrawCommand() {
|
|
|
6043
6407
|
}
|
|
6044
6408
|
const keypair = new Keypair(veilKey);
|
|
6045
6409
|
const rpcUrl = options.rpcUrl || process.env.RPC_URL;
|
|
6410
|
+
const pool = assetUpper.toLowerCase();
|
|
6046
6411
|
const onProgress = options.quiet ? void 0 : (stage, detail) => {
|
|
6047
6412
|
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
6048
6413
|
progress2(msg, options.quiet);
|
|
6049
6414
|
};
|
|
6050
|
-
progress2(
|
|
6415
|
+
progress2(`Starting ${assetUpper} withdrawal...`, options.quiet);
|
|
6051
6416
|
const result = await withdraw({
|
|
6052
6417
|
amount,
|
|
6053
6418
|
recipient,
|
|
6054
6419
|
keypair,
|
|
6420
|
+
pool,
|
|
6055
6421
|
rpcUrl,
|
|
6056
6422
|
onProgress
|
|
6057
6423
|
});
|
|
@@ -6060,6 +6426,7 @@ function createWithdrawCommand() {
|
|
|
6060
6426
|
success: result.success,
|
|
6061
6427
|
transactionHash: result.transactionHash,
|
|
6062
6428
|
blockNumber: result.blockNumber,
|
|
6429
|
+
asset: assetUpper,
|
|
6063
6430
|
amount: result.amount,
|
|
6064
6431
|
recipient: result.recipient
|
|
6065
6432
|
}, null, 2));
|
|
@@ -6125,12 +6492,12 @@ async function buildTransferProof(options) {
|
|
|
6125
6492
|
amount,
|
|
6126
6493
|
recipientAddress,
|
|
6127
6494
|
senderKeypair,
|
|
6495
|
+
pool = "eth",
|
|
6128
6496
|
rpcUrl,
|
|
6129
6497
|
onProgress
|
|
6130
6498
|
} = options;
|
|
6131
|
-
const
|
|
6132
|
-
const
|
|
6133
|
-
const poolAddress = addresses.ethPool;
|
|
6499
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
6500
|
+
const poolAddress = getPoolAddress(pool);
|
|
6134
6501
|
onProgress?.("Checking recipient registration...");
|
|
6135
6502
|
const { isRegistered: isRegistered2, depositKey } = await checkRecipientRegistration(
|
|
6136
6503
|
recipientAddress,
|
|
@@ -6142,6 +6509,7 @@ async function buildTransferProof(options) {
|
|
|
6142
6509
|
onProgress?.("Fetching your UTXOs...");
|
|
6143
6510
|
const balanceResult = await getPrivateBalance({
|
|
6144
6511
|
keypair: senderKeypair,
|
|
6512
|
+
pool,
|
|
6145
6513
|
rpcUrl,
|
|
6146
6514
|
onProgress
|
|
6147
6515
|
});
|
|
@@ -6222,12 +6590,12 @@ async function buildTransferProof(options) {
|
|
|
6222
6590
|
};
|
|
6223
6591
|
}
|
|
6224
6592
|
async function transfer(options) {
|
|
6225
|
-
const { amount, recipientAddress, onProgress } = options;
|
|
6593
|
+
const { amount, recipientAddress, pool = "eth", onProgress } = options;
|
|
6226
6594
|
const proof = await buildTransferProof(options);
|
|
6227
6595
|
onProgress?.("Submitting to relay...");
|
|
6228
6596
|
const relayResult = await submitRelay({
|
|
6229
6597
|
type: "transfer",
|
|
6230
|
-
pool
|
|
6598
|
+
pool,
|
|
6231
6599
|
proofArgs: proof.proofArgs,
|
|
6232
6600
|
extData: proof.extData,
|
|
6233
6601
|
metadata: {
|
|
@@ -6246,13 +6614,13 @@ async function transfer(options) {
|
|
|
6246
6614
|
};
|
|
6247
6615
|
}
|
|
6248
6616
|
async function mergeUtxos(options) {
|
|
6249
|
-
const { amount, keypair, rpcUrl, onProgress } = options;
|
|
6250
|
-
const
|
|
6251
|
-
const
|
|
6252
|
-
const poolAddress = addresses.ethPool;
|
|
6617
|
+
const { amount, keypair, pool = "eth", rpcUrl, onProgress } = options;
|
|
6618
|
+
const poolConfig = POOL_CONFIG[pool];
|
|
6619
|
+
const poolAddress = getPoolAddress(pool);
|
|
6253
6620
|
onProgress?.("Fetching your UTXOs...");
|
|
6254
6621
|
const balanceResult = await getPrivateBalance({
|
|
6255
6622
|
keypair,
|
|
6623
|
+
pool,
|
|
6256
6624
|
rpcUrl,
|
|
6257
6625
|
onProgress
|
|
6258
6626
|
});
|
|
@@ -6319,7 +6687,7 @@ async function mergeUtxos(options) {
|
|
|
6319
6687
|
onProgress?.("Submitting to relay...");
|
|
6320
6688
|
const relayResult = await submitRelay({
|
|
6321
6689
|
type: "transfer",
|
|
6322
|
-
pool
|
|
6690
|
+
pool,
|
|
6323
6691
|
proofArgs: {
|
|
6324
6692
|
proof: result.args.proof,
|
|
6325
6693
|
root: result.args.root,
|
|
@@ -6345,16 +6713,18 @@ async function mergeUtxos(options) {
|
|
|
6345
6713
|
}
|
|
6346
6714
|
|
|
6347
6715
|
// src/cli/commands/transfer.ts
|
|
6716
|
+
var SUPPORTED_ASSETS3 = ["ETH", "USDC", "CBBTC"];
|
|
6348
6717
|
function progress3(msg, quiet) {
|
|
6349
6718
|
if (!quiet) {
|
|
6350
6719
|
process.stderr.write(`\r\x1B[K${msg}`);
|
|
6351
6720
|
}
|
|
6352
6721
|
}
|
|
6353
6722
|
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) => {
|
|
6723
|
+
const transferCmd = new Command("transfer").description("Transfer privately within the pool to another registered address").argument("<asset>", "Asset to transfer (ETH, USDC, or CBBTC)").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
6724
|
try {
|
|
6356
|
-
|
|
6357
|
-
|
|
6725
|
+
const assetUpper = asset.toUpperCase();
|
|
6726
|
+
if (!SUPPORTED_ASSETS3.includes(assetUpper)) {
|
|
6727
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported asset: ${asset}. Supported: ${SUPPORTED_ASSETS3.join(", ")}`);
|
|
6358
6728
|
}
|
|
6359
6729
|
if (!/^0x[a-fA-F0-9]{40}$/.test(recipient)) {
|
|
6360
6730
|
throw new CLIError(ErrorCode.INVALID_ADDRESS, "Invalid recipient address format");
|
|
@@ -6365,15 +6735,17 @@ function createTransferCommand() {
|
|
|
6365
6735
|
}
|
|
6366
6736
|
const senderKeypair = new Keypair(veilKey);
|
|
6367
6737
|
const rpcUrl = options.rpcUrl || process.env.RPC_URL;
|
|
6738
|
+
const pool = assetUpper.toLowerCase();
|
|
6368
6739
|
const onProgress = options.quiet ? void 0 : (stage, detail) => {
|
|
6369
6740
|
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
6370
6741
|
progress3(msg, options.quiet);
|
|
6371
6742
|
};
|
|
6372
|
-
progress3(
|
|
6743
|
+
progress3(`Starting ${assetUpper} transfer...`, options.quiet);
|
|
6373
6744
|
const result = await transfer({
|
|
6374
6745
|
amount,
|
|
6375
6746
|
recipientAddress: recipient,
|
|
6376
6747
|
senderKeypair,
|
|
6748
|
+
pool,
|
|
6377
6749
|
rpcUrl,
|
|
6378
6750
|
onProgress
|
|
6379
6751
|
});
|
|
@@ -6382,6 +6754,7 @@ function createTransferCommand() {
|
|
|
6382
6754
|
success: result.success,
|
|
6383
6755
|
transactionHash: result.transactionHash,
|
|
6384
6756
|
blockNumber: result.blockNumber,
|
|
6757
|
+
asset: assetUpper,
|
|
6385
6758
|
amount: result.amount,
|
|
6386
6759
|
recipient: result.recipient,
|
|
6387
6760
|
type: "transfer"
|
|
@@ -6395,10 +6768,11 @@ function createTransferCommand() {
|
|
|
6395
6768
|
return transferCmd;
|
|
6396
6769
|
}
|
|
6397
6770
|
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) => {
|
|
6771
|
+
const mergeCmd = new Command("merge").description("Merge UTXOs by self-transfer (consolidate small UTXOs)").argument("<asset>", "Asset to merge (ETH, USDC, or CBBTC)").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
6772
|
try {
|
|
6400
|
-
|
|
6401
|
-
|
|
6773
|
+
const assetUpper = asset.toUpperCase();
|
|
6774
|
+
if (!SUPPORTED_ASSETS3.includes(assetUpper)) {
|
|
6775
|
+
throw new CLIError(ErrorCode.INVALID_AMOUNT, `Unsupported asset: ${asset}. Supported: ${SUPPORTED_ASSETS3.join(", ")}`);
|
|
6402
6776
|
}
|
|
6403
6777
|
const veilKey = options.veilKey || process.env.VEIL_KEY;
|
|
6404
6778
|
if (!veilKey) {
|
|
@@ -6406,14 +6780,16 @@ function createMergeCommand() {
|
|
|
6406
6780
|
}
|
|
6407
6781
|
const keypair = new Keypair(veilKey);
|
|
6408
6782
|
const rpcUrl = options.rpcUrl || process.env.RPC_URL;
|
|
6783
|
+
const pool = assetUpper.toLowerCase();
|
|
6409
6784
|
const onProgress = options.quiet ? void 0 : (stage, detail) => {
|
|
6410
6785
|
const msg = detail ? `${stage}: ${detail}` : stage;
|
|
6411
6786
|
progress3(msg, options.quiet);
|
|
6412
6787
|
};
|
|
6413
|
-
progress3(
|
|
6788
|
+
progress3(`Starting ${assetUpper} merge (self-transfer)...`, options.quiet);
|
|
6414
6789
|
const result = await mergeUtxos({
|
|
6415
6790
|
amount,
|
|
6416
6791
|
keypair,
|
|
6792
|
+
pool,
|
|
6417
6793
|
rpcUrl,
|
|
6418
6794
|
onProgress
|
|
6419
6795
|
});
|
|
@@ -6422,6 +6798,7 @@ function createMergeCommand() {
|
|
|
6422
6798
|
success: result.success,
|
|
6423
6799
|
transactionHash: result.transactionHash,
|
|
6424
6800
|
blockNumber: result.blockNumber,
|
|
6801
|
+
asset: assetUpper,
|
|
6425
6802
|
amount: result.amount,
|
|
6426
6803
|
type: "merge"
|
|
6427
6804
|
}, null, 2));
|
|
@@ -6506,7 +6883,7 @@ function createStatusCommand() {
|
|
|
6506
6883
|
// src/cli/index.ts
|
|
6507
6884
|
loadEnv();
|
|
6508
6885
|
var program2 = new Command();
|
|
6509
|
-
program2.name("veil").description("CLI for Veil Cash privacy pools on Base").version("0.
|
|
6886
|
+
program2.name("veil").description("CLI for Veil Cash privacy pools on Base").version("0.3.0");
|
|
6510
6887
|
program2.addCommand(createInitCommand());
|
|
6511
6888
|
program2.addCommand(createKeypairCommand());
|
|
6512
6889
|
program2.addCommand(createRegisterCommand());
|