@oracle-agent/oracle 0.7.0 → 0.8.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.
@@ -10,7 +10,7 @@ import { randomBytes } from "node:crypto";
10
10
  import { verifyMessage } from "ethers";
11
11
  import { data, dataCall, dataHealth, dataCatalog, isExecutionProvider } from "../src/data/desk-data.mjs";
12
12
  import { getProvider } from "../src/data/catalog.mjs";
13
- import { csvEnv, env, envEnabled, envFlag } from "../src/oracle-env.mjs";
13
+ import { csvEnv, env, envFlag } from "../src/oracle-env.mjs";
14
14
  import {
15
15
  listTiers,
16
16
  onboardUser,
@@ -21,7 +21,7 @@ import {
21
21
 
22
22
  const HOST = env("ORACLE_DATA_HOST", "MAD_DESK_HOST", "127.0.0.1");
23
23
  const PORT = Number(env("ORACLE_DATA_PORT", "MAD_DESK_PORT", 8787));
24
- const ONBOARD_ENABLED = envEnabled("ORACLE_ONBOARD_HTTP", "MAD_ONBOARD_HTTP", false);
24
+ const ONBOARD_ENABLED = envFlag("ORACLE_ONBOARD_HTTP", "MAD_ONBOARD_HTTP", false);
25
25
  const PUBLIC_API_MODE = envFlag("ORACLE_PUBLIC_API_MODE", "MAD_PUBLIC_API_MODE", false);
26
26
  const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
27
27
  const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1", "[::1]"]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oracle-agent/oracle",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Oracle: prepare-only multichain agent control plane. Policy-bounded intents for a user-signed wallet. Self-custody by default — the public package never takes your key. Built for Hermes; no model key required.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -57,8 +57,8 @@ the data plane). If it stays ambiguous, ask. Do not guess a chain.
57
57
  owner identity, the venue/destination allowlist, and the exact-grant bind.
58
58
 
59
59
  **Autonomous trading is the one opt-in.** A trigger that fires a trade with
60
- nobody watching requires `ORACLE_AUTONOMOUS=1`. Until then such an action
61
- alerts instead of executing. Say that plainly rather than pretending it fired.
60
+ nobody watching requires `ORACLE_AUTONOMOUS_TRADING=1`. Until then such an
61
+ action alerts instead of executing. Say that plainly rather than pretending it fired.
62
62
  2. **RFQ is a route source, not a permission bypass.** Compare solver/RFQ
63
63
  quotes net of gas/spread where configured, enforce expiry, and keep exact
64
64
  artifact kinds separate.
@@ -0,0 +1 @@
1
+ <svg width="24" height="24" fill="#fff" fill-rule="evenodd" style="flex:none;line-height:1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Codex</title><path clip-rule="evenodd" d="M8.086.457a6.105 6.105 0 013.046-.415c1.333.153 2.521.72 3.564 1.7a.117.117 0 00.107.029c1.408-.346 2.762-.224 4.061.366l.063.03.154.076c1.357.703 2.33 1.77 2.918 3.198.278.679.418 1.388.421 2.126a5.655 5.655 0 01-.18 1.631.167.167 0 00.04.155 5.982 5.982 0 011.578 2.891c.385 1.901-.01 3.615-1.183 5.14l-.182.22a6.063 6.063 0 01-2.934 1.851.162.162 0 00-.108.102c-.255.736-.511 1.364-.987 1.992-1.199 1.582-2.962 2.462-4.948 2.451-1.583-.008-2.986-.587-4.21-1.736a.145.145 0 00-.14-.032c-.518.167-1.04.191-1.604.185a5.924 5.924 0 01-2.595-.622 6.058 6.058 0 01-2.146-1.781c-.203-.269-.404-.522-.551-.821a7.74 7.74 0 01-.495-1.283 6.11 6.11 0 01-.017-3.064.166.166 0 00.008-.074.115.115 0 00-.037-.064 5.958 5.958 0 01-1.38-2.202 5.196 5.196 0 01-.333-1.589 6.915 6.915 0 01.188-2.132c.45-1.484 1.309-2.648 2.577-3.493.282-.188.55-.334.802-.438.286-.12.573-.22.861-.304a.129.129 0 00.087-.087A6.016 6.016 0 015.635 2.31C6.315 1.464 7.132.846 8.086.457zm-.804 7.85a.848.848 0 00-1.473.842l1.694 2.965-1.688 2.848a.849.849 0 001.46.864l1.94-3.272a.849.849 0 00.007-.854l-1.94-3.393zm5.446 6.24a.849.849 0 000 1.695h4.848a.849.849 0 000-1.696h-4.848z"></path></svg>
@@ -0,0 +1 @@
1
+ <svg width="240" height="228" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 240 228"><path fill="#fdfdfd" d="M240 221.115c-.524 1.679-3.536.705-4.715.72-14.483.134-28.986-.263-43.45.288l-1.648-1.093.924-138.355-1.254-.293C149.349 145.255 87.34 195.486 17.09 222.233c-3.635 1.381-12.15 5.121-15.472 5.499-.604.07-1.618-.129-1.618-.661v-51.119c7.811-3.974 16.122-6.995 24.057-10.815 48.345-23.245 91.356-60.33 121.551-104.425 2.088-3.05 5.009-7.064 6.658-10.248.264-.512 1.438-2.315.169-2.315H16.961V.745L17.71 0h221.54l.749.745z"/></svg>
@@ -0,0 +1,17 @@
1
+ <svg width="360" height="360" viewBox="0 0 360 360" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <g clip-path="url(#clip0_2_57)">
3
+ <g clip-path="url(#clip1_2_57)">
4
+ <path d="M252.072 212.292C245.826 220.662 232.686 234.558 225.378 234.558H191.412V212.274H218.466C222.336 212.274 226.026 210.708 228.69 207.954C242.586 193.554 250.614 176.418 250.614 158.04C250.614 126.684 227.178 98.964 191.394 82.26V67.284C191.394 60.84 186.174 55.62 179.73 55.62C173.286 55.62 168.066 60.84 168.066 67.284V73.494C158.04 70.56 147.42 68.328 136.332 67.05C154.692 86.994 165.906 113.67 165.906 142.92C165.906 169.146 156.942 193.23 141.876 212.31H168.066V234.63H129.726C124.542 234.63 120.33 230.436 120.33 225.234V215.478C120.33 213.768 118.944 212.364 117.216 212.364H66.672C65.682 212.364 64.836 213.174 64.836 214.164C64.8 254.088 96.39 284.058 134.172 284.058H240.822C266.382 284.058 277.812 251.298 292.788 230.454C298.602 222.39 312.552 215.91 316.782 214.11C317.556 213.786 318.006 213.066 318.006 212.22V199.26C318.006 197.946 316.71 196.956 315.432 197.316C315.432 197.316 253.782 211.482 253.062 211.68C252.342 211.896 252.072 212.31 252.072 212.31V212.292Z" fill="white"/>
5
+ <path d="M146.16 142.83C146.16 122.724 139.266 104.22 127.746 89.586L69.732 189.972H132.138C141.012 176.436 146.178 160.236 146.178 142.848L146.16 142.83Z" fill="white"/>
6
+ <path d="M181.566 -5.19844e-06C80.91 -0.828005 -0.82799 80.91 1.00604e-05 181.566C0.84601 279.306 80.694 359.172 178.416 359.982C279.072 360.846 360.846 279.072 359.982 178.416C359.172 80.712 279.306 0.845995 181.566 -5.19844e-06ZM127.746 89.586C139.266 104.22 146.16 122.742 146.16 142.83C146.16 160.236 140.994 176.436 132.12 189.954H69.714L127.728 89.568L127.746 89.586ZM318.006 199.242V212.202C318.006 213.048 317.556 213.768 316.782 214.092C312.552 215.892 298.602 222.372 292.788 230.436C277.812 251.28 266.382 284.04 240.822 284.04H134.172C96.408 284.04 64.818 254.07 64.836 214.146C64.836 213.156 65.682 212.346 66.672 212.346H117.216C118.962 212.346 120.33 213.75 120.33 215.46V225.216C120.33 230.4 124.524 234.612 129.726 234.612H168.066V212.292H141.876C156.942 193.212 165.906 169.128 165.906 142.902C165.906 113.652 154.692 86.976 136.332 67.032C147.438 68.328 158.058 70.542 168.066 73.476V67.266C168.066 60.822 173.286 55.602 179.73 55.602C186.174 55.602 191.394 60.822 191.394 67.266V82.242C227.178 98.946 250.614 126.666 250.614 158.022C250.614 176.418 242.568 193.536 228.69 207.936C226.026 210.69 222.336 212.256 218.466 212.256H191.412V234.54H225.378C232.704 234.54 245.844 220.644 252.072 212.274C252.072 212.274 252.342 211.86 253.062 211.644C253.782 211.428 315.432 197.28 315.432 197.28C316.728 196.92 318.006 197.91 318.006 199.224V199.242Z" fill="#0086FF"/>
7
+ </g>
8
+ </g>
9
+ <defs>
10
+ <clipPath id="clip0_2_57">
11
+ <rect width="360" height="360" fill="white"/>
12
+ </clipPath>
13
+ <clipPath id="clip1_2_57">
14
+ <rect width="360" height="360" fill="white"/>
15
+ </clipPath>
16
+ </defs>
17
+ </svg>
@@ -37,7 +37,7 @@
37
37
  --max:1100px;
38
38
  }
