@sherwoodagent/cli 0.73.2 → 0.73.4
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/{addresses-YDPUPGWQ.js → addresses-DGB3D457.js} +3 -3
- package/dist/{agent-AML5SIMT.js → agent-UNSW5IPO.js} +6 -6
- package/dist/{chat-6RO4RS3L.js → chat-KT2WVDT2.js} +8 -8
- package/dist/{chunk-AGZQWXAR.js → chunk-2U4TWPWQ.js} +4 -4
- package/dist/{chunk-RQZ53CV4.js → chunk-BKJ7HYX7.js} +2 -2
- package/dist/{chunk-XJJEZFOA.js → chunk-CHWBQJLT.js} +5 -5
- package/dist/{chunk-FNJHLDRL.js → chunk-CZRJ5GWE.js} +15 -11
- package/dist/chunk-CZRJ5GWE.js.map +1 -0
- package/dist/{chunk-5ECJMM3K.js → chunk-DIZEB2VV.js} +4 -4
- package/dist/{chunk-HYUUR6SC.js → chunk-DXJJMRBM.js} +13 -3
- package/dist/chunk-DXJJMRBM.js.map +1 -0
- package/dist/{chunk-XMYD5SES.js → chunk-GU5VZGXB.js} +4 -4
- package/dist/{chunk-RAITRCM7.js → chunk-IFL5SREW.js} +2 -2
- package/dist/{chunk-WO4YDEDH.js → chunk-NPWYX6NU.js} +2 -2
- package/dist/{chunk-LZH4PJI4.js → chunk-ROKE6ZAW.js} +24 -4
- package/dist/chunk-ROKE6ZAW.js.map +1 -0
- package/dist/{chunk-TSNHEU2C.js → chunk-ZURDCYGU.js} +4 -4
- package/dist/{client-HMUVPZEG.js → client-NAL3HVLK.js} +7 -3
- package/dist/{eas-GDQYAUXR.js → eas-QAH7XVLK.js} +5 -5
- package/dist/{governor-PX6AMIAU.js → governor-S56M6BV6.js} +5 -5
- package/dist/index.js +44 -41
- package/dist/index.js.map +1 -1
- package/dist/{network-L6JKNYOJ.js → network-MKMX2NG6.js} +6 -2
- package/dist/{price-SGQZC4DT.js → price-HHDBMKIE.js} +4 -4
- package/dist/{research-S5PLKE5V.js → research-4TBGYEVI.js} +4 -4
- package/dist/{research-DDEAW7NP.js → research-IJBOMYL3.js} +7 -7
- package/dist/{session-2QRTQ6ID.js → session-L67AVWBY.js} +9 -9
- package/dist/{trade-GNOISJNX.js → trade-LGFQEK3I.js} +14 -14
- package/dist/{vault-32RDL5HM.js → vault-XWFPGHRA.js} +5 -5
- package/dist/{xmtp-AL5W36H6.js → xmtp-6US7GH3Z.js} +6 -6
- package/package.json +2 -2
- package/dist/chunk-FNJHLDRL.js.map +0 -1
- package/dist/chunk-HYUUR6SC.js.map +0 -1
- package/dist/chunk-LZH4PJI4.js.map +0 -1
- /package/dist/{addresses-YDPUPGWQ.js.map → addresses-DGB3D457.js.map} +0 -0
- /package/dist/{agent-AML5SIMT.js.map → agent-UNSW5IPO.js.map} +0 -0
- /package/dist/{chat-6RO4RS3L.js.map → chat-KT2WVDT2.js.map} +0 -0
- /package/dist/{chunk-AGZQWXAR.js.map → chunk-2U4TWPWQ.js.map} +0 -0
- /package/dist/{chunk-RQZ53CV4.js.map → chunk-BKJ7HYX7.js.map} +0 -0
- /package/dist/{chunk-XJJEZFOA.js.map → chunk-CHWBQJLT.js.map} +0 -0
- /package/dist/{chunk-5ECJMM3K.js.map → chunk-DIZEB2VV.js.map} +0 -0
- /package/dist/{chunk-XMYD5SES.js.map → chunk-GU5VZGXB.js.map} +0 -0
- /package/dist/{chunk-RAITRCM7.js.map → chunk-IFL5SREW.js.map} +0 -0
- /package/dist/{chunk-WO4YDEDH.js.map → chunk-NPWYX6NU.js.map} +0 -0
- /package/dist/{chunk-TSNHEU2C.js.map → chunk-ZURDCYGU.js.map} +0 -0
- /package/dist/{client-HMUVPZEG.js.map → client-NAL3HVLK.js.map} +0 -0
- /package/dist/{eas-GDQYAUXR.js.map → eas-QAH7XVLK.js.map} +0 -0
- /package/dist/{governor-PX6AMIAU.js.map → governor-S56M6BV6.js.map} +0 -0
- /package/dist/{network-L6JKNYOJ.js.map → network-MKMX2NG6.js.map} +0 -0
- /package/dist/{price-SGQZC4DT.js.map → price-HHDBMKIE.js.map} +0 -0
- /package/dist/{research-S5PLKE5V.js.map → research-4TBGYEVI.js.map} +0 -0
- /package/dist/{research-DDEAW7NP.js.map → research-IJBOMYL3.js.map} +0 -0
- /package/dist/{session-2QRTQ6ID.js.map → session-L67AVWBY.js.map} +0 -0
- /package/dist/{trade-GNOISJNX.js.map → trade-LGFQEK3I.js.map} +0 -0
- /package/dist/{vault-32RDL5HM.js.map → vault-XWFPGHRA.js.map} +0 -0
- /package/dist/{xmtp-AL5W36H6.js.map → xmtp-6US7GH3Z.js.map} +0 -0
|
@@ -18,8 +18,8 @@ import {
|
|
|
18
18
|
isRobinhoodEquityFeed,
|
|
19
19
|
robinhoodEquityMaxAge,
|
|
20
20
|
symbolForTokenAddress
|
|
21
|
-
} from "./chunk-
|
|
22
|
-
import "./chunk-
|
|
21
|
+
} from "./chunk-IFL5SREW.js";
|
|
22
|
+
import "./chunk-DXJJMRBM.js";
|
|
23
23
|
import "./chunk-GSC7PVEO.js";
|
|
24
24
|
export {
|
|
25
25
|
AERODROME,
|
|
@@ -42,4 +42,4 @@ export {
|
|
|
42
42
|
robinhoodEquityMaxAge,
|
|
43
43
|
symbolForTokenAddress
|
|
44
44
|
};
|
|
45
|
-
//# sourceMappingURL=addresses-
|
|
45
|
+
//# sourceMappingURL=addresses-DGB3D457.js.map
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import {
|
|
13
13
|
getResearchProvider,
|
|
14
14
|
isX402WalletFunded
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-BKJ7HYX7.js";
|
|
16
16
|
import {
|
|
17
17
|
HyperliquidProvider,
|
|
18
18
|
calculateATR,
|
|
@@ -29,9 +29,9 @@ import {
|
|
|
29
29
|
} from "./chunk-DBOINZYU.js";
|
|
30
30
|
import {
|
|
31
31
|
chatCompletion
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
34
|
-
import "./chunk-
|
|
32
|
+
} from "./chunk-NPWYX6NU.js";
|
|
33
|
+
import "./chunk-ROKE6ZAW.js";
|
|
34
|
+
import "./chunk-DXJJMRBM.js";
|
|
35
35
|
import {
|
|
36
36
|
getVeniceApiKey
|
|
37
37
|
} from "./chunk-GSC7PVEO.js";
|
|
@@ -5573,7 +5573,7 @@ var PortfolioTracker = class {
|
|
|
5573
5573
|
}
|
|
5574
5574
|
try {
|
|
5575
5575
|
const { createPublicClient, http } = await import("viem");
|
|
5576
|
-
const { getChain } = await import("./network-
|
|
5576
|
+
const { getChain } = await import("./network-MKMX2NG6.js");
|
|
5577
5577
|
const { BASE_STRATEGY_ABI, SYNDICATE_VAULT_ABI } = await import("./abis-KP7M4IPM.js");
|
|
5578
5578
|
void chain;
|
|
5579
5579
|
const client = createPublicClient({
|
|
@@ -9550,4 +9550,4 @@ function formatFearGreed(value) {
|
|
|
9550
9550
|
export {
|
|
9551
9551
|
registerAgentCommands
|
|
9552
9552
|
};
|
|
9553
|
-
//# sourceMappingURL=agent-
|
|
9553
|
+
//# sourceMappingURL=agent-UNSW5IPO.js.map
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getFund,
|
|
3
3
|
updateMetadata
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-2U4TWPWQ.js";
|
|
5
5
|
import {
|
|
6
6
|
getTextRecord,
|
|
7
7
|
resolveFund,
|
|
8
8
|
setTextRecord
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-CHWBQJLT.js";
|
|
10
|
+
import "./chunk-CZRJ5GWE.js";
|
|
11
11
|
import {
|
|
12
12
|
ENS
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-IFL5SREW.js";
|
|
14
14
|
import {
|
|
15
15
|
formatContractError,
|
|
16
16
|
getAccount
|
|
17
|
-
} from "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
} from "./chunk-ROKE6ZAW.js";
|
|
18
|
+
import "./chunk-DXJJMRBM.js";
|
|
19
19
|
import {
|
|
20
20
|
cacheGroupId,
|
|
21
21
|
getCachedGroupId
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
import chalk from "chalk";
|
|
31
31
|
import ora from "ora";
|
|
32
32
|
async function loadXmtp() {
|
|
33
|
-
return import("./xmtp-
|
|
33
|
+
return import("./xmtp-6US7GH3Z.js");
|
|
34
34
|
}
|
|
35
35
|
function formatTimestamp(date) {
|
|
36
36
|
return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
|
|
@@ -564,4 +564,4 @@ function registerChatCommands(program) {
|
|
|
564
564
|
export {
|
|
565
565
|
registerChatCommands
|
|
566
566
|
};
|
|
567
|
-
//# sourceMappingURL=chat-
|
|
567
|
+
//# sourceMappingURL=chat-KT2WVDT2.js.map
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SHERWOOD
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IFL5SREW.js";
|
|
4
4
|
import {
|
|
5
5
|
getAccount,
|
|
6
6
|
getPublicClient,
|
|
7
7
|
waitForReceipt,
|
|
8
8
|
writeContractWithRetry
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ROKE6ZAW.js";
|
|
10
10
|
import {
|
|
11
11
|
getChain
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-DXJJMRBM.js";
|
|
13
13
|
import {
|
|
14
14
|
SYNDICATE_FACTORY_ABI
|
|
15
15
|
} from "./chunk-BQMOE4FJ.js";
|
|
@@ -144,4 +144,4 @@ export {
|
|
|
144
144
|
getActiveFunds,
|
|
145
145
|
updateMetadata
|
|
146
146
|
};
|
|
147
|
-
//# sourceMappingURL=chunk-
|
|
147
|
+
//# sourceMappingURL=chunk-2U4TWPWQ.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getAccount
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ROKE6ZAW.js";
|
|
4
4
|
|
|
5
5
|
// src/providers/research/messari.ts
|
|
6
6
|
import { base, baseSepolia } from "viem/chains";
|
|
@@ -635,4 +635,4 @@ export {
|
|
|
635
635
|
NansenProvider,
|
|
636
636
|
getResearchProvider
|
|
637
637
|
};
|
|
638
|
-
//# sourceMappingURL=chunk-
|
|
638
|
+
//# sourceMappingURL=chunk-BKJ7HYX7.js.map
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
executeBatch,
|
|
3
3
|
setVaultAddress
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-CZRJ5GWE.js";
|
|
5
5
|
import {
|
|
6
6
|
ENS,
|
|
7
7
|
SHERWOOD
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-IFL5SREW.js";
|
|
9
9
|
import {
|
|
10
10
|
getPublicClient
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-ROKE6ZAW.js";
|
|
12
12
|
import {
|
|
13
13
|
VALID_NETWORKS,
|
|
14
14
|
withNetwork
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-DXJJMRBM.js";
|
|
16
16
|
import {
|
|
17
17
|
L2_REGISTRY_ABI,
|
|
18
18
|
SYNDICATE_FACTORY_ABI
|
|
@@ -124,4 +124,4 @@ export {
|
|
|
124
124
|
setTextRecord,
|
|
125
125
|
getTextRecord
|
|
126
126
|
};
|
|
127
|
-
//# sourceMappingURL=chunk-
|
|
127
|
+
//# sourceMappingURL=chunk-CHWBQJLT.js.map
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TOKENS
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IFL5SREW.js";
|
|
4
4
|
import {
|
|
5
|
+
GAS_UNITS,
|
|
6
|
+
estimateGasCushion,
|
|
5
7
|
getAccount,
|
|
6
8
|
getPublicClient,
|
|
7
9
|
getWalletClient,
|
|
8
10
|
waitForReceipt,
|
|
9
11
|
writeContractWithRetry
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ROKE6ZAW.js";
|
|
11
13
|
import {
|
|
12
14
|
getChain
|
|
13
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-DXJJMRBM.js";
|
|
14
16
|
import {
|
|
15
17
|
getChainContracts
|
|
16
18
|
} from "./chunk-GSC7PVEO.js";
|
|
@@ -20,7 +22,7 @@ import {
|
|
|
20
22
|
} from "./chunk-BQMOE4FJ.js";
|
|
21
23
|
|
|
22
24
|
// src/lib/vault.ts
|
|
23
|
-
import { formatUnits
|
|
25
|
+
import { formatUnits } from "viem";
|
|
24
26
|
var _vaultOverride = null;
|
|
25
27
|
function setVaultAddress(addr) {
|
|
26
28
|
_vaultOverride = addr;
|
|
@@ -111,10 +113,10 @@ async function preflightDeposit(amount) {
|
|
|
111
113
|
);
|
|
112
114
|
}
|
|
113
115
|
const ethBalance = await client.getBalance({ address: account.address });
|
|
114
|
-
const minGas =
|
|
116
|
+
const minGas = await estimateGasCushion(GAS_UNITS.approve + GAS_UNITS.deposit);
|
|
115
117
|
if (ethBalance < minGas) {
|
|
116
118
|
throw new Error(
|
|
117
|
-
`Insufficient ETH for gas. Have ${formatUnits(ethBalance, 18)} ETH, need at least
|
|
119
|
+
`Insufficient ETH for gas. Have ${formatUnits(ethBalance, 18)} ETH, need at least ${formatUnits(minGas, 18)} ETH. Top up your wallet with ETH on ${getChain().name}.`
|
|
118
120
|
);
|
|
119
121
|
}
|
|
120
122
|
const paused = await client.readContract({
|
|
@@ -180,10 +182,12 @@ async function depositWithEthWrap(amount) {
|
|
|
180
182
|
if (wethBalance < amount) {
|
|
181
183
|
const shortfall = amount - wethBalance;
|
|
182
184
|
const ethBalance = await client.getBalance({ address: account.address });
|
|
183
|
-
const minGas =
|
|
185
|
+
const minGas = await estimateGasCushion(
|
|
186
|
+
GAS_UNITS.wrap + GAS_UNITS.approve + GAS_UNITS.deposit
|
|
187
|
+
);
|
|
184
188
|
if (ethBalance < shortfall + minGas) {
|
|
185
189
|
throw new Error(
|
|
186
|
-
`Insufficient ETH. Have ${formatUnits(ethBalance, 18)} ETH, need ${formatUnits(shortfall, 18)} to wrap + gas.`
|
|
190
|
+
`Insufficient ETH on ${getChain().name}. Have ${formatUnits(ethBalance, 18)} ETH, need ${formatUnits(shortfall, 18)} to wrap + ~${formatUnits(minGas, 18)} for gas.`
|
|
187
191
|
);
|
|
188
192
|
}
|
|
189
193
|
const wallet = getWalletClient();
|
|
@@ -307,10 +311,10 @@ async function preflightRedeem(shares) {
|
|
|
307
311
|
}
|
|
308
312
|
}
|
|
309
313
|
const ethBalance = await client.getBalance({ address: account.address });
|
|
310
|
-
const minGas =
|
|
314
|
+
const minGas = await estimateGasCushion(GAS_UNITS.redeem);
|
|
311
315
|
if (ethBalance < minGas) {
|
|
312
316
|
throw new Error(
|
|
313
|
-
`Insufficient ETH for gas. Have ${formatUnits(ethBalance, 18)} ETH, need at least
|
|
317
|
+
`Insufficient ETH for gas on ${getChain().name}. Have ${formatUnits(ethBalance, 18)} ETH, need at least ${formatUnits(minGas, 18)} ETH.`
|
|
314
318
|
);
|
|
315
319
|
}
|
|
316
320
|
}
|
|
@@ -523,4 +527,4 @@ export {
|
|
|
523
527
|
registerAgent,
|
|
524
528
|
getVaultInfo
|
|
525
529
|
};
|
|
526
|
-
//# sourceMappingURL=chunk-
|
|
530
|
+
//# sourceMappingURL=chunk-CZRJ5GWE.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 } 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 type { BatchCall } from \"./batch.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 */\nexport async function getAssetAddress(): Promise<Address> {\n const client = getPublicClient();\n return client.readContract({\n address: 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// ── Batch Execution ──\n\n/**\n * Execute a batch of protocol calls through the vault (owner only).\n * The vault delegatecalls to the executor lib.\n * All calls execute as the vault — positions live on the vault.\n */\nexport async function executeBatch(calls: BatchCall[]): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: getVaultAddress(),\n abi: SYNDICATE_VAULT_ABI,\n functionName: \"executeBatch\",\n args: [\n calls.map((c) => ({\n target: c.target,\n data: c.data,\n value: c.value,\n })),\n ],\n });\n await waitForReceipt(hash);\n return hash;\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":[]}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
UNISWAP
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IFL5SREW.js";
|
|
4
4
|
import {
|
|
5
5
|
getAccount,
|
|
6
6
|
getPublicClient,
|
|
7
7
|
sendTxWithRetry,
|
|
8
8
|
waitForReceipt
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ROKE6ZAW.js";
|
|
10
10
|
import {
|
|
11
11
|
getChain
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-DXJJMRBM.js";
|
|
13
13
|
import {
|
|
14
14
|
getUniswapApiKey
|
|
15
15
|
} from "./chunk-GSC7PVEO.js";
|
|
@@ -322,4 +322,4 @@ export {
|
|
|
322
322
|
encodeSwapPath,
|
|
323
323
|
getMultiHopQuote
|
|
324
324
|
};
|
|
325
|
-
//# sourceMappingURL=chunk-
|
|
325
|
+
//# sourceMappingURL=chunk-DIZEB2VV.js.map
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-GSC7PVEO.js";
|
|
4
4
|
|
|
5
5
|
// src/lib/network.ts
|
|
6
|
-
import { defineChain } from "viem";
|
|
6
|
+
import { defineChain, parseEther } from "viem";
|
|
7
7
|
var robinhoodTestnet = defineChain({
|
|
8
8
|
id: 46630,
|
|
9
9
|
name: "Robinhood Chain Testnet",
|
|
@@ -19,6 +19,7 @@ var robinhoodTestnet = defineChain({
|
|
|
19
19
|
},
|
|
20
20
|
testnet: true
|
|
21
21
|
});
|
|
22
|
+
var DEFAULT_MIN_GAS_RESERVE = parseEther("0.0005");
|
|
22
23
|
var CHAIN_REGISTRY = {
|
|
23
24
|
"robinhood-testnet": {
|
|
24
25
|
chain: robinhoodTestnet,
|
|
@@ -28,7 +29,11 @@ var CHAIN_REGISTRY = {
|
|
|
28
29
|
easGraphqlUrl: null,
|
|
29
30
|
easScanHost: null,
|
|
30
31
|
xmtpEnv: "production",
|
|
31
|
-
isTestnet: true
|
|
32
|
+
isTestnet: true,
|
|
33
|
+
// ~14-wei base fee: a full wrap+approve+deposit sequence costs a few
|
|
34
|
+
// million wei (~1e-11 ETH). 0.00002 ETH is a generous floor that still
|
|
35
|
+
// leaves a 0.00058-ETH wallet room to wrap 0.0005 and deposit.
|
|
36
|
+
minGasReserve: parseEther("0.00002")
|
|
32
37
|
}
|
|
33
38
|
};
|
|
34
39
|
var VALID_NETWORKS = Object.keys(CHAIN_REGISTRY);
|
|
@@ -58,6 +63,9 @@ async function withNetwork(network, fn) {
|
|
|
58
63
|
function getChainConfig() {
|
|
59
64
|
return CHAIN_REGISTRY[_network];
|
|
60
65
|
}
|
|
66
|
+
function getMinGasReserve() {
|
|
67
|
+
return CHAIN_REGISTRY[_network].minGasReserve ?? DEFAULT_MIN_GAS_RESERVE;
|
|
68
|
+
}
|
|
61
69
|
function applyChainIdOverride(chain) {
|
|
62
70
|
const raw = process.env.SIM_CHAIN_ID;
|
|
63
71
|
if (!raw || !process.env.SIM_ADDRESSES_FILE) return chain;
|
|
@@ -94,6 +102,7 @@ function isTestnet() {
|
|
|
94
102
|
|
|
95
103
|
export {
|
|
96
104
|
robinhoodTestnet,
|
|
105
|
+
DEFAULT_MIN_GAS_RESERVE,
|
|
97
106
|
CHAIN_REGISTRY,
|
|
98
107
|
VALID_NETWORKS,
|
|
99
108
|
DEFAULT_NETWORK,
|
|
@@ -101,6 +110,7 @@ export {
|
|
|
101
110
|
getNetwork,
|
|
102
111
|
withNetwork,
|
|
103
112
|
getChainConfig,
|
|
113
|
+
getMinGasReserve,
|
|
104
114
|
applyChainIdOverride,
|
|
105
115
|
getChain,
|
|
106
116
|
getRpcUrls,
|
|
@@ -108,4 +118,4 @@ export {
|
|
|
108
118
|
getExplorerUrl,
|
|
109
119
|
isTestnet
|
|
110
120
|
};
|
|
111
|
-
//# sourceMappingURL=chunk-
|
|
121
|
+
//# sourceMappingURL=chunk-DXJJMRBM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/network.ts"],"sourcesContent":["/**\n * Network state singleton.\n *\n * Called once at CLI startup via the --chain flag's preAction hook.\n * Every other module reads from here — never hardcodes a chain.\n *\n * Current deployment target: Robinhood L2 testnet (chain 46630) only. Sherwood\n * launches on Robinhood first; other chains may be added back later, at which\n * point they re-enter the Network union + CHAIN_REGISTRY below.\n */\n\nimport { type Chain, defineChain, parseEther } from \"viem\";\nimport { getConfigRpcUrl } from \"./config.js\";\n\n// ── Robinhood L2 Testnet (Arbitrum Orbit, chain ID 46630) ──\n\nexport const robinhoodTestnet = defineChain({\n id: 46630,\n name: \"Robinhood Chain Testnet\",\n nativeCurrency: { name: \"Ethereum\", symbol: \"ETH\", decimals: 18 },\n rpcUrls: {\n default: { http: [\"https://rpc.testnet.chain.robinhood.com\"] },\n },\n blockExplorers: {\n default: {\n name: \"Blockscout\",\n url: \"https://explorer.testnet.chain.robinhood.com\",\n },\n },\n testnet: true,\n});\n\n// ── Types ──\n\nexport type Network = \"robinhood-testnet\";\n\nexport interface ChainConfig {\n chain: Chain;\n /**\n * Ordered list of public RPC URLs tried in sequence when no user RPC is set.\n * First entry is the primary; the rest are fallbacks used transparently via\n * viem's `fallback` transport on rate-limit / network errors.\n */\n rpcFallbacks: string[];\n /** Legacy env var for backwards compat (optional per chain) */\n rpcEnvVar?: string;\n explorerHost: string;\n /** EAS GraphQL endpoint — null if EAS is not available on this chain */\n easGraphqlUrl: string | null;\n /** EAS scan host — null if unavailable */\n easScanHost: string | null;\n xmtpEnv: \"production\" | \"dev\";\n isTestnet: boolean;\n /**\n * ETH held back for gas in the native-ETH-wrap deposit path — the floor and\n * fallback for the live per-tx cushion estimate (`estimateGasCushion` in\n * client.ts), NOT a fixed requirement. High-fee chains (Base) want a\n * Base-scale reserve; near-zero-fee chains (Robinhood testnet, ~14-wei base\n * fee) want a tiny one so a valid deposit isn't rejected client-side. Unset →\n * `DEFAULT_MIN_GAS_RESERVE`.\n */\n minGasReserve?: bigint;\n}\n\n/**\n * Base-scale default reserve, used when a chain omits `minGasReserve`. Matches\n * the old hardcoded 0.0005-ETH cushion so higher-fee chains keep prior behavior.\n */\nexport const DEFAULT_MIN_GAS_RESERVE = parseEther(\"0.0005\");\n\n// ── Chain Registry ──\n\nexport const CHAIN_REGISTRY: Record<Network, ChainConfig> = {\n \"robinhood-testnet\": {\n chain: robinhoodTestnet,\n rpcFallbacks: [\"https://rpc.testnet.chain.robinhood.com\"],\n rpcEnvVar: \"ROBINHOOD_TESTNET_RPC_URL\",\n explorerHost: \"explorer.testnet.chain.robinhood.com\",\n easGraphqlUrl: null,\n easScanHost: null,\n xmtpEnv: \"production\",\n isTestnet: true,\n // ~14-wei base fee: a full wrap+approve+deposit sequence costs a few\n // million wei (~1e-11 ETH). 0.00002 ETH is a generous floor that still\n // leaves a 0.00058-ETH wallet room to wrap 0.0005 and deposit.\n minGasReserve: parseEther(\"0.00002\"),\n },\n};\n\nexport const VALID_NETWORKS = Object.keys(CHAIN_REGISTRY) as Network[];\n\nexport const DEFAULT_NETWORK: Network = \"robinhood-testnet\";\n\n// ── Singleton state ──\n\nlet _network: Network = DEFAULT_NETWORK;\n\nexport function setNetwork(n: Network) {\n const config = CHAIN_REGISTRY[n];\n if (!config) {\n throw new Error(\n `Unknown network: ${n}. Valid: ${VALID_NETWORKS.join(\", \")}`,\n );\n }\n _network = n;\n}\n\nexport function getNetwork(): Network {\n return _network;\n}\n\n/**\n * Run `fn` with the network singleton temporarily switched to `network`,\n * restoring the previous network in `finally`.\n *\n * The viem clients (`getPublicClient`, `getWalletClient`) auto-invalidate on\n * chain change, so callers get fresh per-chain RPC + chain context inside the\n * block. Used for cross-chain fund resolution.\n */\nexport async function withNetwork<T>(\n network: Network,\n fn: () => Promise<T>,\n): Promise<T> {\n const previous = _network;\n _network = network;\n try {\n return await fn();\n } finally {\n _network = previous;\n }\n}\n\nexport function getChainConfig(): ChainConfig {\n return CHAIN_REGISTRY[_network];\n}\n\n/**\n * Per-chain ETH gas reserve floor/fallback for the ETH-wrap deposit path.\n * Falls back to the Base-scale default when the active chain doesn't set one.\n */\nexport function getMinGasReserve(): bigint {\n return CHAIN_REGISTRY[_network].minGasReserve ?? DEFAULT_MIN_GAS_RESERVE;\n}\n\n/**\n * Dev/CI-only chain-id override (`SIM_CHAIN_ID`) for custom-chainId vnet forks.\n * viem asserts the node's chainId matches the chain definition on every write,\n * so signing for such a fork requires the id to be swapped at the source.\n *\n * Interlock: honored ONLY while `SIM_ADDRESSES_FILE` is also set (the vnet\n * e2e harness's address override). A bare SIM_CHAIN_ID does nothing, so this\n * can never redirect signing on a real network run.\n */\nexport function applyChainIdOverride(chain: Chain): Chain {\n const raw = process.env.SIM_CHAIN_ID;\n if (!raw || !process.env.SIM_ADDRESSES_FILE) return chain;\n const id = Number(raw);\n if (!Number.isInteger(id) || id <= 0) return chain;\n return { ...chain, id };\n}\n\nexport function getChain(): Chain {\n return applyChainIdOverride(CHAIN_REGISTRY[_network].chain);\n}\n\n/**\n * Ordered list of RPC URLs to try, deduped:\n * 1. User config (~/.sherwood/config.json) — honored first\n * 2. Legacy env var (ROBINHOOD_TESTNET_RPC_URL)\n * 3. Public fallback list from CHAIN_REGISTRY\n *\n * Fed to viem's `fallback()` transport so rate-limited RPCs transparently\n * advance to the next entry. See issue #182.\n */\nexport function getRpcUrls(): string[] {\n const cfg = CHAIN_REGISTRY[_network];\n const urls: string[] = [];\n\n const fromConfig = getConfigRpcUrl(_network);\n if (fromConfig) urls.push(fromConfig);\n\n if (cfg.rpcEnvVar && process.env[cfg.rpcEnvVar]) {\n urls.push(process.env[cfg.rpcEnvVar]!);\n }\n\n // Vnet harness (SIM_CHAIN_ID + SIM_ADDRESSES_FILE interlock): the fork RPC\n // is the ONLY valid endpoint — the public fallbacks point at the real\n // network. viem's fallback() otherwise rotates there on a vnet hiccup and\n // silently estimates gas/fees against MAINNET state (live finding: an\n // approve estimated at 21.9k gas on mainnet — no code at that address —\n // reverted out-of-gas on the vnet where it needs ~46k). A vnet call must\n // fail loudly, never retarget the real chain.\n if (process.env.SIM_CHAIN_ID && process.env.SIM_ADDRESSES_FILE && urls.length > 0) {\n return Array.from(new Set(urls));\n }\n\n urls.push(...cfg.rpcFallbacks);\n\n return Array.from(new Set(urls));\n}\n\nexport function getRpcUrl(): string {\n return getRpcUrls()[0];\n}\n\nexport function getExplorerUrl(txHash: string): string {\n return `https://${CHAIN_REGISTRY[_network].explorerHost}/tx/${txHash}`;\n}\n\nexport function isTestnet(): boolean {\n return CHAIN_REGISTRY[_network].isTestnet;\n}\n"],"mappings":";;;;;AAWA,SAAqB,aAAa,kBAAkB;AAK7C,IAAM,mBAAmB,YAAY;AAAA,EAC1C,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,gBAAgB,EAAE,MAAM,YAAY,QAAQ,OAAO,UAAU,GAAG;AAAA,EAChE,SAAS;AAAA,IACP,SAAS,EAAE,MAAM,CAAC,yCAAyC,EAAE;AAAA,EAC/D;AAAA,EACA,gBAAgB;AAAA,IACd,SAAS;AAAA,MACP,MAAM;AAAA,MACN,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EACA,SAAS;AACX,CAAC;AAsCM,IAAM,0BAA0B,WAAW,QAAQ;AAInD,IAAM,iBAA+C;AAAA,EAC1D,qBAAqB;AAAA,IACnB,OAAO;AAAA,IACP,cAAc,CAAC,yCAAyC;AAAA,IACxD,WAAW;AAAA,IACX,cAAc;AAAA,IACd,eAAe;AAAA,IACf,aAAa;AAAA,IACb,SAAS;AAAA,IACT,WAAW;AAAA;AAAA;AAAA;AAAA,IAIX,eAAe,WAAW,SAAS;AAAA,EACrC;AACF;AAEO,IAAM,iBAAiB,OAAO,KAAK,cAAc;AAEjD,IAAM,kBAA2B;AAIxC,IAAI,WAAoB;AAEjB,SAAS,WAAW,GAAY;AACrC,QAAM,SAAS,eAAe,CAAC;AAC/B,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI;AAAA,MACR,oBAAoB,CAAC,YAAY,eAAe,KAAK,IAAI,CAAC;AAAA,IAC5D;AAAA,EACF;AACA,aAAW;AACb;AAEO,SAAS,aAAsB;AACpC,SAAO;AACT;AAUA,eAAsB,YACpB,SACA,IACY;AACZ,QAAM,WAAW;AACjB,aAAW;AACX,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,UAAE;AACA,eAAW;AAAA,EACb;AACF;AAEO,SAAS,iBAA8B;AAC5C,SAAO,eAAe,QAAQ;AAChC;AAMO,SAAS,mBAA2B;AACzC,SAAO,eAAe,QAAQ,EAAE,iBAAiB;AACnD;AAWO,SAAS,qBAAqB,OAAqB;AACxD,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,mBAAoB,QAAO;AACpD,QAAM,KAAK,OAAO,GAAG;AACrB,MAAI,CAAC,OAAO,UAAU,EAAE,KAAK,MAAM,EAAG,QAAO;AAC7C,SAAO,EAAE,GAAG,OAAO,GAAG;AACxB;AAEO,SAAS,WAAkB;AAChC,SAAO,qBAAqB,eAAe,QAAQ,EAAE,KAAK;AAC5D;AAWO,SAAS,aAAuB;AACrC,QAAM,MAAM,eAAe,QAAQ;AACnC,QAAM,OAAiB,CAAC;AAExB,QAAM,aAAa,gBAAgB,QAAQ;AAC3C,MAAI,WAAY,MAAK,KAAK,UAAU;AAEpC,MAAI,IAAI,aAAa,QAAQ,IAAI,IAAI,SAAS,GAAG;AAC/C,SAAK,KAAK,QAAQ,IAAI,IAAI,SAAS,CAAE;AAAA,EACvC;AASA,MAAI,QAAQ,IAAI,gBAAgB,QAAQ,IAAI,sBAAsB,KAAK,SAAS,GAAG;AACjF,WAAO,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC;AAAA,EACjC;AAEA,OAAK,KAAK,GAAG,IAAI,YAAY;AAE7B,SAAO,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC;AACjC;AAEO,SAAS,YAAoB;AAClC,SAAO,WAAW,EAAE,CAAC;AACvB;AAEO,SAAS,eAAe,QAAwB;AACrD,SAAO,WAAW,eAAe,QAAQ,EAAE,YAAY,OAAO,MAAM;AACtE;AAEO,SAAS,YAAqB;AACnC,SAAO,eAAe,QAAQ,EAAE;AAClC;","names":[]}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
EAS_CONTRACTS,
|
|
3
3
|
EAS_SCHEMAS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IFL5SREW.js";
|
|
5
5
|
import {
|
|
6
6
|
getAccount,
|
|
7
7
|
getPublicClient,
|
|
8
8
|
waitForReceipt,
|
|
9
9
|
writeContractWithRetry
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-ROKE6ZAW.js";
|
|
11
11
|
import {
|
|
12
12
|
CHAIN_REGISTRY,
|
|
13
13
|
getChain,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
getNetwork,
|
|
16
16
|
isTestnet,
|
|
17
17
|
withNetwork
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-DXJJMRBM.js";
|
|
19
19
|
import {
|
|
20
20
|
EAS_ABI
|
|
21
21
|
} from "./chunk-BQMOE4FJ.js";
|
|
@@ -453,4 +453,4 @@ export {
|
|
|
453
453
|
queryApprovals,
|
|
454
454
|
queryJoinRequests
|
|
455
455
|
};
|
|
456
|
-
//# sourceMappingURL=chunk-
|
|
456
|
+
//# sourceMappingURL=chunk-GU5VZGXB.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getNetwork
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-DXJJMRBM.js";
|
|
4
4
|
|
|
5
5
|
// src/lib/addresses.ts
|
|
6
6
|
import { isAddress } from "viem";
|
|
@@ -305,4 +305,4 @@ export {
|
|
|
305
305
|
SYNTHRA,
|
|
306
306
|
CHAINLINK
|
|
307
307
|
};
|
|
308
|
-
//# sourceMappingURL=chunk-
|
|
308
|
+
//# sourceMappingURL=chunk-IFL5SREW.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getAccount
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ROKE6ZAW.js";
|
|
4
4
|
import {
|
|
5
5
|
getVeniceApiKey,
|
|
6
6
|
setVeniceApiKey
|
|
@@ -186,4 +186,4 @@ export {
|
|
|
186
186
|
chatCompletion,
|
|
187
187
|
listModels
|
|
188
188
|
};
|
|
189
|
-
//# sourceMappingURL=chunk-
|
|
189
|
+
//# sourceMappingURL=chunk-NPWYX6NU.js.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getChain,
|
|
3
|
+
getMinGasReserve,
|
|
3
4
|
getRpcUrls
|
|
4
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-DXJJMRBM.js";
|
|
5
6
|
import {
|
|
6
7
|
loadConfig
|
|
7
8
|
} from "./chunk-GSC7PVEO.js";
|
|
@@ -295,14 +296,15 @@ function formatContractError(err) {
|
|
|
295
296
|
return "Transaction nonce conflict \u2014 a previous transaction is still pending. Wait a moment and retry.";
|
|
296
297
|
}
|
|
297
298
|
if (rawMsg.includes("insufficient funds for gas")) {
|
|
298
|
-
return
|
|
299
|
+
return `Insufficient ETH for gas fees. Top up your wallet with ETH on ${getChain().name}.`;
|
|
299
300
|
}
|
|
300
301
|
let cleaned = rawMsg.replace(/ContractFunctionRevertedError:\s*/g, "").replace(/Docs:\s*https:\/\/\S+/g, "").replace(/Version:\s*viem@\S+/g, "").replace(/Request Arguments:[\s\S]*$/m, "").replace(/Contract Call:[\s\S]*?(?=\n\n|\n[A-Z]|$)/m, "").trim();
|
|
301
302
|
const sigMatch = cleaned.match(/signature[:\s]+"?(0x[0-9a-fA-F]{8,})"?/);
|
|
302
303
|
if (sigMatch) {
|
|
303
304
|
const decoded = decodeContractError(sigMatch[1]);
|
|
304
305
|
if (decoded) return decoded.message;
|
|
305
|
-
|
|
306
|
+
const explorer = getChain().blockExplorers?.default?.name ?? "the block explorer";
|
|
307
|
+
cleaned = `Contract reverted with unknown error selector ${sigMatch[1]}. Check the transaction on ${explorer} for details.`;
|
|
306
308
|
}
|
|
307
309
|
return cleaned;
|
|
308
310
|
}
|
|
@@ -383,6 +385,22 @@ async function estimateFeesWithBuffer() {
|
|
|
383
385
|
}
|
|
384
386
|
return { maxFeePerGas: fee, maxPriorityFeePerGas: tip };
|
|
385
387
|
}
|
|
388
|
+
var GAS_UNITS = {
|
|
389
|
+
wrap: 55000n,
|
|
390
|
+
approve: 60000n,
|
|
391
|
+
deposit: 250000n,
|
|
392
|
+
redeem: 250000n
|
|
393
|
+
};
|
|
394
|
+
async function estimateGasCushion(gasUnits, safetyFactor = 2n) {
|
|
395
|
+
const floor = getMinGasReserve();
|
|
396
|
+
try {
|
|
397
|
+
const { maxFeePerGas } = await estimateFeesWithBuffer();
|
|
398
|
+
const derived = gasUnits * maxFeePerGas * safetyFactor;
|
|
399
|
+
return derived > floor ? derived : floor;
|
|
400
|
+
} catch {
|
|
401
|
+
return floor;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
386
404
|
var MAX_RETRIES = 3;
|
|
387
405
|
var RETRY_DELAY_MS = 1500;
|
|
388
406
|
var STUCK_NONCE_CONFIRM_DELAY_MS = 2500;
|
|
@@ -512,10 +530,12 @@ export {
|
|
|
512
530
|
resetClients,
|
|
513
531
|
getAccount,
|
|
514
532
|
estimateFeesWithBuffer,
|
|
533
|
+
GAS_UNITS,
|
|
534
|
+
estimateGasCushion,
|
|
515
535
|
detectStuckNonce,
|
|
516
536
|
unstickWallet,
|
|
517
537
|
sendTxWithRetry,
|
|
518
538
|
writeContractWithRetry,
|
|
519
539
|
waitForReceipt
|
|
520
540
|
};
|
|
521
|
-
//# sourceMappingURL=chunk-
|
|
541
|
+
//# sourceMappingURL=chunk-ROKE6ZAW.js.map
|