@sherwoodagent/cli 0.88.0 → 0.88.2
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/dist/{chunk-N2E2Q5GL.js → chunk-CWGP4VXZ.js} +3 -3
- package/dist/chunk-CWGP4VXZ.js.map +1 -0
- package/dist/index.js +73 -45
- package/dist/index.js.map +1 -1
- package/dist/{vault-WWGSRNRP.js → vault-E7XD6DLD.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-N2E2Q5GL.js.map +0 -1
- /package/dist/{vault-WWGSRNRP.js.map → vault-E7XD6DLD.js.map} +0 -0
|
@@ -39,10 +39,10 @@ function getVaultAddress() {
|
|
|
39
39
|
"Vault address not found. Pass --vault <addr> or run 'sherwood config set --vault <addr>'."
|
|
40
40
|
);
|
|
41
41
|
}
|
|
42
|
-
async function getAssetAddress() {
|
|
42
|
+
async function getAssetAddress(vault) {
|
|
43
43
|
const client = getPublicClient();
|
|
44
44
|
return client.readContract({
|
|
45
|
-
address: getVaultAddress(),
|
|
45
|
+
address: vault ?? getVaultAddress(),
|
|
46
46
|
abi: SYNDICATE_VAULT_ABI,
|
|
47
47
|
functionName: "asset"
|
|
48
48
|
});
|
|
@@ -557,4 +557,4 @@ export {
|
|
|
557
557
|
registerAgent,
|
|
558
558
|
getVaultInfo
|
|
559
559
|
};
|
|
560
|
-
//# sourceMappingURL=chunk-
|
|
560
|
+
//# sourceMappingURL=chunk-CWGP4VXZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/vault.ts"],"sourcesContent":["/**\n * SyndicateVault contract wrapper.\n *\n * The vault is the onchain identity — it holds all positions via delegatecall\n * to a shared BatchExecutorLib. No separate executor contract needed.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { formatUnits, parseAbiItem } from \"viem\";\nimport { getChain } from \"./network.js\";\nimport {\n getPublicClient,\n getAccount,\n getWalletClient,\n writeContractWithRetry,\n waitForReceipt,\n estimateGasCushion,\n GAS_UNITS,\n} from \"./client.js\";\nimport { SYNDICATE_VAULT_ABI, ERC20_ABI } from \"./abis.js\";\nimport { getLogsChunked } from \"./events.js\";\nimport { getChainContracts } from \"./config.js\";\nimport { TOKENS } from \"./addresses.js\";\n\n// Per-command override (set by --vault flag in index.ts)\nlet _vaultOverride: Address | null = null;\n\nexport function setVaultAddress(addr: Address): void {\n _vaultOverride = addr;\n}\n\nexport function getVaultAddress(): Address {\n // 1. Per-command override (--vault flag)\n if (_vaultOverride) return _vaultOverride;\n\n // 2. Config (~/.sherwood/config.json) — default vault\n const chainId = getChain().id;\n const fromConfig = getChainContracts(chainId).vault;\n if (fromConfig) return fromConfig as Address;\n\n throw new Error(\n \"Vault address not found. Pass --vault <addr> or run 'sherwood config set --vault <addr>'.\",\n );\n}\n\n// ── Asset Helpers ──\n\n/**\n * Read the vault's underlying ERC-20 asset address.\n */\n/**\n * The vault's underlying asset. Pass `vault` when the command took an explicit\n * `--vault` that was not installed as the process-wide override — otherwise\n * this falls back to the configured default vault.\n */\nexport async function getAssetAddress(vault?: Address): Promise<Address> {\n const client = getPublicClient();\n return client.readContract({\n address: vault ?? getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"asset\",\n }) as Promise<Address>;\n}\n\n/**\n * Read decimals from the vault's underlying asset.\n * Works with any ERC-20 (USDC=6, WETH=18, WBTC=8, etc.).\n */\nexport async function getAssetDecimals(): Promise<number> {\n const client = getPublicClient();\n const asset = await getAssetAddress();\n return client.readContract({\n address: asset,\n abi: ERC20_ABI,\n functionName: \"decimals\",\n }) as Promise<number>;\n}\n\n/**\n * Read the vault owner (OwnableUpgradeable).\n */\nexport async function getVaultOwner(vault?: Address): Promise<Address> {\n const client = getPublicClient();\n return client.readContract({\n address: vault ?? getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"owner\",\n }) as Promise<Address>;\n}\n\n/**\n * Read the vault's agent performance fee (basis points). Owner-set, default\n * 500 (5%). Snapshotted onto a proposal at propose time and clamped to the\n * governor's `maxPerformanceFeeBps` at settlement.\n */\nexport async function getAgentFeeBps(vault?: Address): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: vault ?? getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"agentFeeBps\",\n }) as Promise<bigint>;\n}\n\n/**\n * Set the vault's agent performance fee (basis points). Vault owner only;\n * reverts above 1500 (15%).\n */\nexport async function setAgentFeeBps(bps: bigint): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"setAgentFeeBps\",\n args: [bps],\n });\n await waitForReceipt(hash);\n return hash;\n}\n\n// ── WETH ABI (for auto-wrapping ETH) ──\n\nconst WETH_ABI = [\n {\n name: \"deposit\",\n type: \"function\",\n stateMutability: \"payable\",\n inputs: [],\n outputs: [],\n },\n] as const;\n\n// ── Pre-flight Checks ──\n\n/**\n * Validate that a deposit can succeed before submitting any transactions.\n * Throws descriptive errors if any pre-condition fails.\n */\nexport async function preflightDeposit(amount: bigint): Promise<void> {\n const client = getPublicClient();\n const vaultAddress = getVaultAddress();\n const account = getAccount();\n const asset = await getAssetAddress();\n const decimals = await getAssetDecimals();\n\n // 1. Check asset balance\n const balance = (await client.readContract({\n address: asset,\n abi: ERC20_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n\n if (balance < amount) {\n const symbol = (await client.readContract({\n address: asset,\n abi: ERC20_ABI,\n functionName: \"symbol\",\n })) as string;\n throw new Error(\n `Insufficient ${symbol}. Have ${formatUnits(balance, decimals)}, need ${formatUnits(amount, decimals)}.`,\n );\n }\n\n // 2. Check ETH for gas — cushion derived from live chain gas (approve +\n // deposit), floored per-chain. Never a fixed Base-calibrated constant: on a\n // ~14-wei-base-fee chain 0.0005 ETH was ~7 orders too high and rejected\n // valid deposits client-side.\n const ethBalance = await client.getBalance({ address: account.address });\n const minGas = await estimateGasCushion(GAS_UNITS.approve + GAS_UNITS.deposit);\n if (ethBalance < minGas) {\n throw new Error(\n `Insufficient ETH for gas. Have ${formatUnits(ethBalance, 18)} ETH, need at least ` +\n `${formatUnits(minGas, 18)} ETH. Top up your wallet with ETH on ${getChain().name}.`,\n );\n }\n\n // 3. Check vault not paused\n const paused = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"paused\",\n })) as boolean;\n if (paused) {\n throw new Error(\"Vault is paused — deposits are temporarily disabled.\");\n }\n\n // 4. Active proposal: deposits lock UNLESS Lane A (the V2 oracle instant\n // lane, PR #357) is live for the running strategy — then the vault accepts\n // instant entries up to maxDeposit. The old unconditional refusal made Lane\n // A unusable through the CLI (vnet e2e finding, issue #416).\n const locked = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"redemptionsLocked\",\n })) as boolean;\n if (locked) {\n const cap = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"maxDeposit\",\n args: [account.address],\n })) as bigint;\n if (cap < amount) {\n throw new Error(\n cap === 0n\n ? \"Deposits are locked while a strategy is executing (Lane A unavailable for this strategy). \" +\n \"Queue an async deposit instead:\\n sherwood queue request-deposit --vault <vault> --amount <usdc>\"\n : `Deposit exceeds the Lane A instant cap while a strategy is executing (maxDeposit ${cap.toString()} ` +\n `raw asset units, requested ${amount.toString()}). Reduce the amount or queue it:\\n` +\n \" sherwood queue request-deposit --vault <vault> --amount <usdc>\",\n );\n }\n }\n\n // 5. Check depositor approval (if whitelist vault)\n const openDeposits = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"openDeposits\",\n })) as boolean;\n if (!openDeposits) {\n const approved = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"isApprovedDepositor\",\n args: [account.address],\n })) as boolean;\n if (!approved) {\n throw new Error(\n \"Your address is not an approved depositor. Ask the vault creator to approve you:\\n sherwood fund approve-depositor --depositor \" +\n account.address,\n );\n }\n }\n}\n\n// ── LP Functions ──\n\n/**\n * Deposit into the vault with optional ETH auto-wrapping for WETH vaults.\n * When `useEth` is true and the vault asset is WETH, wraps ETH first.\n */\nexport async function depositWithEthWrap(amount: bigint): Promise<Hex> {\n const client = getPublicClient();\n const account = getAccount();\n const asset = await getAssetAddress();\n const wethAddress = TOKENS().WETH;\n\n if (asset.toLowerCase() !== wethAddress.toLowerCase()) {\n throw new Error(\"--use-eth is only supported for WETH vaults.\");\n }\n\n // Check current WETH balance — only wrap the shortfall\n const wethBalance = (await client.readContract({\n address: wethAddress,\n abi: ERC20_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n\n if (wethBalance < amount) {\n const shortfall = amount - wethBalance;\n\n // Verify sufficient ETH to cover shortfall + gas. The gas cushion is\n // derived from live chain gas (wrap + approve + deposit), floored per-chain\n // — not a fixed Base-calibrated constant that would reject valid low-fee\n // deposits (e.g. a 0.00058-ETH wallet wrapping 0.0005 on Robinhood testnet).\n const ethBalance = await client.getBalance({ address: account.address });\n const minGas = await estimateGasCushion(\n GAS_UNITS.wrap + GAS_UNITS.approve + GAS_UNITS.deposit,\n );\n if (ethBalance < shortfall + minGas) {\n throw new Error(\n `Insufficient ETH on ${getChain().name}. Have ${formatUnits(ethBalance, 18)} ETH, need ` +\n `${formatUnits(shortfall, 18)} to wrap + ~${formatUnits(minGas, 18)} for gas.`,\n );\n }\n\n // Wrap ETH → WETH\n const wallet = getWalletClient();\n const wrapHash = await wallet.writeContract({\n address: wethAddress,\n abi: WETH_ABI,\n functionName: \"deposit\",\n args: [],\n value: shortfall,\n account,\n chain: getChain(),\n });\n const wrapReceipt = await client.waitForTransactionReceipt({ hash: wrapHash });\n // A reverted wrap leaves WETH short; the downstream deposit would then\n // revert on transferFrom. Fail loudly here instead.\n if (wrapReceipt.status !== \"success\") {\n throw new Error(`ETH->WETH wrap reverted on-chain (tx ${wrapHash}).`);\n }\n }\n\n // Proceed with normal deposit\n return deposit(amount);\n}\n\n/**\n * Deposit into the vault. Handles approval + deposit for the vault's asset.\n */\nexport async function deposit(amount: bigint): Promise<Hex> {\n const client = getPublicClient();\n const vaultAddress = getVaultAddress();\n const account = getAccount();\n const asset = await getAssetAddress();\n\n // Check existing allowance — skip approve if sufficient\n const currentAllowance = (await client.readContract({\n address: asset,\n abi: ERC20_ABI,\n functionName: \"allowance\",\n args: [account.address, vaultAddress],\n })) as bigint;\n\n if (currentAllowance < amount) {\n const approveHash = await writeContractWithRetry({\n account,\n chain: getChain(),\n address: asset,\n abi: ERC20_ABI,\n functionName: \"approve\",\n args: [vaultAddress, amount],\n });\n // Wait for approve to confirm before deposit — prevents nonce collision\n const approveReceipt = await waitForReceipt(approveHash);\n // A reverted approve leaves allowance below `amount`; the deposit's\n // transferFrom would then revert. Surface it here.\n if (approveReceipt.status !== \"success\") {\n throw new Error(`Asset approve reverted on-chain (tx ${approveHash}).`);\n }\n }\n\n // Snapshot share balance before deposit so we can assert shares were minted.\n const sharesBefore = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n\n // Deposit — retry wrapper handles nonce/gas automatically\n const depositHash = await writeContractWithRetry({\n account,\n chain: getChain(),\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"deposit\",\n args: [amount, account.address],\n });\n const receipt = await waitForReceipt(depositHash);\n\n // A mined-but-reverted deposit is NOT a success. viem's\n // waitForTransactionReceipt resolves even for `status: \"reverted\"` txs, so\n // without this guard a reverted deposit would be reported as a successful\n // one and the caller would believe it holds shares it does not.\n if (receipt.status !== \"success\") {\n throw new Error(\n `Deposit transaction reverted on-chain (tx ${depositHash}). No shares were minted.`,\n );\n }\n\n // Confirm shares were actually minted to the receiver. Guards against a\n // silent zero-share mint (e.g. rounding on an inflated vault) that would\n // otherwise pass unnoticed because the tx did not revert.\n const sharesAfter = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n if (sharesAfter <= sharesBefore) {\n throw new Error(\n `Deposit confirmed on-chain (tx ${depositHash}) but minted 0 shares ` +\n `(balance ${sharesBefore} -> ${sharesAfter}). Aborting to avoid reporting a phantom deposit.`,\n );\n }\n\n return depositHash;\n}\n\n// ── Redeem ──\n\n/**\n * Pre-flight check for redeem. Validates that the caller has enough shares\n * and that the vault allows redemption right now.\n */\nexport async function preflightRedeem(shares: bigint): Promise<void> {\n const client = getPublicClient();\n const vaultAddress = getVaultAddress();\n const account = getAccount();\n\n if (shares === 0n) {\n throw new Error(\"No shares to redeem.\");\n }\n\n // 1. Check share balance\n const balance = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"balanceOf\",\n args: [account.address],\n })) as bigint;\n\n if (balance < shares) {\n throw new Error(\n `Insufficient shares. Have ${balance.toString()}, need ${shares.toString()}.`,\n );\n }\n\n // 2. Check vault not paused\n const paused = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"paused\",\n })) as boolean;\n if (paused) {\n throw new Error(\"Vault is paused — redemptions are temporarily disabled.\");\n }\n\n // 3. Active proposal: redemptions lock UNLESS Lane A (the V2 oracle instant\n // lane, PR #357) is live — then instant exits are allowed up to maxRedeem.\n // The old unconditional refusal made Lane A unusable through the CLI (vnet\n // e2e finding, issue #416).\n const locked = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"redemptionsLocked\",\n })) as boolean;\n if (locked) {\n const cap = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"maxRedeem\",\n args: [account.address],\n })) as bigint;\n if (cap < shares) {\n throw new Error(\n cap === 0n\n ? \"Redemptions are locked while a strategy is executing (Lane A unavailable for this strategy). \" +\n \"Queue an async redeem instead:\\n sherwood queue request-redeem --vault <vault> --shares <raw-shares>\"\n : `Redeem exceeds the Lane A instant cap while a strategy is executing (maxRedeem ${cap.toString()} ` +\n `raw shares, requested ${shares.toString()}). Reduce the share amount or queue it:\\n` +\n \" sherwood queue request-redeem --vault <vault> --shares <raw-shares>\",\n );\n }\n }\n\n // 4. Check ETH for gas — cushion derived from live chain gas (redeem),\n // floored per-chain; never a fixed Base-calibrated constant.\n const ethBalance = await client.getBalance({ address: account.address });\n const minGas = await estimateGasCushion(GAS_UNITS.redeem);\n if (ethBalance < minGas) {\n throw new Error(\n `Insufficient ETH for gas on ${getChain().name}. Have ${formatUnits(ethBalance, 18)} ETH, ` +\n `need at least ${formatUnits(minGas, 18)} ETH.`,\n );\n }\n}\n\n/**\n * Redeem shares for the underlying asset (standard ERC-4626 redeem).\n * Returns the tx hash and the assets received.\n */\nexport async function redeem(\n shares: bigint,\n receiver?: Address,\n): Promise<{ hash: Hex; assetsOut: bigint }> {\n const client = getPublicClient();\n const vaultAddress = getVaultAddress();\n const account = getAccount();\n const to = receiver ?? account.address;\n\n // Preview so we can report assets received\n const assetsOut = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"previewRedeem\",\n args: [shares],\n })) as bigint;\n\n const hash = await writeContractWithRetry({\n account,\n chain: getChain(),\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"redeem\",\n args: [shares, to, account.address],\n });\n await waitForReceipt(hash);\n return { hash, assetsOut };\n}\n\n/**\n * Read the current share balance for an address (defaults to the caller).\n */\nexport async function getShareBalance(address?: Address): Promise<bigint> {\n const client = getPublicClient();\n const owner = address ?? getAccount().address;\n return client.readContract({\n address: getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"balanceOf\",\n args: [owner],\n }) as Promise<bigint>;\n}\n\n// NOTE: there is deliberately NO `executeBatch` wrapper here. The vault's\n// owner-direct `executeBatch` was removed on-chain (V-C3) — the only batch\n// path is the governor-driven `executeGovernorBatch` (proposal lifecycle).\n\n// ── Agent Reads ──\n\n/** Mirrors SyndicateVault.MAX_PAGE_LIMIT — the hard clamp on page size. */\nconst AGENT_PAGE_LIMIT = 100n;\n\n/**\n * Read the full registered-agent set by iterating `agentsPaginated`\n * (the vault's `getAgentAddresses` was replaced by the paginated view, V-M3).\n * Starts at offset 0 and advances by the page limit until a short page.\n */\nexport async function getAgentAddresses(vault?: Address): Promise<Address[]> {\n const client = getPublicClient();\n const address = vault ?? getVaultAddress();\n const agents: Address[] = [];\n for (let offset = 0n; ; offset += AGENT_PAGE_LIMIT) {\n const page = (await client.readContract({\n address,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"agentsPaginated\",\n args: [offset, AGENT_PAGE_LIMIT],\n })) as Address[];\n agents.push(...page);\n if (BigInt(page.length) < AGENT_PAGE_LIMIT) break;\n }\n return agents;\n}\n\n// ── Principal (event-derived) ──\n\n/** ERC-4626 flow events scanned by getNetDeposited (parseAbiItem form for getLogs). */\nconst ERC4626_FLOW_EVENTS = [\n parseAbiItem(\n \"event Deposit(address indexed sender, address indexed owner, uint256 assets, uint256 shares)\",\n ),\n parseAbiItem(\n \"event Withdraw(address indexed sender, address indexed receiver, address indexed owner, uint256 assets, uint256 shares)\",\n ),\n] as const;\n\n/**\n * Net deposited principal, derived from the ERC-4626 event history:\n * sum(Deposit.assets) − sum(Withdraw.assets), floored at 0. Scanned 0→latest\n * through `getLogsChunked` (≤10,000 blocks per eth_getLogs, the lib/events.ts\n * precedent) so range-capped public RPCs neither error nor truncate on\n * long-lived vaults.\n *\n * DISPLAY-GRADE ESTIMATE ONLY — the vault's `totalDeposited` view was\n * removed on-chain (the V2 vault tracks no principal) and the event history\n * has hard blind spots, not just noise:\n * - Lane-B settlements (`settleDeposit` / `settleRedeem`) and\n * strategy-serviced custody flows (`strategyMint` / `strategyBurn`) use\n * raw `_mint`/`_burn` with NO ERC-4626 Deposit/Withdraw events — those\n * flows are entirely invisible to this estimate.\n * - Withdrawals include realized profit, so on a profitable vault the net\n * undershoots true remaining principal (and can go negative — hence the\n * floor).\n * Do not use as an accounting source of truth.\n */\nexport async function getNetDeposited(vault?: Address): Promise<bigint> {\n const client = getPublicClient();\n const address = vault ?? getVaultAddress();\n const toBlock = await client.getBlockNumber();\n const logs = await getLogsChunked({\n address,\n events: ERC4626_FLOW_EVENTS,\n fromBlock: 0n,\n toBlock,\n });\n let net = 0n;\n for (const log of logs) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const { eventName, args } = log as any;\n const assets: bigint = args?.assets ?? 0n;\n if (eventName === \"Deposit\") net += assets;\n else if (eventName === \"Withdraw\") net -= assets;\n }\n return net > 0n ? net : 0n;\n}\n\n// ── Depositor Management ──\n\n/**\n * Approve a depositor address (owner only).\n */\nexport async function approveDepositor(depositor: Address): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"approveDepositor\",\n args: [depositor],\n });\n await waitForReceipt(hash);\n return hash;\n}\n\n/**\n * Remove a depositor from the whitelist (owner only).\n */\nexport async function removeDepositor(depositor: Address): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"removeDepositor\",\n args: [depositor],\n });\n await waitForReceipt(hash);\n return hash;\n}\n\n/**\n * Approve multiple depositors in a batch (owner only).\n */\nexport async function approveDepositors(depositors: Address[]): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"approveDepositors\",\n args: [depositors],\n });\n await waitForReceipt(hash);\n return hash;\n}\n\n/**\n * Check if an address is a registered agent on the vault.\n */\nexport async function isAgent(agentAddress: Address): Promise<boolean> {\n const client = getPublicClient();\n return client.readContract({\n address: getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"isAgent\",\n args: [agentAddress],\n }) as Promise<boolean>;\n}\n\n/**\n * Check if an address is an approved depositor.\n */\nexport async function isApprovedDepositor(depositor: Address): Promise<boolean> {\n const client = getPublicClient();\n return client.readContract({\n address: getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"isApprovedDepositor\",\n args: [depositor],\n }) as Promise<boolean>;\n}\n\n/**\n * Get LP share balance and asset value.\n */\nexport async function getBalance(address?: Address): Promise<{\n shares: bigint;\n assetsValue: string;\n percentOfVault: string;\n}> {\n const client = getPublicClient();\n const vaultAddress = getVaultAddress();\n const account = address || getAccount().address;\n\n const [shares, totalSupply] = await Promise.all([\n client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"balanceOf\",\n args: [account],\n }) as Promise<bigint>,\n client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"totalSupply\",\n }) as Promise<bigint>,\n ]);\n\n let assetsValue = 0n;\n if (shares > 0n) {\n assetsValue = (await client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"convertToAssets\",\n args: [shares],\n })) as bigint;\n }\n\n const percent =\n totalSupply > 0n ? ((Number(shares) / Number(totalSupply)) * 100).toFixed(2) : \"0.00\";\n\n const decimals = await getAssetDecimals();\n\n return {\n shares,\n assetsValue: formatUnits(assetsValue, decimals),\n percentOfVault: `${percent}%`,\n };\n}\n\n// ── Agent Management ──\n\n/**\n * Register a new agent (owner only). Requires ERC-8004 agent identity.\n */\nexport async function registerAgent(\n agentId: bigint,\n agentAddress: Address,\n): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"registerAgent\",\n args: [agentId, agentAddress],\n });\n await waitForReceipt(hash);\n return hash;\n}\n\n// ── Views ──\n\nexport interface VaultInfo {\n address: Address;\n totalAssets: string;\n agentCount: bigint;\n redemptionsLocked: boolean;\n managementFeeBps: bigint;\n}\n\n/**\n * Get vault overview info.\n */\nexport async function getVaultInfo(): Promise<VaultInfo> {\n const client = getPublicClient();\n const vaultAddress = getVaultAddress();\n\n const [totalAssets, agentCount, redemptionsLocked, managementFeeBps, decimals] =\n await Promise.all([\n client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"totalAssets\",\n }) as Promise<bigint>,\n client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"getAgentCount\",\n }) as Promise<bigint>,\n client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"redemptionsLocked\",\n }) as Promise<boolean>,\n client.readContract({\n address: vaultAddress,\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"managementFeeBps\",\n }) as Promise<bigint>,\n getAssetDecimals(),\n ]);\n\n return {\n address: vaultAddress,\n totalAssets: formatUnits(totalAssets, decimals),\n agentCount,\n redemptionsLocked,\n managementFeeBps,\n };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -114,7 +114,7 @@ import {
|
|
|
114
114
|
removeDepositor,
|
|
115
115
|
setAgentFeeBps,
|
|
116
116
|
setVaultAddress
|
|
117
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-CWGP4VXZ.js";
|
|
118
118
|
import "./chunk-BH3VTJ4F.js";
|
|
119
119
|
import {
|
|
120
120
|
PROPOSAL_STATE,
|
|
@@ -1393,7 +1393,7 @@ function registerStrategyProposeCommands(strategy2) {
|
|
|
1393
1393
|
metadataURI = `data:application/json;base64,${Buffer.from(inline).toString("base64")}`;
|
|
1394
1394
|
}
|
|
1395
1395
|
try {
|
|
1396
|
-
const { getAgentFeeBps: getAgentFeeBps2 } = await import("./vault-
|
|
1396
|
+
const { getAgentFeeBps: getAgentFeeBps2 } = await import("./vault-E7XD6DLD.js");
|
|
1397
1397
|
const feeBps = await getAgentFeeBps2(vault);
|
|
1398
1398
|
console.log(
|
|
1399
1399
|
chalk3.yellow(
|
|
@@ -1638,7 +1638,7 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1638
1638
|
]);
|
|
1639
1639
|
const stateNames = ["Pending", "Executed", "Settled"];
|
|
1640
1640
|
const stateStr = stateNames[Number(stateRaw)] || `Unknown(${stateRaw})`;
|
|
1641
|
-
const [
|
|
1641
|
+
const [assetDecimals2, assetSymbol] = await Promise.all([
|
|
1642
1642
|
publicClient.readContract({ address: assetAddr, abi: erc20Abi3, functionName: "decimals" }),
|
|
1643
1643
|
publicClient.readContract({ address: assetAddr, abi: erc20Abi3, functionName: "symbol" })
|
|
1644
1644
|
]);
|
|
@@ -1673,19 +1673,19 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1673
1673
|
feeTier: feeTiers[i]
|
|
1674
1674
|
})),
|
|
1675
1675
|
asset: assetAddr,
|
|
1676
|
-
assetDecimals
|
|
1676
|
+
assetDecimals: assetDecimals2
|
|
1677
1677
|
});
|
|
1678
1678
|
priceSource = prices.find((p) => p !== null)?.source ?? null;
|
|
1679
1679
|
} catch {
|
|
1680
1680
|
}
|
|
1681
1681
|
const pricesAvailable = prices.some((p) => p !== null);
|
|
1682
|
-
const assetBalanceNum = Number(formatUnits5(assetBalance,
|
|
1682
|
+
const assetBalanceNum = Number(formatUnits5(assetBalance, assetDecimals2));
|
|
1683
1683
|
let totalPortfolioValue = assetBalanceNum;
|
|
1684
1684
|
let totalInvested = 0n;
|
|
1685
1685
|
const allocStatuses = allocations.map((alloc, i) => {
|
|
1686
1686
|
const [balance, symbol, decimals] = tokenData[i];
|
|
1687
1687
|
const balanceNum = Number(formatUnits5(balance, decimals));
|
|
1688
|
-
const investedNum = Number(formatUnits5(alloc.investedAmount,
|
|
1688
|
+
const investedNum = Number(formatUnits5(alloc.investedAmount, assetDecimals2));
|
|
1689
1689
|
totalInvested += alloc.investedAmount;
|
|
1690
1690
|
const price = prices[i];
|
|
1691
1691
|
let currentValue = null;
|
|
@@ -1700,7 +1700,7 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1700
1700
|
targetWeightBps: Number(alloc.targetWeightBps),
|
|
1701
1701
|
balance: formatUnits5(balance, decimals),
|
|
1702
1702
|
balanceRaw: balance.toString(),
|
|
1703
|
-
investedAmount: formatUnits5(alloc.investedAmount,
|
|
1703
|
+
investedAmount: formatUnits5(alloc.investedAmount, assetDecimals2),
|
|
1704
1704
|
currentPrice: price?.price ?? null,
|
|
1705
1705
|
currentValue,
|
|
1706
1706
|
actualWeightBps: null,
|
|
@@ -1724,7 +1724,7 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1724
1724
|
}
|
|
1725
1725
|
}
|
|
1726
1726
|
}
|
|
1727
|
-
const totalInvestedNum = Number(formatUnits5(totalInvested,
|
|
1727
|
+
const totalInvestedNum = Number(formatUnits5(totalInvested, assetDecimals2));
|
|
1728
1728
|
const totalPnl = pricesAvailable ? totalPortfolioValue - totalInvestedNum : null;
|
|
1729
1729
|
const totalPnlPct = totalPnl !== null && totalInvestedNum > 0 ? totalPnl / totalInvestedNum * 100 : null;
|
|
1730
1730
|
spinner?.succeed("Strategy state loaded");
|
|
@@ -1735,10 +1735,10 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1735
1735
|
proposer,
|
|
1736
1736
|
state: stateStr,
|
|
1737
1737
|
network,
|
|
1738
|
-
asset: { address: assetAddr, symbol: assetSymbol, decimals:
|
|
1739
|
-
totalDeployed: formatUnits5(totalAmount,
|
|
1738
|
+
asset: { address: assetAddr, symbol: assetSymbol, decimals: assetDecimals2 },
|
|
1739
|
+
totalDeployed: formatUnits5(totalAmount, assetDecimals2),
|
|
1740
1740
|
maxSlippageBps: Number(maxSlippage),
|
|
1741
|
-
assetBalance: formatUnits5(assetBalance,
|
|
1741
|
+
assetBalance: formatUnits5(assetBalance, assetDecimals2),
|
|
1742
1742
|
pricesAvailable,
|
|
1743
1743
|
priceSource,
|
|
1744
1744
|
portfolio: {
|
|
@@ -1763,9 +1763,9 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1763
1763
|
console.log(` Proposer: ${chalk4.cyan(proposer)}`);
|
|
1764
1764
|
console.log(` State: ${stateColor(stateStr)}`);
|
|
1765
1765
|
console.log(` Asset: ${assetSymbol} (${assetAddr})`);
|
|
1766
|
-
console.log(` Deployed: ${formatUnits5(totalAmount,
|
|
1766
|
+
console.log(` Deployed: ${formatUnits5(totalAmount, assetDecimals2)} ${assetSymbol}`);
|
|
1767
1767
|
console.log(` Max Slip: ${Number(maxSlippage) / 100}%`);
|
|
1768
|
-
console.log(` Asset held: ${formatUnits5(assetBalance,
|
|
1768
|
+
console.log(` Asset held: ${formatUnits5(assetBalance, assetDecimals2)} ${assetSymbol}`);
|
|
1769
1769
|
if (pricesAvailable) {
|
|
1770
1770
|
const pvStr = totalPortfolioValue.toFixed(6);
|
|
1771
1771
|
const pnlStr = totalPnl !== null ? (totalPnl >= 0 ? "+" : "") + totalPnl.toFixed(6) : "n/a";
|
|
@@ -1807,7 +1807,7 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1807
1807
|
}
|
|
1808
1808
|
}
|
|
1809
1809
|
console.log(chalk4.dim("\u2500".repeat(70)));
|
|
1810
|
-
console.log(` Total invested: ${formatUnits5(totalInvested,
|
|
1810
|
+
console.log(` Total invested: ${formatUnits5(totalInvested, assetDecimals2)} ${assetSymbol}`);
|
|
1811
1811
|
if (pricesAvailable && maxDriftToken) {
|
|
1812
1812
|
const absMaxDrift = Math.abs(maxDriftBps);
|
|
1813
1813
|
const driftColor = absMaxDrift > 500 ? chalk4.red : absMaxDrift > 200 ? chalk4.yellow : chalk4.green;
|
|
@@ -1851,7 +1851,7 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1851
1851
|
verifySpinner.fail(`Only the proposer (${proposer}) can rebalance. Your wallet: ${account.address}`);
|
|
1852
1852
|
process.exit(1);
|
|
1853
1853
|
}
|
|
1854
|
-
const [
|
|
1854
|
+
const [assetDecimals2, assetSymbol] = await Promise.all([
|
|
1855
1855
|
publicClient.readContract({ address: assetAddr, abi: erc20Abi3, functionName: "decimals" }),
|
|
1856
1856
|
publicClient.readContract({ address: assetAddr, abi: erc20Abi3, functionName: "symbol" })
|
|
1857
1857
|
]);
|
|
@@ -1953,7 +1953,7 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
1953
1953
|
const alloc = postAllocations[i];
|
|
1954
1954
|
const [balance, symbol, decimals] = postData[i];
|
|
1955
1955
|
const weightPct = (Number(alloc.targetWeightBps) / 100).toFixed(1) + "%";
|
|
1956
|
-
const investedStr = formatUnits5(alloc.investedAmount,
|
|
1956
|
+
const investedStr = formatUnits5(alloc.investedAmount, assetDecimals2);
|
|
1957
1957
|
console.log(
|
|
1958
1958
|
` ${chalk4.bold(symbol.padEnd(8))} ${weightPct.padEnd(8)} invested: ${investedStr.padEnd(14)} bal: ${formatUnits5(balance, decimals)}`
|
|
1959
1959
|
);
|
|
@@ -2299,7 +2299,7 @@ function registerVeniceCommands(program2) {
|
|
|
2299
2299
|
getNetDeposited(vaultAddress),
|
|
2300
2300
|
getAgentAddresses(vaultAddress)
|
|
2301
2301
|
]);
|
|
2302
|
-
const [
|
|
2302
|
+
const [assetDecimals2, assetSymbol, assetBalance] = await Promise.all([
|
|
2303
2303
|
client.readContract({ address: assetAddress, abi: ERC20_ABI, functionName: "decimals" }),
|
|
2304
2304
|
client.readContract({ address: assetAddress, abi: ERC20_ABI, functionName: "symbol" }),
|
|
2305
2305
|
client.readContract({ address: assetAddress, abi: ERC20_ABI, functionName: "balanceOf", args: [vaultAddress] })
|
|
@@ -2349,7 +2349,7 @@ function registerVeniceCommands(program2) {
|
|
|
2349
2349
|
console.log(chalk5.bold("Venice Inference Status"));
|
|
2350
2350
|
console.log(chalk5.dim("\u2500".repeat(50)));
|
|
2351
2351
|
console.log(chalk5.bold("\n Vault"));
|
|
2352
|
-
console.log(` Profit available: ${formatUnits6(profit,
|
|
2352
|
+
console.log(` Profit available: ${formatUnits6(profit, assetDecimals2)} ${assetSymbol}`);
|
|
2353
2353
|
console.log(` VVV (unstaked): ${formatUnits6(vaultVvvBalance, 18)}`);
|
|
2354
2354
|
console.log(chalk5.bold("\n Agent sVVV Balances"));
|
|
2355
2355
|
for (const { agent, balance } of agentBalances) {
|
|
@@ -2463,8 +2463,8 @@ import ora5 from "ora";
|
|
|
2463
2463
|
|
|
2464
2464
|
// src/strategies/allowance-disburse.ts
|
|
2465
2465
|
import { encodeFunctionData, parseUnits as parseUnits6 } from "viem";
|
|
2466
|
-
function buildDisburseBatch(config, vaultAddress, agents, assetAddress,
|
|
2467
|
-
const assetAmount = parseUnits6(config.amount,
|
|
2466
|
+
function buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDecimals2, minUsdc, swapPath) {
|
|
2467
|
+
const assetAmount = parseUnits6(config.amount, assetDecimals2);
|
|
2468
2468
|
const isUsdc = assetAddress.toLowerCase() === TOKENS().USDC.toLowerCase();
|
|
2469
2469
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
2470
2470
|
const calls = [];
|
|
@@ -2564,7 +2564,7 @@ function registerAllowanceCommands(program2) {
|
|
|
2564
2564
|
const client = getPublicClient();
|
|
2565
2565
|
const spinner = ora5("Reading vault state...").start();
|
|
2566
2566
|
let assetAddress;
|
|
2567
|
-
let
|
|
2567
|
+
let assetDecimals2;
|
|
2568
2568
|
let assetSymbol;
|
|
2569
2569
|
let totalDeposited;
|
|
2570
2570
|
let assetBalance;
|
|
@@ -2575,7 +2575,7 @@ function registerAllowanceCommands(program2) {
|
|
|
2575
2575
|
getNetDeposited(vaultAddress),
|
|
2576
2576
|
getAgentAddresses(vaultAddress)
|
|
2577
2577
|
]);
|
|
2578
|
-
[
|
|
2578
|
+
[assetDecimals2, assetSymbol, assetBalance] = await Promise.all([
|
|
2579
2579
|
client.readContract({ address: assetAddress, abi: ERC20_ABI, functionName: "decimals" }),
|
|
2580
2580
|
client.readContract({ address: assetAddress, abi: ERC20_ABI, functionName: "symbol" }),
|
|
2581
2581
|
client.readContract({ address: assetAddress, abi: ERC20_ABI, functionName: "balanceOf", args: [vaultAddress] })
|
|
@@ -2590,18 +2590,18 @@ function registerAllowanceCommands(program2) {
|
|
|
2590
2590
|
console.error(chalk6.red("No agents registered in vault. Register agents first."));
|
|
2591
2591
|
process.exit(1);
|
|
2592
2592
|
}
|
|
2593
|
-
const requestedAmount = parseUnits7(opts.amount,
|
|
2593
|
+
const requestedAmount = parseUnits7(opts.amount, assetDecimals2);
|
|
2594
2594
|
const profit = assetBalance > totalDeposited ? assetBalance - totalDeposited : 0n;
|
|
2595
2595
|
const isUsdc = assetAddress.toLowerCase() === TOKENS().USDC.toLowerCase();
|
|
2596
2596
|
const isWeth = assetAddress.toLowerCase() === TOKENS().WETH.toLowerCase();
|
|
2597
2597
|
console.log();
|
|
2598
2598
|
console.log(chalk6.bold("Allowance Disburse"));
|
|
2599
2599
|
console.log(chalk6.dim("\u2500".repeat(40)));
|
|
2600
|
-
console.log(` Asset: ${assetSymbol} (${
|
|
2600
|
+
console.log(` Asset: ${assetSymbol} (${assetDecimals2} decimals)`);
|
|
2601
2601
|
console.log(` Amount: ${opts.amount} ${assetSymbol}`);
|
|
2602
|
-
console.log(` Vault balance: ${formatUnits7(assetBalance,
|
|
2603
|
-
console.log(` Net deposited (est.): ${formatUnits7(totalDeposited,
|
|
2604
|
-
console.log(` Profit: ${formatUnits7(profit,
|
|
2602
|
+
console.log(` Vault balance: ${formatUnits7(assetBalance, assetDecimals2)} ${assetSymbol}`);
|
|
2603
|
+
console.log(` Net deposited (est.): ${formatUnits7(totalDeposited, assetDecimals2)} ${assetSymbol}`);
|
|
2604
|
+
console.log(` Profit: ${formatUnits7(profit, assetDecimals2)} ${assetSymbol}`);
|
|
2605
2605
|
console.log(` Agents: ${agents.length} (USDC will be split equally)`);
|
|
2606
2606
|
if (!isUsdc) {
|
|
2607
2607
|
console.log(` Routing: ${isWeth ? `WETH \u2192 USDC (fee ${fee})` : `${assetSymbol} \u2192 WETH \u2192 USDC (fee ${fee})`}`);
|
|
@@ -2610,7 +2610,7 @@ function registerAllowanceCommands(program2) {
|
|
|
2610
2610
|
console.log(` Vault: ${vaultAddress}`);
|
|
2611
2611
|
console.log();
|
|
2612
2612
|
if (requestedAmount > profit) {
|
|
2613
|
-
console.warn(chalk6.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${formatUnits7(profit,
|
|
2613
|
+
console.warn(chalk6.yellow(` Warning: amount (${opts.amount}) exceeds available profit (${formatUnits7(profit, assetDecimals2)})`));
|
|
2614
2614
|
console.warn(chalk6.yellow(" This will use deposited capital, not just profits."));
|
|
2615
2615
|
console.log();
|
|
2616
2616
|
}
|
|
@@ -2662,7 +2662,7 @@ function registerAllowanceCommands(program2) {
|
|
|
2662
2662
|
fee,
|
|
2663
2663
|
slippageBps
|
|
2664
2664
|
};
|
|
2665
|
-
const calls = buildDisburseBatch(config, vaultAddress, agents, assetAddress,
|
|
2665
|
+
const calls = buildDisburseBatch(config, vaultAddress, agents, assetAddress, assetDecimals2, minUsdc, swapPath);
|
|
2666
2666
|
console.log();
|
|
2667
2667
|
console.log(chalk6.bold(`Batch calls (${calls.length}):`));
|
|
2668
2668
|
console.log(formatBatch(calls));
|
|
@@ -2688,7 +2688,7 @@ function registerAllowanceCommands(program2) {
|
|
|
2688
2688
|
getNetDeposited(vaultAddress),
|
|
2689
2689
|
getAgentAddresses(vaultAddress)
|
|
2690
2690
|
]);
|
|
2691
|
-
const [
|
|
2691
|
+
const [assetDecimals2, assetSymbol, assetBalance] = await Promise.all([
|
|
2692
2692
|
client.readContract({ address: assetAddress, abi: ERC20_ABI, functionName: "decimals" }),
|
|
2693
2693
|
client.readContract({ address: assetAddress, abi: ERC20_ABI, functionName: "symbol" }),
|
|
2694
2694
|
client.readContract({ address: assetAddress, abi: ERC20_ABI, functionName: "balanceOf", args: [vaultAddress] })
|
|
@@ -2712,9 +2712,9 @@ function registerAllowanceCommands(program2) {
|
|
|
2712
2712
|
console.log(chalk6.dim("\u2500".repeat(50)));
|
|
2713
2713
|
console.log(chalk6.bold("\n Vault"));
|
|
2714
2714
|
console.log(` Asset: ${assetSymbol}`);
|
|
2715
|
-
console.log(` Balance: ${formatUnits7(assetBalance,
|
|
2716
|
-
console.log(` Net deposited (est.): ${formatUnits7(totalDeposited,
|
|
2717
|
-
console.log(` Profit: ${formatUnits7(profit,
|
|
2715
|
+
console.log(` Balance: ${formatUnits7(assetBalance, assetDecimals2)} ${assetSymbol}`);
|
|
2716
|
+
console.log(` Net deposited (est.): ${formatUnits7(totalDeposited, assetDecimals2)} ${assetSymbol}`);
|
|
2717
|
+
console.log(` Profit: ${formatUnits7(profit, assetDecimals2)} ${assetSymbol}`);
|
|
2718
2718
|
console.log(chalk6.bold("\n Agent USDC Balances"));
|
|
2719
2719
|
for (const { agent, balance } of agentBalances) {
|
|
2720
2720
|
const isMe = agent.toLowerCase() === account.address.toLowerCase();
|
|
@@ -3619,7 +3619,7 @@ async function resolveRiskEnvelope(opts, vault) {
|
|
|
3619
3619
|
console.error(chalk8.red(" --max-capital is required (the ceiling this proposal may deploy, in asset units)."));
|
|
3620
3620
|
process.exit(1);
|
|
3621
3621
|
}
|
|
3622
|
-
const asset = await getAssetAddress();
|
|
3622
|
+
const asset = await getAssetAddress(vault);
|
|
3623
3623
|
const decimals = await getPublicClient().readContract({
|
|
3624
3624
|
address: asset,
|
|
3625
3625
|
abi: ERC20_ABI,
|
|
@@ -3637,7 +3637,7 @@ async function resolveRiskEnvelope(opts, vault) {
|
|
|
3637
3637
|
}
|
|
3638
3638
|
return { maxCapital, maxDrawdownBps };
|
|
3639
3639
|
}
|
|
3640
|
-
function resolveCaps(list, callCount, fallbackTotal, flag) {
|
|
3640
|
+
function resolveCaps(list, callCount, fallbackTotal, flag, decimals) {
|
|
3641
3641
|
if (list === void 0) {
|
|
3642
3642
|
if (callCount === 0) return [];
|
|
3643
3643
|
return Array.from({ length: callCount }, (_, i) => i === callCount - 1 ? fallbackTotal : 0n);
|
|
@@ -3649,7 +3649,20 @@ function resolveCaps(list, callCount, fallbackTotal, flag) {
|
|
|
3649
3649
|
);
|
|
3650
3650
|
process.exit(1);
|
|
3651
3651
|
}
|
|
3652
|
-
return parts.map((x) =>
|
|
3652
|
+
return parts.map((x) => {
|
|
3653
|
+
if (!/^\d+(\.\d+)?$/.test(x)) {
|
|
3654
|
+
console.error(chalk8.red(` ${flag} entries must be non-negative decimal amounts in asset units (got "${x}").`));
|
|
3655
|
+
process.exit(1);
|
|
3656
|
+
}
|
|
3657
|
+
return parseUnits8(x, decimals);
|
|
3658
|
+
});
|
|
3659
|
+
}
|
|
3660
|
+
async function assetDecimals(vault) {
|
|
3661
|
+
return await getPublicClient().readContract({
|
|
3662
|
+
address: await getAssetAddress(vault),
|
|
3663
|
+
abi: ERC20_ABI,
|
|
3664
|
+
functionName: "decimals"
|
|
3665
|
+
});
|
|
3653
3666
|
}
|
|
3654
3667
|
function registerProposalCommands(program2) {
|
|
3655
3668
|
const proposal = program2.command("proposal").description("Governance proposals \u2014 create, vote, execute, settle");
|
|
@@ -3694,6 +3707,7 @@ function registerProposalCommands(program2) {
|
|
|
3694
3707
|
process.exit(1);
|
|
3695
3708
|
}
|
|
3696
3709
|
const calldataEnvelope = await resolveRiskEnvelope(opts, vault);
|
|
3710
|
+
const capDecimals2 = await assetDecimals(vault);
|
|
3697
3711
|
try {
|
|
3698
3712
|
emitCalldata(
|
|
3699
3713
|
encodePropose(
|
|
@@ -3709,14 +3723,16 @@ function registerProposalCommands(program2) {
|
|
|
3709
3723
|
opts.executeCaps,
|
|
3710
3724
|
executeCalls.length,
|
|
3711
3725
|
calldataEnvelope.maxCapital,
|
|
3712
|
-
"--execute-caps"
|
|
3726
|
+
"--execute-caps",
|
|
3727
|
+
capDecimals2
|
|
3713
3728
|
),
|
|
3714
3729
|
settlementCalls: settleCalls,
|
|
3715
3730
|
settlementCallCaps: resolveCaps(
|
|
3716
3731
|
opts.settleCaps,
|
|
3717
3732
|
settleCalls.length,
|
|
3718
3733
|
0n,
|
|
3719
|
-
"--settle-caps"
|
|
3734
|
+
"--settle-caps",
|
|
3735
|
+
capDecimals2
|
|
3720
3736
|
)
|
|
3721
3737
|
},
|
|
3722
3738
|
getChain().id
|
|
@@ -3806,18 +3822,30 @@ function registerProposalCommands(program2) {
|
|
|
3806
3822
|
}
|
|
3807
3823
|
const spinner = ora6({ text: W3("Submitting proposal..."), color: "green" }).start();
|
|
3808
3824
|
const envelope = await resolveRiskEnvelope(opts, vault);
|
|
3825
|
+
const capDecimals = await assetDecimals(vault);
|
|
3809
3826
|
const executeCallCaps = resolveCaps(
|
|
3810
3827
|
opts.executeCaps,
|
|
3811
3828
|
executeCalls.length,
|
|
3812
3829
|
envelope.maxCapital,
|
|
3813
|
-
"--execute-caps"
|
|
3830
|
+
"--execute-caps",
|
|
3831
|
+
capDecimals
|
|
3814
3832
|
);
|
|
3815
3833
|
const settleCallCaps = resolveCaps(
|
|
3816
3834
|
opts.settleCaps,
|
|
3817
3835
|
settleCalls.length,
|
|
3818
3836
|
0n,
|
|
3819
|
-
"--settle-caps"
|
|
3837
|
+
"--settle-caps",
|
|
3838
|
+
capDecimals
|
|
3820
3839
|
);
|
|
3840
|
+
try {
|
|
3841
|
+
await ensureProposerBondAllowance(vault, envelope.maxCapital, await getAssetAddress(vault));
|
|
3842
|
+
} catch (err) {
|
|
3843
|
+
if (err instanceof InsufficientProposerBondWood) {
|
|
3844
|
+
spinner.fail(err.message);
|
|
3845
|
+
process.exit(1);
|
|
3846
|
+
}
|
|
3847
|
+
throw err;
|
|
3848
|
+
}
|
|
3821
3849
|
const result = await propose(
|
|
3822
3850
|
vault,
|
|
3823
3851
|
strategy2,
|
|
@@ -4345,7 +4373,7 @@ function registerProposalCommands(program2) {
|
|
|
4345
4373
|
);
|
|
4346
4374
|
process.exit(1);
|
|
4347
4375
|
}
|
|
4348
|
-
const asset = await getAssetAddress();
|
|
4376
|
+
const asset = await getAssetAddress(vault);
|
|
4349
4377
|
const noopCalldata = encodeFunctionData3({
|
|
4350
4378
|
abi: ERC20_ABI,
|
|
4351
4379
|
functionName: "balanceOf",
|
|
@@ -8048,7 +8076,7 @@ try {
|
|
|
8048
8076
|
} catch {
|
|
8049
8077
|
}
|
|
8050
8078
|
var require2 = createRequire(import.meta.url);
|
|
8051
|
-
var CLI_VERSION = "0.88.
|
|
8079
|
+
var CLI_VERSION = "0.88.2";
|
|
8052
8080
|
async function loadXmtp() {
|
|
8053
8081
|
return import("./xmtp-72IRK7JL.js");
|
|
8054
8082
|
}
|
|
@@ -9340,8 +9368,8 @@ vaultCmd.command("balance").description("Show LP share balance and asset value")
|
|
|
9340
9368
|
});
|
|
9341
9369
|
vaultCmd.command("redeem").description("Redeem vault shares for the underlying asset (ERC-4626)").option("--vault <address>", "Vault address (default: from config)").option("--shares <amount>", "Shares to redeem in whole-share units (default: all)").option("--receiver <address>", "Receiver of the underlying asset (default: your wallet)").option("--owner <address>", "Share owner whose shares burn (required with --calldata-only)").action(async (opts) => {
|
|
9342
9370
|
resolveVault(opts);
|
|
9343
|
-
const
|
|
9344
|
-
const shareDecimals =
|
|
9371
|
+
const assetDecimals2 = await getAssetDecimals();
|
|
9372
|
+
const shareDecimals = assetDecimals2 * 2;
|
|
9345
9373
|
if (isCalldataOnly()) {
|
|
9346
9374
|
if (!opts.shares) {
|
|
9347
9375
|
console.error(
|
|
@@ -9414,7 +9442,7 @@ vaultCmd.command("redeem").description("Redeem vault shares for the underlying a
|
|
|
9414
9442
|
);
|
|
9415
9443
|
spinner.succeed(`Redeemed: ${hash}`);
|
|
9416
9444
|
console.log(chalk17.dim(` ${getExplorerUrl(hash)}`));
|
|
9417
|
-
console.log(` Assets received: ${formatUnits10(assetsOut,
|
|
9445
|
+
console.log(` Assets received: ${formatUnits10(assetsOut, assetDecimals2)}`);
|
|
9418
9446
|
} catch (err) {
|
|
9419
9447
|
spinner.fail("Redeem failed");
|
|
9420
9448
|
console.error(chalk17.red(formatContractError(err)));
|