39
39
  *{box-sizing:border-box;margin:0;padding:0}
40
- html{scroll-behavior:smooth;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
40
+ html{scroll-behavior:smooth;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}
41
41
  body{
42
42
  min-height:100dvh;background:var(--bg);color:var(--ink);position:relative;isolation:isolate;
43
43
  font-family:var(--sans);font-weight:400;overflow-x:hidden;
@@ -64,7 +64,9 @@ img{display:inline-block}
64
64
  .orbital .core{fill:var(--blue);animation:core-pulse 3.2s var(--ease) infinite}
65
65
  .orbital .halo{fill:none;stroke:rgba(124,196,255,.22);stroke-width:5;filter:blur(3px)}
66
66
  @keyframes orb-spin{to{transform:rotate(360deg)}}
67
- @keyframes core-pulse{0%,100%{opacity:1}50%{opacity:.55}}
67
+ @keyframes core-pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.6;transform:scale(1.06)}}
68
+ @keyframes core-billboard{from{transform:rotateY(0deg) rotateX(-18deg) rotateZ(8deg)}to{transform:rotateY(-360deg) rotateX(-18deg) rotateZ(8deg)}}
69
+ @keyframes orbit-travel{from{transform:rotateX(76deg) rotateZ(0deg) translateX(clamp(170px,23vw,280px))}to{transform:rotateX(76deg) rotateZ(360deg) translateX(clamp(170px,23vw,280px))}}
68
70
 
