@oracle-agent/oracle 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/LICENSE +115 -201
  2. package/README.md +66 -84
  3. package/SECURITY.md +37 -12
  4. package/SETUP.md +207 -272
  5. package/dist/action-receipts.mjs +1 -0
  6. package/dist/action-semantics.mjs +1 -0
  7. package/dist/address-book.mjs +2 -0
  8. package/dist/bin/desk-server.mjs +14 -0
  9. package/dist/bin/oracle-data-mcp.mjs +8 -0
  10. package/dist/bin/oracle-init.mjs +24 -0
  11. package/dist/bin/oracle-public-server.mjs +5 -0
  12. package/dist/bin/oracle-route.mjs +22 -0
  13. package/dist/bin/oracle-scan.mjs +18 -0
  14. package/dist/bin/oracle-upgrade.mjs +21 -0
  15. package/dist/bin/oracle.mjs +68 -0
  16. package/dist/chains.mjs +1 -0
  17. package/dist/cli/commands/auth.mjs +16 -0
  18. package/dist/cli/commands/bootstrap.mjs +18 -0
  19. package/dist/cli/commands/chain.mjs +21 -0
  20. package/dist/cli/commands/chat.mjs +35 -0
  21. package/dist/cli/commands/credential.mjs +1 -0
  22. package/dist/cli/commands/data-mcp.mjs +2 -0
  23. package/dist/cli/commands/data.mjs +12 -0
  24. package/dist/cli/commands/doctor.mjs +5 -0
  25. package/dist/cli/commands/gate.mjs +13 -0
  26. package/dist/cli/commands/help.mjs +1 -0
  27. package/dist/cli/commands/init.mjs +3 -0
  28. package/dist/cli/commands/mcp.mjs +33 -0
  29. package/dist/cli/commands/model.mjs +44 -0
  30. package/dist/cli/commands/prepare.mjs +2 -0
  31. package/dist/cli/commands/public.mjs +3 -0
  32. package/dist/cli/commands/route.mjs +2 -0
  33. package/dist/cli/commands/runner.mjs +1 -0
  34. package/dist/cli/commands/scan.mjs +2 -0
  35. package/dist/cli/commands/setup.mjs +34 -0
  36. package/dist/cli/commands/sign.mjs +4 -0
  37. package/dist/cli/commands/signer.mjs +1 -0
  38. package/dist/cli/commands/upgrade.mjs +2 -0
  39. package/dist/cli/commands/vault.mjs +1 -0
  40. package/dist/cli/commands/version.mjs +2 -0
  41. package/dist/data/desk-data.mjs +12 -0
  42. package/dist/index.mjs +17 -0
  43. package/dist/nft-gas-war-guard.mjs +1 -0
  44. package/dist/onboarding/harness-configs.mjs +4 -0
  45. package/dist/portfolio-risk.mjs +1 -0
  46. package/dist/prepare-envelope.mjs +1 -0
  47. package/dist/public-control/policy-schema.mjs +1 -0
  48. package/dist/router/index.mjs +2 -0
  49. package/dist/scanner/index.mjs +4 -0
  50. package/dist/signals/index.mjs +1 -0
  51. package/dist/watch-preferences.mjs +1 -0
  52. package/package.json +27 -65
  53. package/public/oracle-splash/index.html +11 -1
  54. package/CONTRIBUTING.md +0 -98
  55. package/bin/desk-server.mjs +0 -440
  56. package/bin/oracle-data-mcp.mjs +0 -1019
  57. package/bin/oracle-init.mjs +0 -496
  58. package/bin/oracle-public-server.mjs +0 -36
  59. package/bin/oracle-route.mjs +0 -254
  60. package/bin/oracle-scan.mjs +0 -192
  61. package/bin/oracle-upgrade.mjs +0 -42
  62. package/bin/oracle.mjs +0 -33
  63. package/docs/adding-a-chain.md +0 -229
  64. package/docs/architecture.md +0 -138
  65. package/docs/cli.md +0 -47
  66. package/docs/connectors.md +0 -13
  67. package/docs/oracle-pack-standard.md +0 -29
  68. package/docs/profiles.md +0 -151
  69. package/docs/public-surface.md +0 -133
  70. package/examples/add-a-chain.mjs +0 -65
  71. package/examples/oracle-pack-template.mjs +0 -38
  72. package/examples/research-a-token.mjs +0 -70
  73. package/plugins/oracle-owner-gate/__init__.py +0 -227
  74. package/plugins/oracle-owner-gate/plugin.yaml +0 -9
  75. package/profiles/_template/SOUL.md +0 -54
  76. package/profiles/_template/profile.json +0 -22
  77. package/profiles/bitcoin-agent/SOUL.md +0 -31
  78. package/profiles/bitcoin-agent/profile.json +0 -32
  79. package/profiles/hyperliquid-agent/SOUL.md +0 -34
  80. package/profiles/hyperliquid-agent/profile.json +0 -37
  81. package/profiles/oracle/SOUL.md +0 -107
  82. package/profiles/oracle/profile.json +0 -39
  83. package/profiles/polymarket-agent/SOUL.md +0 -35
  84. package/profiles/polymarket-agent/profile.json +0 -34
  85. package/profiles/profile.schema.json +0 -90
  86. package/profiles/protocol-builder/SOUL.md +0 -57
  87. package/profiles/protocol-builder/profile.json +0 -39
  88. package/profiles/robinhood-agent/SOUL.md +0 -53
  89. package/profiles/robinhood-agent/profile.json +0 -40
  90. package/profiles/solana-agent/SOUL.md +0 -37
  91. package/profiles/solana-agent/profile.json +0 -37
  92. package/profiles/stable-agent/SOUL.md +0 -43
  93. package/profiles/stable-agent/profile.json +0 -37
  94. package/protocols/templates/safe-erc20/SECURITY.md +0 -16
  95. package/protocols/templates/safe-erc20/foundry.toml +0 -12
  96. package/protocols/templates/safe-erc20/remappings.txt +0 -2
  97. package/protocols/templates/safe-erc20/src/SafeERC20.sol +0 -53
  98. package/protocols/templates/safe-erc20/test/SafeERC20.t.sol +0 -72
  99. package/scripts/adversarial-bench.mjs +0 -114
  100. package/scripts/build-inscription.py +0 -230
  101. package/scripts/check-doc-drift.mjs +0 -123
  102. package/scripts/check-test-count.mjs +0 -105
  103. package/scripts/e2e-hl-markets.mjs +0 -21
  104. package/scripts/e2e-hl-perps.mjs +0 -48
  105. package/scripts/e2e-hypercore-staking.mjs +0 -128
  106. package/scripts/e2e-solana-bitcoin.mjs +0 -183
  107. package/scripts/protocol-template-gate.mjs +0 -15
  108. package/scripts/public-api-scan.mjs +0 -23
  109. package/scripts/secret-scan.mjs +0 -181
  110. package/scripts/verify-v3-venues.mjs +0 -192
  111. package/skills/balance/SKILL.md +0 -176
  112. package/skills/oracle-action-semantics/SKILL.md +0 -40
  113. package/skills/oracle-best-execution/SKILL.md +0 -127
  114. package/skills/oracle-bitcoin/SKILL.md +0 -53
  115. package/skills/oracle-chain-graphs-telegram-cards/SKILL.md +0 -59
  116. package/skills/oracle-chat/SKILL.md +0 -61
  117. package/skills/oracle-chat/chain.SKILL.md +0 -31
  118. package/skills/oracle-chat/setup.SKILL.md +0 -37
  119. package/skills/oracle-circuit-breaker/SKILL.md +0 -51
  120. package/skills/oracle-contract-research/SKILL.md +0 -55
  121. package/skills/oracle-desk/SKILL.md +0 -58
  122. package/skills/oracle-dex-launch/SKILL.md +0 -38
  123. package/skills/oracle-grants/SKILL.md +0 -69
  124. package/skills/oracle-hypercore-staking/SKILL.md +0 -57
  125. package/skills/oracle-hyperliquid/SKILL.md +0 -56
  126. package/skills/oracle-meme-token-sniper/SKILL.md +0 -73
  127. package/skills/oracle-multichain-nft-launch/SKILL.md +0 -338
  128. package/skills/oracle-multichain-token-launch/SKILL.md +0 -300
  129. package/skills/oracle-nft-gacha-launch/SKILL.md +0 -48
  130. package/skills/oracle-nft-mint-gas-war/SKILL.md +0 -63
  131. package/skills/oracle-polymarket/SKILL.md +0 -60
  132. package/skills/oracle-protocol-builder/SKILL.md +0 -59
  133. package/skills/oracle-protocol-security/SKILL.md +0 -60
  134. package/skills/oracle-public-product/SKILL.md +0 -44
  135. package/skills/oracle-receipts/SKILL.md +0 -52
  136. package/skills/oracle-rfq-tokenized-assets/SKILL.md +0 -69
  137. package/skills/oracle-smart-wallet-scanner/SKILL.md +0 -49
  138. package/skills/oracle-solana/SKILL.md +0 -65
  139. package/skills/oracle-solana-nft/SKILL.md +0 -54
  140. package/skills/oracle-token-research/SKILL.md +0 -67
  141. package/skins/oracle.yaml +0 -56
  142. package/src/action-receipts.mjs +0 -265
  143. package/src/action-semantics.mjs +0 -62
  144. package/src/address-book.mjs +0 -208
  145. package/src/agent-auth.mjs +0 -206
  146. package/src/approval-guard.mjs +0 -282
  147. package/src/attestation-secret.mjs +0 -88
  148. package/src/audit-log.mjs +0 -196
  149. package/src/auth/oauth.mjs +0 -672
  150. package/src/auto-slippage.mjs +0 -378
  151. package/src/capability-posture.mjs +0 -125
  152. package/src/chains.mjs +0 -62
  153. package/src/cli/chain-catalog.mjs +0 -215
  154. package/src/cli/chain-state.mjs +0 -74
  155. package/src/cli/commands/auth.mjs +0 -193
  156. package/src/cli/commands/bootstrap.mjs +0 -87
  157. package/src/cli/commands/chain.mjs +0 -143
  158. package/src/cli/commands/chat.mjs +0 -434
  159. package/src/cli/commands/credential.mjs +0 -9
  160. package/src/cli/commands/data-mcp.mjs +0 -18
  161. package/src/cli/commands/data.mjs +0 -75
  162. package/src/cli/commands/doctor.mjs +0 -136
  163. package/src/cli/commands/help.mjs +0 -7
  164. package/src/cli/commands/init.mjs +0 -27
  165. package/src/cli/commands/mcp.mjs +0 -142
  166. package/src/cli/commands/model.mjs +0 -99
  167. package/src/cli/commands/prepare.mjs +0 -12
  168. package/src/cli/commands/public.mjs +0 -20
  169. package/src/cli/commands/route.mjs +0 -12
  170. package/src/cli/commands/runner.mjs +0 -9
  171. package/src/cli/commands/scan.mjs +0 -12
  172. package/src/cli/commands/setup.mjs +0 -275
  173. package/src/cli/commands/sign.mjs +0 -21
  174. package/src/cli/commands/signer.mjs +0 -9
  175. package/src/cli/commands/upgrade.mjs +0 -12
  176. package/src/cli/commands/vault.mjs +0 -9
  177. package/src/cli/commands/version.mjs +0 -22
  178. package/src/cli/first-run.mjs +0 -23
  179. package/src/cli/kernel.mjs +0 -239
  180. package/src/cli/mcp-targets/chatgpt.mjs +0 -51
  181. package/src/cli/mcp-targets/claude-code.mjs +0 -39
  182. package/src/cli/mcp-targets/claude-desktop.mjs +0 -24
  183. package/src/cli/mcp-targets/codex.mjs +0 -41
  184. package/src/cli/mcp-targets/shared.mjs +0 -61
  185. package/src/cli/messaging-platforms.mjs +0 -209
  186. package/src/cli/model-config.mjs +0 -70
  187. package/src/cli/operator-dispatch.mjs +0 -258
  188. package/src/cli/oracle-harness.py +0 -415
  189. package/src/cli/paths.mjs +0 -83
  190. package/src/cli/runtime.mjs +0 -351
  191. package/src/cli/setup-state.mjs +0 -168
  192. package/src/cli/spawn-child.mjs +0 -43
  193. package/src/data/catalog.mjs +0 -585
  194. package/src/data/desk-data.mjs +0 -695
  195. package/src/data/http.mjs +0 -253
  196. package/src/data/provider-endpoint.mjs +0 -94
  197. package/src/data/providers/aerodrome.mjs +0 -245
  198. package/src/data/providers/balancer.mjs +0 -209
  199. package/src/data/providers/bitcoin-esplora.mjs +0 -216
  200. package/src/data/providers/bitcoin-meta.mjs +0 -378
  201. package/src/data/providers/blockscout.mjs +0 -14
  202. package/src/data/providers/bridges.mjs +0 -242
  203. package/src/data/providers/cowswap.mjs +0 -415
  204. package/src/data/providers/curve.mjs +0 -201
  205. package/src/data/providers/defillama.mjs +0 -88
  206. package/src/data/providers/dexscreener.mjs +0 -43
  207. package/src/data/providers/evm-rpc.mjs +0 -225
  208. package/src/data/providers/geckoterminal.mjs +0 -34
  209. package/src/data/providers/gmx.mjs +0 -496
  210. package/src/data/providers/hl-assets.mjs +0 -165
  211. package/src/data/providers/hl-info.mjs +0 -108
  212. package/src/data/providers/hl-markets.mjs +0 -210
  213. package/src/data/providers/hl-outcome.mjs +0 -61
  214. package/src/data/providers/hl-perps.mjs +0 -387
  215. package/src/data/providers/hl-staking.mjs +0 -353
  216. package/src/data/providers/hl-ws.mjs +0 -119
  217. package/src/data/providers/hyperevm-dex.mjs +0 -49
  218. package/src/data/providers/jupiter-venues.mjs +0 -119
  219. package/src/data/providers/jupiter.mjs +0 -315
  220. package/src/data/providers/lifi.mjs +0 -151
  221. package/src/data/providers/magiceden-sol.mjs +0 -406
  222. package/src/data/providers/morpho.mjs +0 -177
  223. package/src/data/providers/nft-gallery.mjs +0 -163
  224. package/src/data/providers/nft-portfolio.mjs +0 -494
  225. package/src/data/providers/odos.mjs +0 -156
  226. package/src/data/providers/oneinch.mjs +0 -174
  227. package/src/data/providers/opensea-multichain.mjs +0 -136
  228. package/src/data/providers/opensea-nft.mjs +0 -371
  229. package/src/data/providers/paraswap.mjs +0 -118
  230. package/src/data/providers/pendle.mjs +0 -188
  231. package/src/data/providers/poly-clob.mjs +0 -283
  232. package/src/data/providers/poly-public.mjs +0 -96
  233. package/src/data/providers/poly-ws.mjs +0 -103
  234. package/src/data/providers/portfolio-history.mjs +0 -394
  235. package/src/data/providers/portfolio.mjs +0 -594
  236. package/src/data/providers/rfq.mjs +0 -15
  237. package/src/data/providers/rh-agent.mjs +0 -59
  238. package/src/data/providers/satflow.mjs +0 -341
  239. package/src/data/providers/signed-material-guard.mjs +0 -108
  240. package/src/data/providers/solana-rpc.mjs +0 -197
  241. package/src/data/providers/uniswap-v3.mjs +0 -349
  242. package/src/data/providers/uniswap-v4.mjs +0 -414
  243. package/src/data/providers/zerox.mjs +0 -167
  244. package/src/data/public-api-scan.mjs +0 -61
  245. package/src/data/quote-placeholder.mjs +0 -31
  246. package/src/exact-integer.mjs +0 -72
  247. package/src/exec-policy.mjs +0 -455
  248. package/src/flags.mjs +0 -15
  249. package/src/fresh-window.mjs +0 -76
  250. package/src/gmx-attestation.mjs +0 -176
  251. package/src/index.mjs +0 -100
  252. package/src/nft-gas-war-guard.mjs +0 -139
  253. package/src/onboarding/agent-keys.mjs +0 -161
  254. package/src/onboarding/harness-configs.mjs +0 -102
  255. package/src/onboarding/index.mjs +0 -18
  256. package/src/onboarding/tiers.mjs +0 -139
  257. package/src/oracle-env.mjs +0 -47
  258. package/src/portfolio-risk.mjs +0 -170
  259. package/src/prepare-envelope.mjs +0 -204
  260. package/src/profile-upgrade.mjs +0 -277
  261. package/src/protocol-execution.mjs +0 -84
  262. package/src/protocol-templates/gate.mjs +0 -179
  263. package/src/protocol-templates/prepare-deploy.mjs +0 -81
  264. package/src/public-api/buzz-integration.mjs +0 -256
  265. package/src/public-api/connect-agent.mjs +0 -416
  266. package/src/public-api/grants.mjs +0 -142
  267. package/src/public-api/http.mjs +0 -389
  268. package/src/public-control/aa-adapter.mjs +0 -402
  269. package/src/public-control/build-registry.mjs +0 -227
  270. package/src/public-control/bundler-client.mjs +0 -357
  271. package/src/public-control/grant-indexer.mjs +0 -296
  272. package/src/public-control/policy-render.mjs +0 -69
  273. package/src/public-control/policy-schema.mjs +0 -318
  274. package/src/public-control/runtime-config.mjs +0 -275
  275. package/src/public-control/session-key-model.mjs +0 -374
  276. package/src/public-control/session-orchestrator.mjs +0 -412
  277. package/src/rfq/intent.mjs +0 -180
  278. package/src/rfq/sources.mjs +0 -181
  279. package/src/route-attestation.mjs +0 -132
  280. package/src/router/best-execution.mjs +0 -326
  281. package/src/router/index.mjs +0 -226
  282. package/src/router/prepare-bridge.mjs +0 -289
  283. package/src/router/prepare-route.mjs +0 -398
  284. package/src/router/proposal.mjs +0 -311
  285. package/src/router/risk-classifier.mjs +0 -119
  286. package/src/router/route-sources.mjs +0 -364
  287. package/src/scanner/chains.config.mjs +0 -430
  288. package/src/scanner/contract.mjs +0 -270
  289. package/src/scanner/evm-scanner.mjs +0 -394
  290. package/src/scanner/index.mjs +0 -9
  291. package/src/scanner/v2-venue.mjs +0 -335
  292. package/src/scanner/v3-venue.mjs +0 -290
  293. package/src/scopes.mjs +0 -44
  294. package/src/sell-simulation.mjs +0 -167
  295. package/src/signals/engine.mjs +0 -146
  296. package/src/signals/index.mjs +0 -1
  297. package/src/token-transfer-guard.mjs +0 -188
  298. package/src/tui/app.mjs +0 -438
  299. package/src/tui/backend.mjs +0 -145
  300. package/src/tui/format.mjs +0 -272
  301. package/src/tui/gateway-client.mjs +0 -177
  302. package/src/tui/input.mjs +0 -501
  303. package/src/tui/renderer.mjs +0 -443
  304. package/src/tui/standalone-client.mjs +0 -666
  305. package/src/tui/theme.mjs +0 -81
  306. package/src/vault-attestation.mjs +0 -146
  307. package/src/venues.mjs +0 -206
  308. package/src/watch-preferences.mjs +0 -85