69
71
  .loader{
70
72
  position:fixed;inset:0;z-index:50;background:var(--bg);
@@ -153,23 +155,39 @@ main{position:relative;z-index:2;padding-top:84px}
153
155
  width:clamp(380px,50vw,640px);aspect-ratio:1;position:relative;transform-style:preserve-3d;
154
156
  animation:orb-slew 22s linear infinite;
155
157
  }
156
- .hero-orb .lat{position:absolute;inset:0;border-radius:50%;border:1.4px solid rgba(124,196,255,.5);transform-style:preserve-3d;box-shadow:0 0 26px rgba(124,196,255,.12)}
157
- .hero-orb .lat.l1{transform:rotateY(0deg)}
158
+ .hero-orb .lat{position:absolute;inset:0;border-radius:50%;border:1.2px solid rgba(124,196,255,.42);transform-style:preserve-3d;box-shadow:0 0 26px rgba(124,196,255,.1), inset 0 0 34px rgba(124,196,255,.07)}
159
+ .hero-orb .lat.l1{transform:rotateY(0deg);border-color:rgba(167,216,255,.62)}
158
160
  .hero-orb .lat.l2{transform:rotateY(45deg)}
159
- .hero-orb .lat.l3{transform:rotateY(90deg)}
161
+ .hero-orb .lat.l3{transform:rotateY(90deg);border-color:rgba(167,216,255,.58)}
160
162
  .hero-orb .lat.l4{transform:rotateY(135deg)}
161
- .hero-orb .par{position:absolute;left:50%;top:50%;border-radius:50%;border:1.2px solid rgba(124,196,255,.38);transform-style:preserve-3d}
163
+ .hero-orb .par{position:absolute;left:50%;top:50%;border-radius:50%;border:1px solid rgba(124,196,255,.3);transform-style:preserve-3d;box-shadow:inset 0 0 24px rgba(124,196,255,.06)}
162
164
  .hero-orb .par.p1{width:96%;height:96%;transform:translate(-50%,-50%) rotateX(90deg)}
163
165
  .hero-orb .par.p2{width:78%;height:78%;transform:translate(-50%,-50%) rotateX(90deg) translateZ(calc(clamp(380px,50vw,640px) * .31))}
164
166
  .hero-orb .par.p3{width:78%;height:78%;transform:translate(-50%,-50%) rotateX(90deg) translateZ(calc(clamp(380px,50vw,640px) * -.31))}
165
- .hero-orb .eq{position:absolute;inset:-4%;border-radius:50%;border:2px solid rgba(167,216,255,.75);transform:rotateX(76deg);box-shadow:0 0 40px rgba(124,196,255,.35)}
167
+ .hero-orb .eq{position:absolute;inset:-4%;border-radius:50%;border:1.8px solid rgba(190,228,255,.82);transform:rotateX(76deg);box-shadow:0 0 44px rgba(124,196,255,.4), inset 0 0 30px rgba(167,216,255,.14)}
166
168
  .hero-orb .core-glow{
167
- position:absolute;inset:33%;border-radius:50%;
168
- background:radial-gradient(circle at 40% 36%, rgba(232,241,250,.9), rgba(124,196,255,.65) 34%, rgba(124,196,255,.12) 68%, transparent);
169
- box-shadow:0 0 46px rgba(124,196,255,.45), 0 0 110px rgba(124,196,255,.18);
169
+ position:absolute;inset:38%;border-radius:50%;
170
+ transform:rotateZ(8deg) rotateX(-18deg);
171
+ animation:core-billboard 22s linear infinite;
172
+ background:
173
+ radial-gradient(circle at 36% 30%, rgba(255,255,255,.95) 0%, rgba(214,238,255,.8) 12%, rgba(140,204,255,.55) 32%, rgba(74,150,214,.34) 56%, rgba(28,74,124,.22) 78%, rgba(14,34,62,.12) 100%);
174
+ box-shadow:
175
+ inset -12px -15px 34px rgba(6,16,32,.5),
176
+ inset 8px 10px 26px rgba(210,238,255,.2),
177
+ 0 0 60px rgba(124,196,255,.5),
178
+ 0 0 140px rgba(124,196,255,.2);
179
+ }
180
+ .hero-orb .core-glow::before{
181
+ content:"";position:absolute;left:22%;top:16%;width:26%;height:20%;border-radius:50%;
182
+ background:radial-gradient(ellipse at 50% 50%, rgba(255,255,255,.9), rgba(255,255,255,.28) 44%, transparent 74%);
183
+ transform:rotate(-24deg);
184
+ }
185
+ .hero-orb .core-glow::after{
186
+ content:"";position:absolute;inset:-6%;border-radius:50%;pointer-events:none;
187
+ background:radial-gradient(circle at 50% 50%, rgba(124,196,255,.3) 0%, rgba(124,196,255,.09) 46%, transparent 68%);
170
188
  animation:core-pulse 3.4s var(--ease) infinite;
171
189
  }