@@ -1,69 +0,0 @@
1
- // Oracle Control — human-readable grant renderer (Slice A).
2
- //
3
- // Renders a validated public grant into deterministic plain text a user can
4
- // review before approving. Rendering is a PRESENTATION of the deterministic
5
- // policy only — it never adds, removes, or reinterprets authority, and it only
6
- // ever surfaces public grant material (no keys, tokens, paths, or secrets).
7
- //
8
- // Output is byte-for-byte deterministic for a given grant: fixed field order,
9
- // fixed labels, UTC timestamps derived purely from expiresAt, and the sha256
10
- // grant id from the canonical form. Tests assert exact output.
11
-
12
- import { normalizeGrant, grantId, isReadonlyAction, GRANT_VERSION } from "./policy-schema.mjs";
13
-
14
- const LABEL_WIDTH = 14;
15
-
16
- function row(label, value) {
17
- return `${(label + ":").padEnd(LABEL_WIDTH)}${value}`;
18
- }
19
-
20
- /** Deterministic UTC ISO string from unix seconds. */
21
- function isoUtc(unixSeconds) {
22
- return new Date(unixSeconds * 1000).toISOString();
23
- }
24
-
25
- /** "50 bps (0.50%)" — deterministic fixed-2 percentage. */
26
- export function formatBps(bps) {
27
- return `${bps} bps (${(bps / 100).toFixed(2)}%)`;
28
- }
29
-
30
- /** Group wei digits for readability: 1000000 -> "1,000,000". Deterministic. */
31
- export function formatWei(weiString) {
32
- const s = String(weiString);
33
- return `${s.replace(/\B(?=(\d{3})+(?!\d))/g, ",")} wei`;
34
- }
35
-
36
- /**
37
- * Render a grant as deterministic human-readable text.
38
- * Validates/normalizes first (throws GrantValidationError on bad input), so a
39
- * grant that cannot be rendered is a grant that cannot be authorized.
40
- */
41
- export function renderGrant(input, opts = {}) {
42
- const g = normalizeGrant(input, opts);
43
- const id = grantId(g);
44
- const readonlyOnly = g.actions.every((a) => isReadonlyAction(a));
45
-
46
- const lines = [
47
- "ORACLE CONTROL GRANT (deterministic authorization)",
48
- "==================================================",
49
- row("Grant ID", id),
50
- row("Version", String(GRANT_VERSION)),
51
- row("Chain", String(g.chainId)),
52
- row("Agent", g.agentAddress),
53
- row("Account", g.accountAddress),
54
- row("Actions", g.actions.join(", ")),
55
- row("Targets", g.targets.length ? g.targets.join(", ") : "(none — read/simulate only)"),
56
- row("Max value", formatWei(g.maxValueWei)),
57
- row("Max gas", formatWei(g.maxGasWei)),
58
- row("Max slippage", formatBps(g.maxSlippageBps)),
59
- row("Expires", `${isoUtc(g.expiresAt)} (unix ${g.expiresAt})`),
60
- row("Nonce", g.nonce),
61
- row("Revocation", g.revocationKey),
62
- "--------------------------------------------------",
63
- readonlyOnly
64
- ? "Scope: read/simulate only — this grant cannot move funds."
65
- : "Scope: includes state-changing actions bounded by the caps above.",
66
- "Self-custodial: this grant contains public data only and can be revoked at any time via the revocation key.",
67
- ];
68
- return lines.join("\n");
69
- }
@@ -1,318 +0,0 @@
1
- // Oracle Control — public grant policy schema (Slice A).
2
- //
3
- // Oracle Control is DETERMINISTIC AUTHORIZATION: a grant either validates or it
4
- // does not, with no advisory judgement involved (that is Oracle Router's job,
5
- // and Router output must never gate anything here).
6
- //
7
- // This module is dependency-free (node builtins only, no npm packages) and
8
- // fully deterministic: same input object => same normalized grant => same
9
- // canonical string => same grant id, regardless of key order, address casing,
10
- // array ordering, or numeric representation (number / bigint / decimal string).
11
- //
12
- // Self-custody boundary: a grant only ever references PUBLIC material —
13
- // chain id, the agent's public address, the user's own account address,
14
- // action scopes, target contracts, spend/gas/slippage ceilings, expiry,
15
- // nonce, and a public revocation key identifier. Nothing here may carry or
16
- // derive private keys, bearer tokens, keystore paths, or session secrets.
17
- //
18
- // Fail-closed rules enforced by validateGrant / normalizeGrant:
19
- // - every required field must be present (expiry, chain, agent, account, ...)
20
- // - unknown fields are rejected (no smuggling extra authority)
21
- // - broad wildcard actions are rejected by default ("*", "*:*", "verb:*")
22
- // - empty targets are only allowed when EVERY action is read/simulate scoped
23
- // - expiresAt is required and, when a reference `now` is supplied, must be
24
- // strictly in the future
25
-
26
- import { createHash } from "node:crypto";
27
-
28
- export const GRANT_VERSION = 1;
29
-
30
- /** Every field is required. Order here is documentation only; canonical form
31
- * always sorts keys alphabetically. */
32
- export const REQUIRED_FIELDS = Object.freeze([
33
- "chainId",
34
- "agentAddress",
35
- "accountAddress",
36
- "actions",
37
- "targets",
38
- "maxValueWei",
39
- "maxGasWei",
40
- "maxSlippageBps",
41
- "expiresAt",
42
- "nonce",
43
- "revocationKey",
44
- ]);
45
-
46
- /** Action verbs that never touch state; only these may have empty targets. */
47
- export const READONLY_ACTION_VERBS = Object.freeze(["read", "simulate"]);
48
-
49
- export const MAX_SLIPPAGE_BPS = 10_000;
50
- export const MAX_NONCE_LENGTH = 128;
51
- export const MAX_REVOCATION_KEY_LENGTH = 256;
52
- export const MAX_ACTIONS = 64;
53
- export const MAX_TARGETS = 256;
54
-
55
- const ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
56
- // verb:resource — lowercase verb, resource may carry dots/dashes/underscores.
57
- const ACTION_RE = /^[a-z][a-z0-9_-]*:[a-z0-9._-]+$/;
58
- // wildcard-bearing action (only accepted when explicitly opted in, and never
59
- // with a wildcard verb).
60
- const ACTION_WILDCARD_RE = /^[a-z][a-z0-9_-]*:\*$/;
61
- const NONCE_RE = /^[A-Za-z0-9._:-]+$/;
62
- const REVOCATION_KEY_RE = /^[A-Za-z0-9._:-]+$/;
63
- const DECIMAL_RE = /^(0|[1-9][0-9]*)$/;
64
-
65
- export class GrantValidationError extends Error {
66
- constructor(errors) {
67
- const lines = errors.map((e) => `${e.field}: ${e.message}`);
68
- super(`invalid grant (${errors.length} error${errors.length === 1 ? "" : "s"}): ${lines.join("; ")}`);
69
- this.name = "GrantValidationError";
70
- this.errors = errors;
71
- }
72
- }
73
-
74
- function isPlainObject(v) {
75
- return v != null && typeof v === "object" && !Array.isArray(v);
76
- }
77
-
78
- /** Parse a non-negative integer amount (number | bigint | decimal string)
79
- * into a canonical decimal string. Returns null when unparseable. */
80
- function toAmountString(v) {
81
- if (typeof v === "bigint") {
82
- return v >= 0n ? v.toString(10) : null;
83
- }
84
- if (typeof v === "number") {
85
- if (!Number.isSafeInteger(v) || v < 0) return null;
86
- return String(v);
87
- }
88
- if (typeof v === "string") {
89
- const s = v.trim();
90
- if (!DECIMAL_RE.test(s)) return null;
91
- return s;
92
- }
93
- return null;
94
- }
95
-
96
- function toSafeInt(v) {
97
- if (typeof v === "bigint") {
98
- if (v < 0n || v > BigInt(Number.MAX_SAFE_INTEGER)) return null;
99
- return Number(v);
100
- }
101
- if (typeof v === "number") {
102
- if (!Number.isSafeInteger(v) || v < 0) return null;
103
- return v;
104
- }
105
- if (typeof v === "string") {
106
- const s = v.trim();
107
- if (!DECIMAL_RE.test(s)) return null;
108
- const n = Number(s);
109
- return Number.isSafeInteger(n) ? n : null;
110
- }
111
- return null;
112
- }
113
-
114
- /** True when the action verb is read-only (read/simulate). */
115
- export function isReadonlyAction(action) {
116
- const verb = String(action).split(":")[0];
117
- return READONLY_ACTION_VERBS.includes(verb);
118
- }
119
-
120
- /**
121
- * Validate a grant. Never throws; returns { ok, errors, grant } where `grant`
122
- * is the normalized form when ok, else null.
123
- *
124
- * Options:
125
- * allowWildcardActions (default false) — permit "verb:*" actions. Broad
126
- * wildcards ("*", "*:*", wildcard verbs) are ALWAYS
127
- * rejected regardless of this flag.
128
- * now (unix seconds) — when provided, expiresAt must be
129
- * strictly greater than it. Pass explicitly for
130
- * deterministic validation; omitted means no liveness
131
- * check (pure shape validation).
132
- */
133
- export function validateGrant(input, opts = {}) {
134
- const errors = [];
135
- const push = (field, message) => errors.push({ field, message });
136
-
137
- if (!isPlainObject(input)) {
138
- push("grant", "grant must be a plain object");
139
- return { ok: false, errors, grant: null };
140
- }
141
-
142
- // Fail closed on unknown fields.
143
- for (const key of Object.keys(input)) {
144
- if (!REQUIRED_FIELDS.includes(key)) push(key, "unknown field is not allowed");
145
- }
146
- for (const key of REQUIRED_FIELDS) {
147
- if (!(key in input) || input[key] == null) push(key, "required field is missing");
148
- }
149
- if (errors.length) return { ok: false, errors, grant: null };
150
-
151
- const out = {};
152
-
153
- // chainId
154
- const chainId = toSafeInt(input.chainId);
155
- if (chainId == null || chainId <= 0) push("chainId", "must be a positive integer chain id");
156
- else out.chainId = chainId;
157
-
158
- // addresses
159
- for (const field of ["agentAddress", "accountAddress"]) {
160
- const v = input[field];
161
- if (typeof v !== "string" || !ADDRESS_RE.test(v.trim())) {
162
- push(field, "must be a 0x-prefixed 20-byte hex address");
163
- } else {
164
- out[field] = v.trim().toLowerCase();
165
- }
166
- }
167
-
168
- // actions
169
- if (!Array.isArray(input.actions) || input.actions.length === 0) {
170
- push("actions", "must be a non-empty array of action scopes");
171
- } else if (input.actions.length > MAX_ACTIONS) {
172
- push("actions", `too many actions (max ${MAX_ACTIONS})`);
173
- } else {
174
- const actions = [];
175
- for (const raw of input.actions) {
176
- const a = typeof raw === "string" ? raw.trim() : null;
177
- if (!a) {
178
- push("actions", "action entries must be non-empty strings");
179
- continue;
180
- }
181
- if (a.includes("*")) {
182
- if (opts.allowWildcardActions === true && ACTION_WILDCARD_RE.test(a)) {
183
- actions.push(a);
184
- } else {
185
- push("actions", `broad wildcard action "${a}" is rejected (fail closed)`);
186
- }
187
- continue;
188
- }
189
- if (!ACTION_RE.test(a)) {
190
- push("actions", `malformed action "${a}" (expected verb:resource)`);
191
- continue;
192
- }
193
- actions.push(a);
194
- }
195
- out.actions = [...new Set(actions)].sort();
196
- }
197
-
198
- // targets
199
- if (!Array.isArray(input.targets)) {
200
- push("targets", "must be an array of contract addresses");
201
- } else if (input.targets.length > MAX_TARGETS) {
202
- push("targets", `too many targets (max ${MAX_TARGETS})`);
203
- } else {
204
- const targets = [];
205
- for (const raw of input.targets) {
206
- const t = typeof raw === "string" ? raw.trim() : null;
207
- if (!t || !ADDRESS_RE.test(t)) {
208
- push("targets", `target "${raw}" must be a 0x-prefixed 20-byte hex address (wildcards not allowed)`);
209
- continue;
210
- }
211
- targets.push(t.toLowerCase());
212
- }
213
- out.targets = [...new Set(targets)].sort();
214
- if (out.targets.length === 0 && Array.isArray(out.actions)) {
215
- const nonReadonly = out.actions.filter((a) => !isReadonlyAction(a));
216
- if (nonReadonly.length > 0 || out.actions.length === 0) {
217
- push(
218
- "targets",
219
- `empty targets are only allowed for read/simulate scopes (blocked by: ${nonReadonly.join(", ") || "no valid actions"})`
220
- );
221
- }
222
- }
223
- }
224
-
225
- // amounts
226
- for (const field of ["maxValueWei", "maxGasWei"]) {
227
- const amt = toAmountString(input[field]);
228
- if (amt == null) push(field, "must be a non-negative integer wei amount");
229
- else out[field] = amt;
230
- }
231
-
232
- // slippage
233
- const bps = toSafeInt(input.maxSlippageBps);
234
- if (bps == null || bps > MAX_SLIPPAGE_BPS) {
235
- push("maxSlippageBps", `must be an integer between 0 and ${MAX_SLIPPAGE_BPS}`);
236
- } else {
237
- out.maxSlippageBps = bps;
238
- }
239
-
240
- // expiry — required (checked above); must be a positive unix-seconds int and,
241
- // when `now` is supplied, strictly in the future.
242
- // Date-renderable ceiling in unix seconds. JS Date maxes at 8.64e15 ms, so a
243
- // seconds value above 8.64e12 overflows the renderer (isoUtc does *1000).
244
- // Also well within the AA lane's uint48 bound, so a schema-valid expiry always
245
- // fits both the on-chain validUntil field and the human render. Reject rather
246
- // than render a bogus far-future date (fail closed on the seconds-vs-ms mistake).
247
- const MAX_UNIX_SECONDS = 8_640_000_000_000;
248
- const expiresAt = toSafeInt(input.expiresAt);
249
- if (expiresAt == null || expiresAt <= 0) {
250
- push("expiresAt", "must be a positive unix-seconds timestamp");
251
- } else if (expiresAt > MAX_UNIX_SECONDS) {
252
- push("expiresAt", "exceeds the max unix-seconds timestamp (pass seconds, not milliseconds)");
253
- } else {
254
- out.expiresAt = expiresAt;
255
- if (opts.now != null) {
256
- const now = toSafeInt(opts.now);
257
- if (now == null) push("expiresAt", "opts.now must be a unix-seconds integer");
258
- else if (expiresAt <= now) push("expiresAt", `grant is expired (expiresAt ${expiresAt} <= now ${now})`);
259
- }
260
- }
261
-
262
- // nonce
263
- const nonce =
264
- typeof input.nonce === "string"
265
- ? input.nonce.trim()
266
- : toSafeInt(input.nonce) != null
267
- ? String(toSafeInt(input.nonce))
268
- : null;
269
- if (!nonce || nonce.length > MAX_NONCE_LENGTH || !NONCE_RE.test(nonce)) {
270
- push("nonce", `must be a non-empty string (max ${MAX_NONCE_LENGTH} chars, [A-Za-z0-9._:-])`);
271
- } else {
272
- out.nonce = nonce;
273
- }
274
-
275
- // revocationKey — a PUBLIC identifier used to revoke this grant; never a secret.
276
- const rk = typeof input.revocationKey === "string" ? input.revocationKey.trim() : null;
277
- if (!rk || rk.length > MAX_REVOCATION_KEY_LENGTH || !REVOCATION_KEY_RE.test(rk)) {
278
- push("revocationKey", `must be a non-empty public identifier (max ${MAX_REVOCATION_KEY_LENGTH} chars, [A-Za-z0-9._:-])`);
279
- } else {
280
- out.revocationKey = rk;
281
- }
282
-
283
- if (errors.length) return { ok: false, errors, grant: null };
284
- return { ok: true, errors: [], grant: out };
285
- }
286
-
287
- /** Validate + normalize; throws GrantValidationError on any failure. */
288
- export function normalizeGrant(input, opts = {}) {
289
- const { ok, errors, grant } = validateGrant(input, opts);
290
- if (!ok) throw new GrantValidationError(errors);
291
- return grant;
292
- }
293
-
294
- /**
295
- * Deterministic canonical JSON for a grant: validates/normalizes first, then
296
- * serializes with alphabetically sorted keys (arrays already sorted + deduped
297
- * by normalization). Identical grants — regardless of input key order, address
298
- * casing, or numeric representation — always produce the identical string.
299
- */
300
- export function canonicalizeGrant(input, opts = {}) {
301
- const g = normalizeGrant(input, opts);
302
- const keys = Object.keys(g).sort();
303
- const parts = keys.map((k) => `${JSON.stringify(k)}:${JSON.stringify(g[k])}`);
304
- return `{"version":${GRANT_VERSION},${parts.join(",")}}`;
305
- }
306
-
307
- /** sha256 hex of the canonical form — stable public identifier for a grant. */
308
- export function grantId(input, opts = {}) {
309
- return createHash("sha256").update(canonicalizeGrant(input, opts), "utf8").digest("hex");
310
- }
311
-
312
- /** Deterministic expiry check against an explicit unix-seconds `now`. */
313
- export function isExpired(grant, nowSeconds) {
314
- const now = toSafeInt(nowSeconds);
315
- const exp = toSafeInt(isPlainObject(grant) ? grant.expiresAt : null);
316
- if (now == null || exp == null) return true; // fail closed
317
- return exp <= now;
318
- }
@@ -1,275 +0,0 @@
1
- // Oracle Control — public runtime config: chain/bundler/paymaster registry
2
- // (Slice K).
3
- //
4
- // This module is pure config parsing. It never makes a live network call and
5
- // never imports the private executor stack — its only job is to turn env
6
- // vars into a validated, in-memory registry of PUBLIC endpoints (chain
7
- // metadata, bundler URLs, paymaster URLs, and the public HTTP bind) that the
8
- // rest of Oracle Control (aa-adapter.mjs, bundler-client.mjs, http.mjs) can
9
- // read from.
10
- //
11
- // Hard boundaries for this file:
12
- // - Imports ONLY from ./aa-adapter.mjs (ENTRYPOINT_V07 — the single source
13
- // of truth for the deployed EntryPoint address this codebase targets)
14
- // and node builtins. NEVER from the private executor stack
15
- // (get-signer.mjs, keystore.mjs, exec-policy.mjs, local-signer/*,
16
- // adapters/*, mint-capability.mjs) — this module must never be wired to
17
- // private operator wallet, and holds no secrets of any kind.
18
- // - bundlerUrl/paymasterUrl are treated as PUBLIC endpoints (the same way a
19
- // public RPC URL is public) — but they are still scanned for anything
20
- // secret-SHAPED (a bearer token, an api-key-looking query param, a raw
21
- // private-key hex blob, a PEM block) and rejected outright if found.
22
- // Fail closed: a config that looks like it's carrying a credential in a
23
- // URL must never load.
24
- // - resolveChain() fails closed on any chainId not in the registry — no
25
- // silent fallback to a made-up chain.
26
- // - entryPoint is never read from env or invented; it is always pinned to
27
- // aa-adapter.mjs's ENTRYPOINT_V07 and asserted equal for every seeded
28
- // chain, so a typo/drift in this file can never point a chain at the
29
- // wrong EntryPoint deployment.
30
- // - redactedConfig() strips the query string (and any embedded userinfo)
31
- // off every bundler/paymaster URL before it is considered "safe to log"
32
- // — even though the full URL already passed the secret-shape scan at
33
- // load time, a log line is a wider blast radius than an in-memory
34
- // config object, so this view is deliberately more conservative.
35
-
36
- import { ENTRYPOINT_V07 } from "./aa-adapter.mjs";
37
-
38
- export class RuntimeConfigError extends Error {
39
- constructor(message) {
40
- super(`runtime-config: ${message}`);
41
- this.name = "RuntimeConfigError";
42
- }
43
- }
44
-
45
- function fail(message) {
46
- throw new RuntimeConfigError(message);
47
- }
48
-
49
- // ---------------------------------------------------------------------------
50
- // Secret-shape guard for public endpoint URLs (fail closed)
51
- // ---------------------------------------------------------------------------
52
-
53
- /** String-value shapes that must never appear in a bundler/paymaster URL.
54
- * Mirrors the posture of connect-agent.mjs's FORBIDDEN_VALUE_RULES /
55
- * bundler-client.mjs's SecretLeakError checks, scoped to what a URL could
56
- * plausibly carry (query-string credentials, embedded key material). */
57
- const SECRET_URL_RULES = Object.freeze([
58
- // 32-byte hex — the shape of a raw EVM private key / session secret.
59
- { rule: "raw-32-byte-hex-key", re: /0x[0-9a-fA-F]{64}/ },
60
- { rule: "bearer-token", re: /bearer\s+[A-Za-z0-9._~+/=-]+/i },
61
- { rule: "pem-private-key", re: /-----BEGIN[A-Z ]*PRIVATE KEY-----/ },
62
- { rule: "authorization-header", re: /authorization\s*:/i },
63
- // Credential-shaped query/path segment: ?api_key=..., ?token=..., ?secret=...,
64
- // ?password=..., ?auth=..., ?access_token=..., ?bearer=..., or userinfo
65
- // (user:pass@host) embedded in the URL itself.
66
- {
67
- rule: "credential-shaped-param",
68
- re: /[?&](api[_-]?key|apikey|key|token|access[_-]?token|secret|password|passwd|auth|bearer)=/i,
69
- },
70
- { rule: "embedded-userinfo", re: /^[a-z][a-z0-9+.-]*:\/\/[^/@\s]+:[^/@\s]+@/i },
71
- ]);
72
-
73
- function assertPublicUrlSafe(value, label) {
74
- if (typeof value !== "string" || value.trim() === "") {
75
- fail(`${label} must be a non-empty string URL`);
76
- }
77
- let parsed;
78
- try {
79
- parsed = new URL(value);
80
- } catch {
81
- fail(`${label} is not a valid URL: ${value}`);
82
- }
83
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
84
- fail(`${label} must be an http(s) URL, got scheme ${parsed.protocol}`);
85
- }
86
- for (const { rule, re } of SECRET_URL_RULES) {
87
- if (re.test(value)) {
88
- fail(`${label} looks like it carries secret material (rule: ${rule}) — refusing to load a credential-shaped public endpoint`);
89
- }
90
- }
91
- return value;
92
- }
93
-
94
- // ---------------------------------------------------------------------------
95
- // Chain registry seed
96
- // ---------------------------------------------------------------------------
97
-
98
- /** Base metadata for every chain Oracle Control's public runtime config
99
- * knows about out of the box. entryPoint is intentionally NOT stored here —
100
- * it is always ENTRYPOINT_V07, asserted below, so there is exactly one
101
- * place (aa-adapter.mjs) that can ever define it. */
102
- const CHAIN_SEEDS = Object.freeze([
103
- { chainId: 8453, name: "Base" },
104
- { chainId: 42161, name: "Arbitrum" },
105
- ]);
106
-
107
- export const DEFAULT_CHAIN_ID = 8453;
108
- export const DEFAULT_PUBLIC_HOST = "127.0.0.1";
109
- export const DEFAULT_PUBLIC_PORT = 8799;
110
- const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1"]);
111
-
112
- function buildChainEntry(seed, env) {
113
- const entry = {
114
- name: seed.name,
115
- entryPoint: ENTRYPOINT_V07,
116
- };
117
- // entryPoint must always equal aa-adapter's ENTRYPOINT_V07 for every
118
- // supported chain — asserted here (not just "set here") so a future edit
119
- // that tries to override it per-chain is caught immediately.
120
- if (entry.entryPoint !== ENTRYPOINT_V07) {
121
- fail(`chain ${seed.chainId} entryPoint drifted from aa-adapter ENTRYPOINT_V07`);
122
- }
123
-
124
- const bundlerVar = `ORACLE_BUNDLER_URL_${seed.chainId}`;
125
- const paymasterVar = `ORACLE_PAYMASTER_URL_${seed.chainId}`;
126
- const bundlerRaw = env[bundlerVar];
127
- const paymasterRaw = env[paymasterVar];
128
-
129
- if (bundlerRaw != null && String(bundlerRaw).trim() !== "") {
130
- entry.bundlerUrl = assertPublicUrlSafe(String(bundlerRaw), bundlerVar);
131
- }
132
- if (paymasterRaw != null && String(paymasterRaw).trim() !== "") {
133
- entry.paymasterUrl = assertPublicUrlSafe(String(paymasterRaw), paymasterVar);
134
- }
135
-
136
- return entry;
137
- }
138
-
139
- function parsePort(raw, label) {
140
- const n = Number(raw);
141
- if (!Number.isInteger(n) || n < 0 || n > 65535) {
142
- fail(`${label} must be an integer port 0-65535, got ${JSON.stringify(raw)}`);
143
- }
144
- return n;
145
- }
146
-
147
- function parsePublicHost(raw, label) {
148
- const host = String(raw).trim();
149
- const normalized = host.toLowerCase().replace(/^\[|\]$/g, "");
150
- if (!LOOPBACK_HOSTS.has(normalized)) {
151
- fail(`${label} must be a loopback host, got ${JSON.stringify(raw)}`);
152
- }
153
- return normalized === "::1" ? "::1" : host;
154
- }
155
-
156
- /**
157
- * Parse the public runtime config (chain/bundler/paymaster registry + public
158
- * HTTP bind) from an env-like object. Pure function, no I/O, no network.
159
- *
160
- * @param {object} [env] defaults to process.env; any plain object of
161
- * string-ish values works (this is what makes it deterministically
162
- * testable without touching real process.env).
163
- * @returns {{
164
- * chains: Record<string, {name:string, entryPoint:string, bundlerUrl?:string, paymasterUrl?:string}>,
165
- * defaultChainId: number,
166
- * publicHost: string,
167
- * publicPort: number,
168
- * }}
169
- */
170
- export function loadPublicConfig(env = process.env) {
171
- if (env == null || typeof env !== "object") {
172
- fail("env must be an object");
173
- }
174
-
175
- const chains = {};
176
- for (const seed of CHAIN_SEEDS) {
177
- chains[String(seed.chainId)] = buildChainEntry(seed, env);
178
- }
179
-
180
- const rawDefaultChainId = env.ORACLE_DEFAULT_CHAIN_ID;
181
- let defaultChainId = DEFAULT_CHAIN_ID;
182
- if (rawDefaultChainId != null && String(rawDefaultChainId).trim() !== "") {
183
- const n = Number(rawDefaultChainId);
184
- if (!Number.isInteger(n)) {
185
- fail(`ORACLE_DEFAULT_CHAIN_ID must be an integer chain id, got ${JSON.stringify(rawDefaultChainId)}`);
186
- }
187
- if (chains[String(n)] == null) {
188
- fail(`ORACLE_DEFAULT_CHAIN_ID ${n} is not a registered chain (known: ${Object.keys(chains).join(", ")})`);
189
- }
190
- defaultChainId = n;
191
- }
192
-
193
- const publicHost = (() => {
194
- const v = env.ORACLE_PUBLIC_HOST ?? env.MAD_PUBLIC_HOST;
195
- return v != null && String(v).trim() !== "" ? parsePublicHost(v, "ORACLE_PUBLIC_HOST") : DEFAULT_PUBLIC_HOST;
196
- })();
197
-
198
- const publicPort = (() => {
199
- const v = env.ORACLE_PUBLIC_PORT ?? env.MAD_PUBLIC_PORT;
200
- if (v == null || String(v).trim() === "") return DEFAULT_PUBLIC_PORT;
201
- return parsePort(v, "ORACLE_PUBLIC_PORT");
202
- })();
203
-
204
- return Object.freeze({
205
- chains: Object.freeze(chains),
206
- defaultChainId,
207
- publicHost,
208
- publicPort,
209
- });
210
- }
211
-
212
- /**
213
- * Resolve a single chain entry from a loaded config. Fails closed on any
214
- * chainId not present in the registry — never falls back to a guessed/
215
- * default chain.
216
- *
217
- * @param {ReturnType<typeof loadPublicConfig>} config
218
- * @param {number|string} chainId
219
- */
220
- export function resolveChain(config, chainId) {
221
- if (config == null || typeof config.chains !== "object") {
222
- fail("resolveChain: config must be a loadPublicConfig() result");
223
- }
224
- const key = String(chainId);
225
- const entry = config.chains[key];
226
- if (entry == null) {
227
- fail(`unsupported chainId ${key} (registered: ${Object.keys(config.chains).join(", ") || "none"})`);
228
- }
229
- return entry;
230
- }
231
-
232
- /** Drop the query string and any userinfo from a URL, keeping only
233
- * scheme://host:port/path — safe to write to a log line even though the
234
- * full URL already passed the load-time secret-shape scan. */
235
- function redactUrl(value) {
236
- try {
237
- const u = new URL(value);
238
- u.search = "";
239
- u.username = "";
240
- u.password = "";
241
- return u.toString();
242
- } catch {
243
- return "[unparseable-url-redacted]";
244
- }
245
- }
246
-
247
- /**
248
- * Safe-to-log view of a loaded config: chain names/entryPoints/host/port
249
- * pass through unchanged (none of that is secret-shaped), bundler/paymaster
250
- * URLs are stripped down to origin+path only.
251
- *
252
- * @param {ReturnType<typeof loadPublicConfig>} config
253
- */
254
- export function redactedConfig(config) {
255
- if (config == null || typeof config.chains !== "object") {
256
- fail("redactedConfig: config must be a loadPublicConfig() result");
257
- }
258
- const chains = {};
259
- for (const [chainId, entry] of Object.entries(config.chains)) {
260
- chains[chainId] = {
261
- name: entry.name,
262
- entryPoint: entry.entryPoint,
263
- ...(entry.bundlerUrl != null ? { bundlerUrl: redactUrl(entry.bundlerUrl) } : {}),
264
- ...(entry.paymasterUrl != null ? { paymasterUrl: redactUrl(entry.paymasterUrl) } : {}),
265
- };
266
- }
267
- return Object.freeze({
268
- chains: Object.freeze(chains),
269
- defaultChainId: config.defaultChainId,
270
- publicHost: config.publicHost,
271
- publicPort: config.publicPort,
272
- });
273
- }
274
-
275
- export const _internal = { assertPublicUrlSafe, SECRET_URL_RULES, CHAIN_SEEDS };