172
- .hero-orb .orbit-dot{position:absolute;width:10px;height:10px;border-radius:50%;background:var(--blue2);box-shadow:0 0 20px rgba(167,216,255,.9);left:calc(50% - 5px);top:calc(50% - 5px);transform:rotateX(76deg) translateX(clamp(170px,23vw,280px));animation:none}
190
+ .hero-orb .orbit-dot{position:absolute;width:9px;height:9px;border-radius:50%;background:radial-gradient(circle at 38% 34%, #fff, var(--blue2) 55%, rgba(124,196,255,.5));box-shadow:0 0 22px rgba(167,216,255,.95), 0 0 44px rgba(124,196,255,.4);left:calc(50% - 4.5px);top:calc(50% - 4.5px);transform-style:preserve-3d;animation:orbit-travel 14s linear infinite}
173
191
  .home-title{
174
192
  position:relative;z-index:2;
175
193
  font-family:var(--display);font-weight:300;font-size:clamp(96px,17vw,230px);line-height:.9;letter-spacing:-.045em;
@@ -250,9 +268,9 @@ main{position:relative;z-index:2;padding-top:84px}
250
268
  .node{
251
269
  border:1px solid rgba(124,196,255,.42);border-radius:14px;background:rgba(21,32,49,.92);
252
270
  padding:14px 12px;text-align:center;
253
- transition:border-color .3s,transform .3s var(--ease),box-shadow .3s;
271
+ transition:border-color .4s var(--ease),transform .4s var(--ease),box-shadow .4s var(--ease);
254
272
  }
255
- .node:hover{transform:translateY(-2px);box-shadow:0 12px 30px rgba(0,0,0,.28)}
273
+ .node:hover{transform:translate3d(0,-3px,0);box-shadow:0 14px 34px rgba(0,0,0,.32)}
256
274
  .node.hub{
257
275
  width:min(300px,100%);
258
276
  border-color:rgba(124,196,255,.5);
@@ -453,9 +471,9 @@ main{position:relative;z-index:2;padding-top:84px}
453
471
  border:1px solid var(--line);border-radius:14px;padding:16px;
454
472
  background:linear-gradient(180deg, rgba(124,196,255,.06), transparent 55%), rgba(17,25,37,.94);
455
473
  min-height:100px;display:flex;flex-direction:column;justify-content:space-between;gap:12px;
456
- transition:border-color .3s,transform .3s var(--ease);
474
+ transition:border-color .4s var(--ease),transform .4s var(--ease),box-shadow .4s var(--ease);
457
475
  }
458
- .chain:hover{border-color:rgba(124,196,255,.35);transform:translateY(-2px)}
476
+ .chain:hover{border-color:rgba(124,196,255,.45);transform:translate3d(0,-3px,0)}
459
477
  .chain-top{display:flex;justify-content:space-between;gap:8px;align-items:flex-start}
460
478
  .chain .nm{font-family:var(--display);font-size:20px;display:flex;align-items:center;gap:8px}
461
479
  .chain .nm img{width:18px;height:18px;border-radius:50%;object-fit:cover;background:rgba(255,255,255,.06)}
@@ -475,21 +493,24 @@ main{position:relative;z-index:2;padding-top:84px}
475
493
  display:flex;justify-content:space-between;gap:10px;flex-wrap:wrap;
476
494
  }
477
495
  .venues-head b{color:var(--blue);font-weight:500}
478
- .marquee{overflow:hidden;white-space:nowrap;mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent)}
496
+ .marquee{overflow:hidden;white-space:nowrap;mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent);-webkit-mask-image:linear-gradient(90deg,transparent,#000 6%,#000 94%,transparent)}
497
+ .marquee:hover .track{animation-play-state:paused}
479
498
  .marquee + .marquee{border-top:1px solid rgba(124,196,255,.08)}
480
- .track{display:inline-flex;gap:26px;padding:12px 0;animation:scroll 48s linear infinite;will-change:transform}
481
- .marquee.rev .track{animation-direction:reverse;animation-duration:56s}
499
+ .track{display:inline-flex;gap:26px;padding:12px 0;animation:scroll 75s linear infinite;will-change:transform;transform:translate3d(0,0,0);backface-visibility:hidden;perspective:1000px}
500
+ .marquee.rev .track{animation-direction:reverse;animation-duration:88s}
482
501
  a.chip{text-decoration:none;color:inherit}
483
502
  .chip{
484
503
  display:inline-flex;align-items:center;gap:10px;
485
504
  font-size:15px;letter-spacing:-.015em;text-transform:none;color:var(--proto-color,var(--cool));
486
505
  padding:8px 13px;border:1px solid rgba(124,196,255,.1);border-radius:999px;background:rgba(11,16,24,.38);
487
506
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.025);
507
+ transition:border-color .35s var(--ease),background .35s var(--ease),transform .35s var(--ease);
488
508
  }
509
+ a.chip:hover{border-color:rgba(124,196,255,.3);background:rgba(21,32,49,.6);transform:translate3d(0,-2px,0)}
489
510
  .chip img{width:18px;height:18px;border-radius:50%;object-fit:cover;background:rgba(255,255,255,.06)}
490
- .chip.wm-chip{padding:10px 16px}
491
- .chip img.wm{width:auto;height:20px;max-width:150px;border-radius:0;object-fit:contain;background:none;opacity:1}
492
- .chip img.wm.tall{height:22px;max-width:26px}
511
+ .chip.wm-chip{padding:11px 18px}
512
+ .chip img.wm{width:auto;height:27px;max-width:190px;border-radius:0;object-fit:contain;background:none;opacity:1}
513
+ .chip img.wm.tall{height:28px;max-width:32px}
493
514
 
494
515
  .chip .wordmark{font-family:var(--proto-font,var(--sans));font-weight:var(--proto-weight,750);font-style:var(--proto-style,normal);text-transform:var(--proto-transform,none);letter-spacing:var(--proto-track,-.025em);line-height:1.2}
495
516
  .proto-uniswap{--proto-font:"Inter",var(--sans);--proto-color:#ff4dcb;--proto-weight:850}
@@ -515,7 +536,7 @@ a.chip{text-decoration:none;color:inherit}
515
536
  .proto-across{--proto-font:"Manrope",var(--sans);--proto-color:#ff6b9b;--proto-weight:800}
516
537
  .proto-stargate{--proto-font:"Sora",var(--sans);--proto-color:#9ddcff;--proto-weight:700}
517
538
  .proto-magic-eden{--proto-font:"Archivo Black",var(--sans);--proto-color:#dfc7ff;--proto-weight:800;--proto-track:.01em}
518
- @keyframes scroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}
539
+ @keyframes scroll{from{transform:translate3d(0,0,0)}to{transform:translate3d(-50%,0,0)}}
519
540
 
520
541
  .wallet-grid{
521
542
  display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
@@ -561,8 +582,8 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
561
582
  font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--mute);
562
583
  }
563
584
 
564
- .js .rv{opacity:0;transform:translateY(18px)}
565
- .js .rv.in{opacity:1;transform:none;transition:opacity .9s var(--ease),transform .9s var(--ease)}
585
+ .js .rv{opacity:0;transform:translate3d(0,22px,0);will-change:opacity,transform}
586
+ .js .rv.in{opacity:1;transform:translate3d(0,0,0);transition:opacity 1.05s var(--ease),transform 1.05s var(--ease)}
566
587
  .js .rv.done{transform:none;will-change:auto}
567
588
 
568
589
  @media (max-width:960px){
@@ -1061,7 +1082,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1061
1082
  { n: "Hyperliquid", wm: "hyperliquid.svg", u: "https://hyperliquid.xyz" },
1062
1083
  { n: "Outcome", wm: "outcome.svg", u: "https://outcome.xyz" },
1063
1084
  { n: "XYZ", wm: "xyz.svg", u: "https://trade.xyz" },
1064
- { n: "Markets By Kinetiq", wm: "kinetiq.svg", tall: 1, u: "https://kinetiq.xyz" },
1085
+ { n: "Markets", wm: "markets.svg", tall: 1, u: "https://markets.xyz" },
1065
1086
  { n: "HyENA", wm: "hyena.svg", u: "https://hyena.trade" },
1066
1087
  { n: "Paragon", wm: "paragon.svg", tall: 1, u: "https://paragon.trade" },
1067
1088
  { n: "HyperSwap", wm: "hyperswap.svg", u: "https://hyperswap.exchange" },
@@ -1084,11 +1105,11 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1084
1105
  { n: "Velora", wm: "paraswap.svg", u: "https://velora.xyz" },
1085
1106
  { n: "Odos", wm: "odos.svg", u: "https://odos.xyz" },
1086
1107
  { n: "CoW Swap", wm: "cowswap.svg", u: "https://cow.fi" },
1087
- { n: "1inch", wm: "oneinch.svg", u: "https://1inch.io" },
1108
+ { n: "1inch", wm: "oneinch-icon.webp", tall: 1, u: "https://1inch.io" },
1088
1109
  { n: "Jupiter", wm: "jupiter.svg", u: "https://jup.ag" },
1089
- { n: "OpenSea", wm: "opensea.svg", u: "https://opensea.io" },
1090
- { n: "Across", wm: "across.svg", u: "https://across.to" },
1091
- { n: "Stargate", wm: "stargate.svg", u: "https://stargate.finance" },
1110
+ { n: "OpenSea", wm: "opensea-icon.svg", tall: 1, u: "https://opensea.io" },
1111
+ { n: "Across", wm: "across-icon.webp", tall: 1, u: "https://across.to" },
1112
+ { n: "Stargate", wm: "stargate-icon.webp", tall: 1, u: "https://stargate.finance" },
1092
1113
  { n: "Magic Eden", wm: "magic-eden.svg", u: "https://magiceden.io" }
1093
1114
  ];
1094
1115
 
@@ -1110,7 +1131,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1110
1131
  { n: "Hermes Agent", wm: "hermes.png", tall: 1, u: "https://hermes.nousresearch.com" },
1111
1132
  { n: "Claude", wm: "claude.svg", u: "https://claude.ai" },
1112
1133
  { n: "Grok", wm: "grok.svg", u: "https://grok.com" },
1113
- { n: "Codex", wm: "codex.svg", u: "https://openai.com/codex" },
1134
+ { n: "Codex", wm: "codex-icon.svg", tall: 1, u: "https://openai.com/codex" },
1114
1135
  { n: "Gemini", wm: "gemini.svg", u: "https://gemini.google.com" },
1115
1136
  { n: "OpenClaw", wm: "openclaw.svg", tall: 1, u: "https://openclaw.ai" },
1116
1137
  { n: "Perplexity", wm: "perplexity.svg", u: "https://perplexity.ai" },
@@ -39,6 +39,7 @@ const STALE_CLAIMS = [
39
39
  { re: /ORACLE_SIGNER_SURFACES=hl,poly\s*$/i, why: "quickstart freezes ORACLE_SIGNER_SURFACES at hl,poly" },
40
40
  { re: /ORACLE_AUTONOMOUS_TRADING=1.*(?:or\s+run\s+the\s+signer\s+daemon|same(?:-tier)?).*oracle-signer/i, why: "frames direct exec and oracle-signer as equivalent agent paths" },
41
41
  { re: /(?:or\s+run\s+the\s+signer\s+daemon|same(?:-tier)?).*oracle-signer.*ORACLE_AUTONOMOUS_TRADING=1/i, why: "frames direct exec and oracle-signer as equivalent agent paths" },
42
+ { re: /ORACLE_AUTONOMOUS=1/i, why: "names the dead autonomous env var instead of ORACLE_AUTONOMOUS_TRADING" },
42
43
  ];
43
44
 
44
45
  // Version pins that go stale the moment a release ships. The audit found the
@@ -3,19 +3,26 @@
3
3
  /** @typedef {{ id: string, venue: string, chainIds: number[], auth: 'none'|'apiKey'|'agentKey', ops: string[], baseEnv?: string[], description?: string }} ProviderMeta */
4
4
 
5
5
  const REGISTRY = new Map();
6
+ const BUILTIN_PROVIDER_IDS = new Set();
7
+ let BUILTINS_LOCKED = false;
6
8
 
7
9
  export function registerProvider(meta) {
8
10
  if (!meta?.id) throw new Error("registerProvider requires id");
9
11
  if (!meta.venue) throw new Error("registerProvider requires venue");
10
12
  if (!Array.isArray(meta.ops)) throw new Error("registerProvider requires ops[]");
11
- REGISTRY.set(meta.id, {
13
+ const id = String(meta.id);
14
+ if (BUILTINS_LOCKED && BUILTIN_PROVIDER_IDS.has(id)) {
15
+ throw new Error(`registerProvider refuses to overwrite built-in provider: ${id}`);
16
+ }
17
+ REGISTRY.set(id, {
12
18
  chainIds: meta.chainIds || [],
13
19
  auth: meta.auth || "none",
14
20
  description: meta.description || "",
15
21
  baseEnv: meta.baseEnv || [],
16
22
  ...meta,
23
+ id,
17
24
  });
18
- return REGISTRY.get(meta.id);
25
+ return REGISTRY.get(id);
19
26
  }
20
27
 
21
28
  export function getProvider(id) {
@@ -33,6 +40,12 @@ export function clearProvidersForTest() {
33
40
  REGISTRY.clear();
34
41
  }
35
42
 
43
+ function lockBuiltinProviders() {
44
+ BUILTIN_PROVIDER_IDS.clear();
45
+ for (const id of REGISTRY.keys()) BUILTIN_PROVIDER_IDS.add(id);
46
+ BUILTINS_LOCKED = true;
47
+ }
48
+
36
49
  // ── Built-in providers ──────────────────────────────────────────────────────
37
50
 
38
51
  registerProvider({
@@ -537,3 +550,5 @@ registerProvider({
537
550
  baseEnv: ["ZEROX_API_KEY", "ONEINCH_API_KEY"],
538
551
  description: "Cross-chain RFQ intent normalizer and firm-quote fanout over reviewed venues. Prepares artifacts only, never signs or broadcasts.",
539
552
  });
553
+
554
+ lockBuiltinProviders();
@@ -41,6 +41,8 @@ export const DEFAULT_HOST = "127.0.0.1";
41
41
  export const DEFAULT_PORT = 8799;
42
42
  export const VERSION = pkg.version;
43
43
 
44
+ const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1"]);
45
+
44
46
  const ROOT_DIR = join(dirname(fileURLToPath(import.meta.url)), "../..");
45
47
  const CONSOLE_DIR = join(ROOT_DIR, "public", "oracle-console");
46
48
 
@@ -136,6 +138,18 @@ function asPlainObject(v, code) {
136
138
  return v;
137
139
  }
138
140
 
141
+ function normalizeHost(host) {
142
+ return String(host || "").trim().toLowerCase().replace(/^\[|\]$/g, "");
143
+ }
144
+
145
+ function assertLoopbackBindHost(host) {
146
+ const normalized = normalizeHost(host);
147
+ if (!LOOPBACK_HOSTS.has(normalized)) {
148
+ throw new TypeError(`oracle-public only binds loopback hosts; got ${String(host)}`);
149
+ }
150
+ return normalized === "::1" ? "::1" : String(host).trim();
151
+ }
152
+
139
153
  // ---------------------------------------------------------------------------
140
154
  // Route handlers — each returns { status, body }; errors are thrown.
141
155
  // ---------------------------------------------------------------------------
@@ -354,9 +368,10 @@ export function createPublicServer() {
354
368
  /**
355
369
  * Resolve host/port: explicit args > ORACLE_PUBLIC_HOST/PORT env (via
356
370
  * oracle-env's env() helper) > loopback 127.0.0.1:8799 default.
371
+ * Non-loopback binds fail closed; this plane has no remote peer/origin guard.
357
372
  */
358
373
  export function resolvePublicBind({ host, port } = {}) {
359
- const h = host ?? env("ORACLE_PUBLIC_HOST", "MAD_PUBLIC_HOST", DEFAULT_HOST);
374
+ const h = assertLoopbackBindHost(host ?? env("ORACLE_PUBLIC_HOST", "MAD_PUBLIC_HOST", DEFAULT_HOST));
360
375
  const rawPort = port ?? env("ORACLE_PUBLIC_PORT", "MAD_PUBLIC_PORT", String(DEFAULT_PORT));
361
376
  const p = Number(rawPort);
362
377
  if (!Number.isInteger(p) || p < 0 || p > 65535) {
@@ -107,6 +107,7 @@ const CHAIN_SEEDS = Object.freeze([
107
107
  export const DEFAULT_CHAIN_ID = 8453;
108
108
  export const DEFAULT_PUBLIC_HOST = "127.0.0.1";
109
109
  export const DEFAULT_PUBLIC_PORT = 8799;
110
+ const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1"]);
110
111
 
111
112
  function buildChainEntry(seed, env) {
112
113
  const entry = {
@@ -143,6 +144,15 @@ function parsePort(raw, label) {
143
144
  return n;
144
145
  }
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
+
146
156
  /**
147
157
  * Parse the public runtime config (chain/bundler/paymaster registry + public
148
158
  * HTTP bind) from an env-like object. Pure function, no I/O, no network.
@@ -182,7 +192,7 @@ export function loadPublicConfig(env = process.env) {
182
192
 
183
193
  const publicHost = (() => {
184
194
  const v = env.ORACLE_PUBLIC_HOST ?? env.MAD_PUBLIC_HOST;
185
- return v != null && String(v).trim() !== "" ? String(v) : DEFAULT_PUBLIC_HOST;
195
+ return v != null && String(v).trim() !== "" ? parsePublicHost(v, "ORACLE_PUBLIC_HOST") : DEFAULT_PUBLIC_HOST;
186
196
  })();
187
197
 
188
198
  const publicPort = (() => {