@oracle-agent/oracle 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/oracle-data-mcp.mjs +32 -0
- package/package.json +1 -1
- package/public/oracle-splash/assets/llms/claude.svg +1 -1
- package/public/oracle-splash/assets/llms/codex.svg +1 -1
- package/public/oracle-splash/assets/llms/cursor-icon.svg +12 -0
- package/public/oracle-splash/assets/llms/cursor.svg +1 -1
- package/public/oracle-splash/assets/llms/deepseek.svg +1 -1
- package/public/oracle-splash/assets/llms/gemini.svg +1 -1
- package/public/oracle-splash/assets/llms/kimi-icon.svg +1 -0
- package/public/oracle-splash/assets/llms/kimi.svg +1 -1
- package/public/oracle-splash/assets/llms/openclaw.svg +1 -1
- package/public/oracle-splash/assets/llms/perplexity.svg +1 -1
- package/public/oracle-splash/assets/llms/qwen.svg +1 -1
- package/public/oracle-splash/assets/wordmarks/cowswap.svg +1 -1
- package/public/oracle-splash/assets/wordmarks/curve.png +0 -0
- package/public/oracle-splash/assets/wordmarks/gmx.svg +1 -1
- package/public/oracle-splash/assets/wordmarks/kinetiq.svg +1 -0
- package/public/oracle-splash/assets/wordmarks/lfj.webp +0 -0
- package/public/oracle-splash/assets/wordmarks/magic-eden.svg +1 -1
- package/public/oracle-splash/assets/wordmarks/morpho.svg +1 -1
- package/public/oracle-splash/assets/wordmarks/odos.svg +1 -1
- package/public/oracle-splash/assets/wordmarks/opensea.svg +1 -1
- package/public/oracle-splash/assets/wordmarks/paragon.svg +9 -0
- package/public/oracle-splash/assets/wordmarks/paraswap.svg +1 -1
- package/public/oracle-splash/index.html +85 -95
- package/src/data/catalog.mjs +11 -0
- package/src/data/desk-data.mjs +6 -0
- package/src/data/providers/rfq.mjs +15 -0
- package/src/index.mjs +7 -0
- package/src/rfq/intent.mjs +180 -0
- package/src/rfq/sources.mjs +181 -0
- package/protocols/templates/safe-erc20/README.md +0 -9
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
--blue:#7CC4FF;
|
|
19
19
|
--blue2:#A7D8FF;
|
|
20
20
|
--blue-dim:#3a6f99;
|
|
21
|
-
--ink:#
|
|
22
|
-
--cool:#
|
|
23
|
-
--mute:#
|
|
21
|
+
--ink:#F4F9FE;
|
|
22
|
+
--cool:#C9DAEC;
|
|
23
|
+
--mute:#9FB8D2;
|
|
24
24
|
--line:rgba(124,196,255,.14);
|
|
25
25
|
--line-2:rgba(124,196,255,.24);
|
|
26
26
|
--evm:#7CC4FF;
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
html{scroll-behavior:smooth;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}
|
|
41
41
|
body{
|
|
42
42
|
min-height:100dvh;background:var(--bg);color:var(--ink);position:relative;isolation:isolate;
|
|
43
|
-
font-family:var(--sans);font-weight:
|
|
43
|
+
font-family:var(--sans);font-weight:400;overflow-x:hidden;
|
|
44
44
|
}
|
|
45
45
|
::selection{background:var(--blue);color:#061018}
|
|
46
46
|
a{color:inherit;text-decoration:none}
|
|
@@ -117,7 +117,7 @@ img{display:inline-block}
|
|
|
117
117
|
.nav-cta:hover{border-color:var(--blue);color:var(--blue2);box-shadow:0 0 0 1px rgba(124,196,255,.12)}
|
|
118
118
|
|
|
119
119
|
/* fixed soft field behind content */
|
|
120
|
-
#gl{position:fixed;inset:0;width:100%;height:100%;z-index:-1;display:block;opacity:.
|
|
120
|
+
#gl{position:fixed;inset:0;width:100%;height:100%;z-index:-1;display:block;opacity:.4;pointer-events:none}
|
|
121
121
|
.veil{
|
|
122
122
|
position:fixed;inset:0;z-index:1;pointer-events:none;
|
|
123
123
|
background:
|
|
@@ -147,7 +147,7 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
147
147
|
.hero-stage{position:relative;width:100%;display:grid;place-items:center;min-height:clamp(360px,52vh,560px)}
|
|
148
148
|
.hero-art{position:absolute;inset:0;display:grid;place-items:center;z-index:0;pointer-events:none}
|
|
149
149
|
#orb-vid{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);width:min(74vw,620px);aspect-ratio:1;object-fit:contain;opacity:0;transition:opacity 1.4s var(--ease);mix-blend-mode:screen}
|
|
150
|
-
#orb-vid.ready{opacity:.
|
|
150
|
+
#orb-vid.ready{opacity:.62}
|
|
151
151
|
.blender-orb .hero-orb{display:none}
|
|
152
152
|
.hero-orb{
|
|
153
153
|
width:clamp(380px,50vw,640px);aspect-ratio:1;position:relative;transform-style:preserve-3d;
|
|
@@ -195,12 +195,12 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
195
195
|
.hero-note{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--mute)}
|
|
196
196
|
@keyframes orb-slew{0%{transform:rotateX(18deg) rotateZ(-8deg) rotateY(0deg)}100%{transform:rotateX(18deg) rotateZ(-8deg) rotateY(360deg)}}
|
|
197
197
|
@keyframes home-breathe{0%,100%{opacity:.65;transform:scale(1)}50%{opacity:1;transform:scale(1.07)}}
|
|
198
|
-
@keyframes drop-line{0%,100%{opacity:.25;transform:translateX(-50%) scaleY(.45)}50%{opacity:1;transform:translateX(-50%) scaleY(1)}}
|
|
198
|
+
@keyframes drop-line{0%,100%{opacity:.25;transform:translateX(-50%) scaleY(.45)}50%{opacity:1;transform:translateX(-50%) scaleY(1)}}
|
|
199
199
|
|
|
200
200
|
|
|
201
201
|
.section{
|
|
202
202
|
position:relative;z-index:2;max-width:var(--max);margin:0 auto;
|
|
203
|
-
padding:clamp(
|
|
203
|
+
padding:clamp(56px,10vh,110px) var(--pad) 0;
|
|
204
204
|
}
|
|
205
205
|
.section:first-of-type{padding-top:clamp(18px,3vh,28px)}
|
|
206
206
|
.section-label{
|
|
@@ -213,7 +213,7 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
213
213
|
max-width:18ch;margin-bottom:12px;
|
|
214
214
|
}
|
|
215
215
|
.section-title em{font-style:italic;color:var(--blue2)}
|
|
216
|
-
.section-lede{max-width:52ch;color:#
|
|
216
|
+
.section-lede{max-width:52ch;color:#C9DAEC;font-size:16px;line-height:1.7;margin-bottom:clamp(28px,4vw,44px)}
|
|
217
217
|
|
|
218
218
|
/* orchestration graph */
|
|
219
219
|
.graph-shell{
|
|
@@ -223,7 +223,7 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
223
223
|
.graph-top{
|
|
224
224
|
display:flex;flex-wrap:wrap;justify-content:center;gap:10px;
|
|
225
225
|
padding:14px 18px;border-bottom:1px solid var(--line);
|
|
226
|
-
font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:#
|
|
226
|
+
font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:#9FB8D2;
|
|
227
227
|
}
|
|
228
228
|
.graph-top b{color:var(--blue);font-weight:500}
|
|
229
229
|
.graph-canvas{padding:clamp(28px,4vw,40px) clamp(14px,2.5vw,24px) clamp(22px,3vw,30px);overflow:auto}
|
|
@@ -262,11 +262,11 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
262
262
|
display:flex;flex-direction:column;align-items:center;
|
|
263
263
|
}
|
|
264
264
|
.node.hub .orbital{width:74px;height:74px;margin:2px 0 10px;filter:drop-shadow(0 0 20px rgba(124,196,255,.35))}
|
|
265
|
-
.node .tag{font-family:var(--mono);font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:#
|
|
265
|
+
.node .tag{font-family:var(--mono);font-size:10px;letter-spacing:.18em;text-transform:uppercase;color:#9FB8D2;margin-bottom:8px}
|
|
266
266
|
.node.hub .tag{color:var(--blue)}
|
|
267
267
|
.node .name{font-family:var(--display);font-size:22px;font-weight:500;color:#DCEAF6;line-height:1;letter-spacing:.01em;margin-bottom:6px}
|
|
268
268
|
.node.hub .name{font-size:34px;font-weight:400;font-style:italic}
|
|
269
|
-
.node .sub{font-family:var(--mono);font-size:11px;letter-spacing:.05em;color:#
|
|
269
|
+
.node .sub{font-family:var(--mono);font-size:11px;letter-spacing:.05em;color:#C9DAEC;line-height:1.5}
|
|
270
270
|
.node.route{min-height:138px;display:flex;flex-direction:column;justify-content:flex-start;text-align:left;padding:14px}
|
|
271
271
|
.node.route .name{font-size:18px;margin-bottom:8px}
|
|
272
272
|
.node.route .chains{
|
|
@@ -362,14 +362,14 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
362
362
|
margin-top:22px;
|
|
363
363
|
}
|
|
364
364
|
.moat-card{
|
|
365
|
-
background:
|
|
365
|
+
background:rgba(17,25,37,.94);padding:clamp(20px,3vw,28px);min-height:140px;
|
|
366
366
|
display:flex;flex-direction:column;gap:10px;
|
|
367
367
|
transition:background .35s;
|
|
368
368
|
}
|
|
369
369
|
.moat-card:hover{background:var(--panel-2)}
|
|
370
370
|
.moat-card .n{font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--blue)}
|
|
371
371
|
.moat-card h3{font-family:var(--display);font-weight:400;font-size:clamp(20px,2.2vw,26px)}
|
|
372
|
-
.moat-card p{color:#
|
|
372
|
+
.moat-card p{color:#C9DAEC;font-size:15px;line-height:1.55;max-width:44ch}
|
|
373
373
|
@media (max-width:860px){.moat-grid{grid-template-columns:1fr}}
|
|
374
374
|
.evolve-rail{
|
|
375
375
|
display:flex;flex-wrap:wrap;gap:8px;justify-content:center;
|
|
@@ -405,7 +405,7 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
405
405
|
.wires.multi circle.c-sol{fill:var(--sol)}
|
|
406
406
|
|
|
407
407
|
/* route detail cards */
|
|
408
|
-
.route-card{
|
|
408
|
+
.route-card{background:rgba(17,25,37,.94);
|
|
409
409
|
background:var(--bg);padding:22px 20px;min-height:150px;
|
|
410
410
|
display:flex;flex-direction:column;gap:10px;transition:background .35s;
|
|
411
411
|
}
|
|
@@ -413,7 +413,7 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
413
413
|
.route-card h3{font-family:var(--display);font-weight:400;font-size:26px;display:flex;align-items:center;gap:10px}
|
|
414
414
|
.route-card h3 img{width:20px;height:20px;border-radius:50%;object-fit:cover;background:rgba(255,255,255,.06)}
|
|
415
415
|
.route-card .where{font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--blue)}
|
|
416
|
-
.route-card p{color:#
|
|
416
|
+
.route-card p{color:#C9DAEC;font-size:15px;line-height:1.55}
|
|
417
417
|
.route-card .chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:auto}
|
|
418
418
|
.route-card.p-add{grid-column:1/-1;align-items:center;text-align:center;justify-content:center;gap:14px;padding:30px 22px}
|
|
419
419
|
.route-card.p-add .chips{justify-content:center;margin-top:4px}
|
|
@@ -441,9 +441,9 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
441
441
|
.chain-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px}
|
|
442
442
|
.hl-surface{margin-top:34px;border:1px solid var(--line);border-radius:14px;padding:20px;background:rgba(124,196,255,.02)}
|
|
443
443
|
.hl-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px;margin-top:16px}
|
|
444
|
-
.hl-grid article{border:1px solid
|
|
444
|
+
.hl-grid article{border:1px solid rgba(124,196,255,.22);border-radius:10px;padding:16px 17px;background:rgba(17,25,37,.92)}
|
|
445
445
|
.hl-grid h3{font-family:var(--display);font-size:15px;font-weight:500;color:var(--ink);margin:0 0 6px}
|
|
446
|
-
.hl-grid p{font-size:14px;line-height:1.6;color:#
|
|
446
|
+
.hl-grid p{font-size:14px;line-height:1.6;color:#C9DAEC;margin:0}
|
|
447
447
|
.hl-note{margin:16px 0 0;font-family:var(--mono);font-size:10.5px;letter-spacing:.04em;color:var(--cool);opacity:.62}
|
|
448
448
|
.hip3{margin-top:20px;padding-top:18px;border-top:1px solid var(--line)}
|
|
449
449
|
.hl-note code{font-family:var(--mono);color:var(--blue2);opacity:.9}
|
|
@@ -451,7 +451,7 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
451
451
|
@media(max-width:620px){.hl-grid{grid-template-columns:1fr}}
|
|
452
452
|
.chain{
|
|
453
453
|
border:1px solid var(--line);border-radius:14px;padding:16px;
|
|
454
|
-
background:linear-gradient(180deg, rgba(124,196,255,.
|
|
454
|
+
background:linear-gradient(180deg, rgba(124,196,255,.06), transparent 55%), rgba(17,25,37,.94);
|
|
455
455
|
min-height:100px;display:flex;flex-direction:column;justify-content:space-between;gap:12px;
|
|
456
456
|
transition:border-color .3s,transform .3s var(--ease);
|
|
457
457
|
}
|
|
@@ -468,6 +468,7 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
468
468
|
.badge.live{border-color:rgba(124,196,255,.35);color:var(--blue)}
|
|
469
469
|
|
|
470
470
|
.venues{margin-top:14px;border:1px solid var(--line);border-radius:14px;overflow:hidden;background:rgba(17,25,37,.85)}
|
|
471
|
+
.venues{background:rgba(17,25,37,.86);border:1px solid rgba(124,196,255,.16);border-radius:16px;overflow:hidden;margin-bottom:14px}
|
|
471
472
|
.venues-head{
|
|
472
473
|
padding:11px 14px;border-bottom:1px solid var(--line);
|
|
473
474
|
font-family:var(--mono);font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--mute);
|
|
@@ -478,6 +479,7 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
478
479
|
.marquee + .marquee{border-top:1px solid rgba(124,196,255,.08)}
|
|
479
480
|
.track{display:inline-flex;gap:26px;padding:12px 0;animation:scroll 48s linear infinite;will-change:transform}
|
|
480
481
|
.marquee.rev .track{animation-direction:reverse;animation-duration:56s}
|
|
482
|
+
a.chip{text-decoration:none;color:inherit}
|
|
481
483
|
.chip{
|
|
482
484
|
display:inline-flex;align-items:center;gap:10px;
|
|
483
485
|
font-size:15px;letter-spacing:-.015em;text-transform:none;color:var(--proto-color,var(--cool));
|
|
@@ -486,7 +488,7 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
486
488
|
}
|
|
487
489
|
.chip img{width:18px;height:18px;border-radius:50%;object-fit:cover;background:rgba(255,255,255,.06)}
|
|
488
490
|
.chip.wm-chip{padding:10px 16px}
|
|
489
|
-
.chip img.wm{width:auto;height:20px;max-width:150px;border-radius:0;object-fit:contain;background:none;opacity
|
|
491
|
+
.chip img.wm{width:auto;height:20px;max-width:150px;border-radius:0;object-fit:contain;background:none;opacity:1}
|
|
490
492
|
.chip img.wm.tall{height:22px;max-width:26px}
|
|
491
493
|
|
|
492
494
|
.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}
|
|
@@ -521,7 +523,7 @@ main{position:relative;z-index:2;padding-top:84px}
|
|
|
521
523
|
margin-top:8px;
|
|
522
524
|
}
|
|
523
525
|
.wallet-card{
|
|
524
|
-
background:
|
|
526
|
+
background:rgba(17,25,37,.94);padding:clamp(22px,3vw,30px);
|
|
525
527
|
display:flex;flex-direction:column;gap:12px;min-height:170px;
|
|
526
528
|
transition:background .35s;
|
|
527
529
|
}
|
|
@@ -634,7 +636,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
|
|
|
634
636
|
<div class="home-inner">
|
|
635
637
|
<div class="hero-stage">
|
|
636
638
|
<div class="hero-art" aria-hidden="true">
|
|
637
|
-
<video id="orb-vid"
|
|
639
|
+
<video id="orb-vid" muted loop playsinline preload="none" hidden>
|
|
638
640
|
<source src="assets/hero/orb.webm" type="video/webm">
|
|
639
641
|
</video>
|
|
640
642
|
<div class="hero-orb" id="hero-orb">
|
|
@@ -742,7 +744,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
|
|
|
742
744
|
<div class="tag">profile</div>
|
|
743
745
|
<div class="name">robinhood agent</div>
|
|
744
746
|
<div class="sub">markets · nfts · names</div>
|
|
745
|
-
<div class="chains"><span class="ch">Robinhood Chain
|
|
747
|
+
<div class="chains"><span class="ch">Robinhood Chain <img src="https://icons.llamao.fi/icons/chains/rsz_robinhood?w=24&h=24" alt="" loading="lazy"></span></div>
|
|
746
748
|
</div>
|
|
747
749
|
<div class="node route p-sol">
|
|
748
750
|
<div class="tag">profile</div>
|
|
@@ -825,11 +827,11 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
|
|
|
825
827
|
<article class="route-card p-rh">
|
|
826
828
|
<div class="where">robinhood agent →</div>
|
|
827
829
|
<h3>Robinhood <img src="https://icons.llamao.fi/icons/chains/rsz_robinhood?w=40&h=40" alt="Robinhood Chain" loading="lazy"></h3>
|
|
828
|
-
<p>RH Chain markets, NFTs, names, token scans, and chain-local routing
|
|
830
|
+
<p>RH Chain markets, NFTs, names, token scans, and chain-local routing.</p>
|
|
829
831
|
<div class="chips">
|
|
830
832
|
<span class="chip-s">markets</span>
|
|
831
833
|
<span class="chip-s">NFTs</span>
|
|
832
|
-
<span class="chip-s">
|
|
834
|
+
<span class="chip-s">rh chain</span>
|
|
833
835
|
</div>
|
|
834
836
|
</article>
|
|
835
837
|
<article class="route-card p-sol">
|
|
@@ -875,10 +877,10 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
|
|
|
875
877
|
<article class="route-card p-stable">
|
|
876
878
|
<div class="where">stable agent →</div>
|
|
877
879
|
<h3>Stable <img src="https://icons.llamao.fi/icons/chains/rsz_stable?w=40&h=40" alt="Stable" loading="lazy"></h3>
|
|
878
|
-
<p>Stable mainnet launch radar and venue ops
|
|
880
|
+
<p>Stable mainnet launch radar and venue ops, scanned straight from the chain's own logs.</p>
|
|
879
881
|
<div class="chips">
|
|
880
882
|
<span class="chip-s">launches</span>
|
|
881
|
-
<span class="chip-s">Stable
|
|
883
|
+
<span class="chip-s">Stable</span>
|
|
882
884
|
</div>
|
|
883
885
|
</article>
|
|
884
886
|
<article class="route-card p-build">
|
|
@@ -980,17 +982,17 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
|
|
|
980
982
|
<article><h3>Staking</h3><p>Validator summaries, delegations, rewards and history. Stake deposit, withdraw and delegate prepare with a 7-day unstaking queue.</p></article>
|
|
981
983
|
<article><h3>Outcome markets</h3><p>HIP-4 outcome listing plus order and cancel prepare.</p></article>
|
|
982
984
|
<article><h3>Account state</h3><p>Clearinghouse state, open orders, user fills, positions.</p></article>
|
|
983
|
-
<article><h3>HyperEVM
|
|
985
|
+
<article><h3>HyperEVM</h3><p>Token search and metadata on Hyperliquid, routed with the EVM lane.</p></article>
|
|
984
986
|
</div>
|
|
985
987
|
</div>
|
|
986
988
|
<div class="venues rv">
|
|
987
989
|
<div class="venues-head"><span>protocols // venues</span><span><b>routed by name</b> · quotes ranked · prepare-only</span></div>
|
|
988
|
-
<div class="marquee"
|
|
989
|
-
<div class="marquee rev"
|
|
990
|
+
<div class="marquee"><div class="track" id="proto-track-a"></div></div>
|
|
991
|
+
<div class="marquee rev"><div class="track" id="proto-track-b"></div></div>
|
|
990
992
|
</div>
|
|
991
993
|
<div class="venues rv">
|
|
992
994
|
<div class="venues-head"><span>models // harnesses</span><span><b>bring your own model</b> · oracle is the control plane</span></div>
|
|
993
|
-
<div class="marquee"
|
|
995
|
+
<div class="marquee"><div class="track" id="llm-track"></div></div>
|
|
994
996
|
</div>
|
|
995
997
|
</section>
|
|
996
998
|
|
|
@@ -1022,7 +1024,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
|
|
|
1022
1024
|
</div>
|
|
1023
1025
|
<div class="foot-meta">
|
|
1024
1026
|
<span>oracle · <a class="labs-link" href="https://demi.la">locals only labs</a></span>
|
|
1025
|
-
<span>
|
|
1027
|
+
<span>self custodial // the future is agentic</span>
|
|
1026
1028
|
</div>
|
|
1027
1029
|
</footer>
|
|
1028
1030
|
|
|
@@ -1051,53 +1053,53 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
|
|
|
1051
1053
|
var cls = c.badge === "live" ? "badge live" : "badge";
|
|
1052
1054
|
var label = c.badge === "live" ? "live" : "read";
|
|
1053
1055
|
return '<article class="chain rv"><div class="chain-top"><div class="nm">' + c.name +
|
|
1054
|
-
' <img src="' + ICON + c.logo + '?w=36&h=36" alt="' + c.name + ' logo" loading="lazy"></div><div class="
|
|
1055
|
-
'</div></div><div class="meta"><span>' + c.note + '</span><span class="' + cls + '">' + label + '</span></div></article>';
|
|
1056
|
+
' <img src="' + ICON + c.logo + '?w=36&h=36" alt="' + c.name + ' logo" loading="lazy"></div></div><div class="meta"><span>' + c.note + '</span><span class="' + cls + '">' + label + '</span></div></article>';
|
|
1056
1057
|
}).join("");
|
|
1057
1058
|
|
|
1058
1059
|
var WM = "assets/wordmarks/";
|
|
1059
1060
|
var PROTOS_A = [
|
|
1060
|
-
{ n: "Hyperliquid", wm: "hyperliquid.svg" },
|
|
1061
|
-
{ n: "Outcome", wm: "outcome.svg" },
|
|
1062
|
-
{ n: "XYZ", wm: "xyz.svg" },
|
|
1063
|
-
{ n: "Markets By Kinetiq",
|
|
1064
|
-
{ n: "HyENA", wm: "hyena.svg" },
|
|
1065
|
-
{ n: "Paragon",
|
|
1066
|
-
{ n: "HyperSwap", wm: "hyperswap.svg" },
|
|
1067
|
-
{ n: "Uniswap", wm: "uniswap.svg" },
|
|
1068
|
-
{ n: "Polymarket", wm: "polymarket.png" },
|
|
1069
|
-
{ n: "Aerodrome", wm: "aerodrome.svg" },
|
|
1070
|
-
{ n: "Velodrome", wm: "velodrome.svg" },
|
|
1071
|
-
{ n: "PancakeSwap", wm: "pancakeswap.svg" },
|
|
1072
|
-
{ n: "QuickSwap", wm: "quickswap.png" },
|
|
1073
|
-
{ n: "LFJ",
|
|
1074
|
-
{ n: "Curve",
|
|
1075
|
-
{ n: "Balancer", wm: "balancer.svg" },
|
|
1076
|
-
{ n: "Pendle", wm: "pendle.png" }
|
|
1061
|
+
{ n: "Hyperliquid", wm: "hyperliquid.svg", u: "https://hyperliquid.xyz" },
|
|
1062
|
+
{ n: "Outcome", wm: "outcome.svg", u: "https://outcome.xyz" },
|
|
1063
|
+
{ n: "XYZ", wm: "xyz.svg", u: "https://trade.xyz" },
|
|
1064
|
+
{ n: "Markets By Kinetiq", wm: "kinetiq.svg", tall: 1, u: "https://kinetiq.xyz" },
|
|
1065
|
+
{ n: "HyENA", wm: "hyena.svg", u: "https://hyena.trade" },
|
|
1066
|
+
{ n: "Paragon", wm: "paragon.svg", tall: 1, u: "https://paragon.trade" },
|
|
1067
|
+
{ n: "HyperSwap", wm: "hyperswap.svg", u: "https://hyperswap.exchange" },
|
|
1068
|
+
{ n: "Uniswap", wm: "uniswap.svg", u: "https://uniswap.org" },
|
|
1069
|
+
{ n: "Polymarket", wm: "polymarket.png", u: "https://polymarket.com" },
|
|
1070
|
+
{ n: "Aerodrome", wm: "aerodrome.svg", u: "https://aerodrome.finance" },
|
|
1071
|
+
{ n: "Velodrome", wm: "velodrome.svg", u: "https://velodrome.finance" },
|
|
1072
|
+
{ n: "PancakeSwap", wm: "pancakeswap.svg", u: "https://pancakeswap.finance" },
|
|
1073
|
+
{ n: "QuickSwap", wm: "quickswap.png", u: "https://quickswap.exchange" },
|
|
1074
|
+
{ n: "LFJ", wm: "lfj.webp", tall: 1, u: "https://lfj.gg" },
|
|
1075
|
+
{ n: "Curve", wm: "curve.png", tall: 1, u: "https://curve.finance" },
|
|
1076
|
+
{ n: "Balancer", wm: "balancer.svg", u: "https://balancer.fi" },
|
|
1077
|
+
{ n: "Pendle", wm: "pendle.png", u: "https://pendle.finance" }
|
|
1077
1078
|
];
|
|
1078
1079
|
var PROTOS_B = [
|
|
1079
|
-
{ n: "Morpho", wm: "morpho.svg" },
|
|
1080
|
-
{ n: "GMX", wm: "gmx.svg" },
|
|
1081
|
-
{ n: "LI.FI", wm: "lifi.png" },
|
|
1082
|
-
{ n: "Relay", wm: "relay.svg" },
|
|
1083
|
-
{ n: "Velora", wm: "paraswap.svg" },
|
|
1084
|
-
{ n: "Odos", wm: "odos.svg" },
|
|
1085
|
-
{ n: "CoW Swap", wm: "cowswap.svg" },
|
|
1086
|
-
{ n: "1inch", wm: "oneinch.svg" },
|
|
1087
|
-
{ n: "Jupiter", wm: "jupiter.svg" },
|
|
1088
|
-
{ n: "OpenSea", wm: "opensea.svg" },
|
|
1089
|
-
{ n: "Across", wm: "across.svg" },
|
|
1090
|
-
{ n: "Stargate", wm: "stargate.svg" },
|
|
1091
|
-
{ n: "Magic Eden", wm: "magic-eden.svg" }
|
|
1080
|
+
{ n: "Morpho", wm: "morpho.svg", u: "https://morpho.org" },
|
|
1081
|
+
{ n: "GMX", wm: "gmx.svg", u: "https://gmx.io" },
|
|
1082
|
+
{ n: "LI.FI", wm: "lifi.png", u: "https://li.fi" },
|
|
1083
|
+
{ n: "Relay", wm: "relay.svg", u: "https://relay.link" },
|
|
1084
|
+
{ n: "Velora", wm: "paraswap.svg", u: "https://velora.xyz" },
|
|
1085
|
+
{ n: "Odos", wm: "odos.svg", u: "https://odos.xyz" },
|
|
1086
|
+
{ n: "CoW Swap", wm: "cowswap.svg", u: "https://cow.fi" },
|
|
1087
|
+
{ n: "1inch", wm: "oneinch.svg", u: "https://1inch.io" },
|
|
1088
|
+
{ 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" },
|
|
1092
|
+
{ n: "Magic Eden", wm: "magic-eden.svg", u: "https://magiceden.io" }
|
|
1092
1093
|
];
|
|
1093
1094
|
|
|
1094
1095
|
function chipRow(list) {
|
|
1095
1096
|
var seq = list.concat(list);
|
|
1096
1097
|
return seq.map(function (x) {
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1098
|
+
var body = x.wm
|
|
1099
|
+
? '<img class="' + (x.tall ? 'wm tall' : 'wm') + '" src="' + WM + x.wm + '" alt="' + x.n + '" decoding="async">' +
|
|
1100
|
+
(x.tall ? '<span class="wordmark">' + x.n + '</span>' : '')
|
|
1101
|
+
: '<span class="wordmark">' + x.n + '</span>';
|
|
1102
|
+
return '<a class="chip wm-chip" href="' + x.u + '" target="_blank" rel="noopener noreferrer" aria-label="' + x.n + '">' + body + '</a>';
|
|
1101
1103
|
}).join("");
|
|
1102
1104
|
}
|
|
1103
1105
|
document.getElementById("proto-track-a").innerHTML = chipRow(PROTOS_A);
|
|
@@ -1105,23 +1107,23 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
|
|
|
1105
1107
|
|
|
1106
1108
|
var LM = "assets/llms/";
|
|
1107
1109
|
var LLMS = [
|
|
1108
|
-
{ n: "Hermes Agent", wm: "hermes.png", tall: 1 },
|
|
1109
|
-
{ n: "Claude", wm: "claude.svg" },
|
|
1110
|
-
{ n: "Grok", wm: "grok.svg" },
|
|
1111
|
-
{ n: "Codex", wm: "codex.svg" },
|
|
1112
|
-
{ n: "Gemini", wm: "gemini.svg" },
|
|
1113
|
-
{ n: "OpenClaw", wm: "openclaw.svg", tall: 1 },
|
|
1114
|
-
{ n: "Perplexity", wm: "perplexity.svg" },
|
|
1115
|
-
{ n: "Manus", wm: "manus.svg" },
|
|
1116
|
-
{ n: "Cursor", wm: "cursor.svg" },
|
|
1117
|
-
{ n: "Windsurf", wm: "windsurf.svg" },
|
|
1118
|
-
{ n: "DeepSeek", wm: "deepseek.svg" },
|
|
1119
|
-
{ n: "Qwen", wm: "qwen.svg", tall: 1 },
|
|
1120
|
-
{ n: "Kimi", wm: "kimi.svg" }
|
|
1110
|
+
{ n: "Hermes Agent", wm: "hermes.png", tall: 1, u: "https://hermes.nousresearch.com" },
|
|
1111
|
+
{ n: "Claude", wm: "claude.svg", u: "https://claude.ai" },
|
|
1112
|
+
{ n: "Grok", wm: "grok.svg", u: "https://grok.com" },
|
|
1113
|
+
{ n: "Codex", wm: "codex.svg", u: "https://openai.com/codex" },
|
|
1114
|
+
{ n: "Gemini", wm: "gemini.svg", u: "https://gemini.google.com" },
|
|
1115
|
+
{ n: "OpenClaw", wm: "openclaw.svg", tall: 1, u: "https://openclaw.ai" },
|
|
1116
|
+
{ n: "Perplexity", wm: "perplexity.svg", u: "https://perplexity.ai" },
|
|
1117
|
+
{ n: "Manus", wm: "manus.svg", u: "https://manus.im" },
|
|
1118
|
+
{ n: "Cursor", wm: "cursor-icon.svg", tall: 1, u: "https://cursor.com" },
|
|
1119
|
+
{ n: "Windsurf", wm: "windsurf.svg", u: "https://windsurf.com" },
|
|
1120
|
+
{ n: "DeepSeek", wm: "deepseek.svg", u: "https://deepseek.com" },
|
|
1121
|
+
{ n: "Qwen", wm: "qwen.svg", tall: 1, u: "https://chat.qwen.ai" },
|
|
1122
|
+
{ n: "Kimi", wm: "kimi-icon.svg", tall: 1, u: "https://kimi.com" }
|
|
1121
1123
|
];
|
|
1122
1124
|
document.getElementById("llm-track").innerHTML = LLMS.concat(LLMS).map(function (x) {
|
|
1123
1125
|
var cls = x.tall ? "wm tall" : "wm";
|
|
1124
|
-
return '<
|
|
1126
|
+
return '<a class="chip wm-chip" href="' + x.u + '" target="_blank" rel="noopener noreferrer" aria-label="' + x.n + '"><img class="' + cls + '" src="' + LM + x.wm + '" alt="' + x.n + '" decoding="async">' + (x.tall ? '<span class="wordmark">' + x.n + '</span>' : '') + '</a>';
|
|
1125
1127
|
}).join("");
|
|
1126
1128
|
|
|
1127
1129
|
var loader = document.getElementById("loader");
|
|
@@ -1171,19 +1173,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
|
|
|
1171
1173
|
}, { passive: true });
|
|
1172
1174
|
}
|
|
1173
1175
|
|
|
1174
|
-
|
|
1175
|
-
var v = document.getElementById("orb-vid");
|
|
1176
|
-
if (!v) return;
|
|
1177
|
-
var art = document.querySelector(".hero-art");
|
|
1178
|
-
function ready() { art.classList.add("blender-orb"); v.classList.add("ready"); }
|
|
1179
|
-
if (v.readyState >= 2) ready();
|
|
1180
|
-
v.addEventListener("loadeddata", ready, { once: true });
|
|
1181
|
-
if (reduced) { v.removeAttribute("autoplay"); v.pause(); ready(); return; }
|
|
1182
|
-
document.addEventListener("visibilitychange", function () {
|
|
1183
|
-
if (document.visibilityState === "visible") { var q = v.play(); if (q && q.catch) q.catch(function () {}); }
|
|
1184
|
-
else v.pause();
|
|
1185
|
-
});
|
|
1186
|
-
})();
|
|
1176
|
+
// Hero is the original CSS orb.
|
|
1187
1177
|
|
|
1188
1178
|
var nodes = Array.prototype.slice.call(document.querySelectorAll(".rv, .wires"));
|
|
1189
1179
|
if (reduced || !("IntersectionObserver" in window)) {
|
package/src/data/catalog.mjs
CHANGED
|
@@ -526,3 +526,14 @@ registerProvider({
|
|
|
526
526
|
baseEnv: ["PARASWAP_API_URL"],
|
|
527
527
|
description: "ParaSwap/Velora public price routes + validated transaction builder",
|
|
528
528
|
});
|
|
529
|
+
|
|
530
|
+
registerProvider({
|
|
531
|
+
id: "rfq",
|
|
532
|
+
venue: "intent-rfq",
|
|
533
|
+
chainIds: [1, 10, 56, 137, 8453, 42161, 43114],
|
|
534
|
+
auth: "none",
|
|
535
|
+
ops: ["health", "intent", "quote"],
|
|
536
|
+
execution: "prepare",
|
|
537
|
+
baseEnv: ["ZEROX_API_KEY", "ONEINCH_API_KEY"],
|
|
538
|
+
description: "Cross-chain RFQ intent normalizer and firm-quote fanout over reviewed venues. Prepares artifacts only, never signs or broadcasts.",
|
|
539
|
+
});
|
package/src/data/desk-data.mjs
CHANGED
|
@@ -44,6 +44,7 @@ import * as portfolio from "./providers/portfolio.mjs";
|
|
|
44
44
|
import * as portfolioHistory from "./providers/portfolio-history.mjs";
|
|
45
45
|
import * as nftPortfolio from "./providers/nft-portfolio.mjs";
|
|
46
46
|
import * as paraswap from "./providers/paraswap.mjs";
|
|
47
|
+
import * as rfq from "./providers/rfq.mjs";
|
|
47
48
|
|
|
48
49
|
const OPS = {
|
|
49
50
|
"hl-info": {
|
|
@@ -356,6 +357,11 @@ const OPS = {
|
|
|
356
357
|
quote: (o, a = {}) => paraswap.paraswapPrice(a, o),
|
|
357
358
|
prepare: (o, a = {}) => paraswap.paraswapPrepare(a, o),
|
|
358
359
|
},
|
|
360
|
+
rfq: {
|
|
361
|
+
health: (o) => rfq.rfqHealth(o),
|
|
362
|
+
intent: (o, a = {}) => rfq.rfqIntent(a, o),
|
|
363
|
+
quote: (o, a = {}) => rfq.rfqQuote(a, o),
|
|
364
|
+
},
|
|
359
365
|
};
|
|
360
366
|
|
|
361
367
|
/**
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { normalizeRfqIntent } from "../../rfq/intent.mjs";
|
|
2
|
+
import { requestRfqQuotes } from "../../rfq/sources.mjs";
|
|
3
|
+
|
|
4
|
+
export function rfqIntent(args = {}, opts = {}) {
|
|
5
|
+
return normalizeRfqIntent(args, opts);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export async function rfqQuote(args = {}, opts = {}) {
|
|
9
|
+
const intent = args.intent?.kind === "rfq-intent" ? args.intent : normalizeRfqIntent(args, opts);
|
|
10
|
+
return requestRfqQuotes(intent, opts);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function rfqHealth() {
|
|
14
|
+
return { ok: true, provider: "rfq", mode: "intent-rfq", execution: "prepare" };
|
|
15
|
+
}
|
package/src/index.mjs
CHANGED
|
@@ -38,6 +38,13 @@ export {
|
|
|
38
38
|
} from "./scanner/index.mjs";
|
|
39
39
|
|
|
40
40
|
export { bestSwapRoute, bestBridgeRoute, QUALITY } from "./router/index.mjs";
|
|
41
|
+
export {
|
|
42
|
+
normalizeRfqIntent,
|
|
43
|
+
normalizeFirmQuote,
|
|
44
|
+
hashRfqIntent,
|
|
45
|
+
hashFirmQuote,
|
|
46
|
+
} from "./rfq/intent.mjs";
|
|
47
|
+
export { sourceCandidates, executeRfqCandidates, rankRfqQuotes, requestRfqQuotes } from "./rfq/sources.mjs";
|
|
41
48
|
export { validateNftMintGasWar, assertNftMintGasWar, NftGasWarLimitError } from "./nft-gas-war-guard.mjs";
|
|
42
49
|
export { simulateSell, assertSellable, SELL_SIM } from "./sell-simulation.mjs";
|
|
43
50
|
export { capabilityStatus, assertCapability, autonomousTradingEnabled, posture } from "./capability-posture.mjs";
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { getAddress, isAddress } from "ethers";
|
|
3
|
+
|
|
4
|
+
export const NATIVE_TOKEN = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
|
|
5
|
+
export const DEFAULT_SAME_CHAIN_SOURCES = Object.freeze(["lifi", "paraswap", "0x", "cow", "uniswap-v3"]);
|
|
6
|
+
export const DEFAULT_CROSS_CHAIN_SOURCES = Object.freeze(["lifi"]);
|
|
7
|
+
const HEX32 = /^0x[0-9a-fA-F]{64}$/;
|
|
8
|
+
const INT = /^\d+$/;
|
|
9
|
+
|
|
10
|
+
function fail(label, message = "invalid") {
|
|
11
|
+
throw new Error(`rfq: ${label} ${message}`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function chainId(value, label) {
|
|
15
|
+
const n = Number(value);
|
|
16
|
+
if (!Number.isSafeInteger(n) || n <= 0) fail(label, "must be a positive chainId");
|
|
17
|
+
return n;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function amount(value, label) {
|
|
21
|
+
const s = String(value ?? "").trim();
|
|
22
|
+
if (!INT.test(s) || BigInt(s) <= 0n) fail(label, "must be a positive integer string");
|
|
23
|
+
return s;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function optionalAmount(value, label) {
|
|
27
|
+
if (value == null || value === "") return null;
|
|
28
|
+
return amount(value, label);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function token(value, label) {
|
|
32
|
+
const s = String(value ?? "").trim();
|
|
33
|
+
if (s.toLowerCase() === NATIVE_TOKEN.toLowerCase()) return NATIVE_TOKEN;
|
|
34
|
+
if (!isAddress(s)) fail(label, "must be an EVM address or native token sentinel");
|
|
35
|
+
return getAddress(s);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function address(value, label) {
|
|
39
|
+
const s = String(value ?? "").trim();
|
|
40
|
+
if (!isAddress(s)) fail(label, "must be an EVM address");
|
|
41
|
+
return getAddress(s);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function optionalAddress(value, label) {
|
|
45
|
+
if (value == null || value === "") return null;
|
|
46
|
+
return address(value, label);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function stringList(value, label, defaults) {
|
|
50
|
+
if (value === undefined) return [...defaults];
|
|
51
|
+
if (!Array.isArray(value)) fail(label, "must be an array");
|
|
52
|
+
return value.map((x) => String(x).trim()).filter(Boolean);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function deadline(value, { nowMs, maxDeadlineMs }, label) {
|
|
56
|
+
const n = Number(value);
|
|
57
|
+
if (!Number.isFinite(n)) fail(label, "must be a finite millisecond timestamp");
|
|
58
|
+
if (n <= nowMs) fail(label, "expired");
|
|
59
|
+
if (n > nowMs + maxDeadlineMs) fail(label, "exceeds maxDeadlineMs");
|
|
60
|
+
return Math.floor(n);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function plain(value) {
|
|
64
|
+
if (Array.isArray(value)) return value.map(plain);
|
|
65
|
+
if (value && typeof value === "object") {
|
|
66
|
+
const out = {};
|
|
67
|
+
for (const key of Object.keys(value).sort()) {
|
|
68
|
+
if (value[key] !== undefined) out[key] = plain(value[key]);
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function canonicalJson(value) {
|
|
76
|
+
return JSON.stringify(plain(value));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function sha256Hex(value) {
|
|
80
|
+
return `0x${createHash("sha256").update(canonicalJson(value)).digest("hex")}`;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function withoutHash(value, keys) {
|
|
84
|
+
const out = { ...value };
|
|
85
|
+
for (const key of keys) delete out[key];
|
|
86
|
+
return out;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function hashRfqIntent(intent) {
|
|
90
|
+
return sha256Hex(withoutHash(intent, ["intentHash"]));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function hashFirmQuote(quote) {
|
|
94
|
+
return sha256Hex(withoutHash(quote, ["firmQuoteHash"]));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function normalizeRfqIntent(input = {}, opts = {}) {
|
|
98
|
+
const nowMs = Number(opts.nowMs ?? Date.now());
|
|
99
|
+
const maxDeadlineMs = Number(opts.maxDeadlineMs ?? 30 * 60 * 1000);
|
|
100
|
+
if (!Number.isFinite(nowMs) || !Number.isFinite(maxDeadlineMs) || maxDeadlineMs <= 0) fail("time", "is invalid");
|
|
101
|
+
const fromChainId = chainId(input.fromChainId ?? input.fromChain, "fromChainId");
|
|
102
|
+
const toChainId = chainId(input.toChainId ?? input.toChain, "toChainId");
|
|
103
|
+
const sameChain = fromChainId === toChainId;
|
|
104
|
+
const defaults = sameChain ? DEFAULT_SAME_CHAIN_SOURCES : DEFAULT_CROSS_CHAIN_SOURCES;
|
|
105
|
+
const intent = {
|
|
106
|
+
kind: "rfq-intent",
|
|
107
|
+
version: 1,
|
|
108
|
+
fromChainId,
|
|
109
|
+
toChainId,
|
|
110
|
+
sellToken: token(input.sellToken ?? input.tokenIn ?? input.fromToken, "sellToken"),
|
|
111
|
+
buyToken: token(input.buyToken ?? input.tokenOut ?? input.toToken, "buyToken"),
|
|
112
|
+
sellAmount: amount(input.sellAmount ?? input.amountIn ?? input.fromAmount, "sellAmount"),
|
|
113
|
+
receiver: address(input.receiver ?? input.recipient ?? input.to, "receiver"),
|
|
114
|
+
deadlineMs: deadline(input.deadlineMs ?? input.deadline ?? input.expiresAtMs, { nowMs, maxDeadlineMs }, "deadline"),
|
|
115
|
+
minBuyAmount: optionalAmount(input.minBuyAmount ?? input.minOut ?? input.amountOutMin, "minBuyAmount"),
|
|
116
|
+
allowedSources: stringList(input.allowedSources, "allowedSources", defaults),
|
|
117
|
+
allowedRouters: stringList(input.allowedRouters, "allowedRouters", []),
|
|
118
|
+
slippageBps: Number.isFinite(Number(input.slippageBps)) ? Number(input.slippageBps) : null,
|
|
119
|
+
partialFill: input.partialFill === true,
|
|
120
|
+
metadata: input.metadata && typeof input.metadata === "object" && !Array.isArray(input.metadata) ? plain(input.metadata) : {},
|
|
121
|
+
};
|
|
122
|
+
if (intent.slippageBps != null && (!Number.isInteger(intent.slippageBps) || intent.slippageBps < 0 || intent.slippageBps > 10_000)) fail("slippageBps", "must be 0 to 10000");
|
|
123
|
+
intent.intentId = input.intentId ? String(input.intentId) : sha256Hex({ seed: "rfq-intent", intent }).slice(0, 34);
|
|
124
|
+
intent.intentHash = hashRfqIntent(intent);
|
|
125
|
+
return Object.freeze(intent);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function artifact(value) {
|
|
129
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) fail("artifact", "required");
|
|
130
|
+
if (value.typedDataHash != null && !HEX32.test(String(value.typedDataHash))) fail("artifact.typedDataHash", "must be bytes32");
|
|
131
|
+
if (value.calldataHash != null && !HEX32.test(String(value.calldataHash))) fail("artifact.calldataHash", "must be bytes32");
|
|
132
|
+
if (value.to != null && !isAddress(String(value.to))) fail("artifact.to", "must be an address");
|
|
133
|
+
if (value.data != null && !/^0x(?:[0-9a-fA-F]{2})*$/.test(String(value.data))) fail("artifact.data", "must be hex");
|
|
134
|
+
return plain(value);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function normalizeFirmQuote(intent, quote = {}, opts = {}) {
|
|
138
|
+
if (!intent || intent.kind !== "rfq-intent") fail("intent", "required");
|
|
139
|
+
const nowMs = Number(opts.nowMs ?? Date.now());
|
|
140
|
+
const expiryMs = Number(quote.expiryMs ?? quote.expiresAtMs ?? quote.validUntilMs);
|
|
141
|
+
if (!Number.isFinite(expiryMs)) fail("quote expiry", "required");
|
|
142
|
+
if (expiryMs <= nowMs) fail("quote", "expired");
|
|
143
|
+
if (expiryMs > intent.deadlineMs) fail("quote expiry", "exceeds intent deadline");
|
|
144
|
+
const source = String(quote.source ?? quote.provider ?? "").trim();
|
|
145
|
+
if (!source) fail("source", "required");
|
|
146
|
+
if (!intent.allowedSources.includes(source)) fail("source", "not allowed by intent");
|
|
147
|
+
const amountOut = amount(quote.amountOut ?? quote.buyAmount, "amountOut");
|
|
148
|
+
const minBuyAmount = amount(quote.minBuyAmount ?? quote.minOut ?? amountOut, "minBuyAmount");
|
|
149
|
+
if (BigInt(minBuyAmount) > BigInt(amountOut)) fail("minBuyAmount", "exceeds amountOut");
|
|
150
|
+
const artifactValue = artifact(quote.artifact ?? quote.executableArtifact ?? quote.transaction ?? quote.typedData);
|
|
151
|
+
const quotedAtMs = Number(quote.quotedAtMs ?? quote.timestampMs ?? opts.nowMs ?? Date.now());
|
|
152
|
+
if (!Number.isFinite(quotedAtMs)) fail("quotedAtMs", "must be finite");
|
|
153
|
+
const router = optionalAddress(quote.router ?? quote.settlementRouter ?? artifactValue.to, "router");
|
|
154
|
+
const out = {
|
|
155
|
+
kind: "rfq-firm-quote",
|
|
156
|
+
provider: "rfq",
|
|
157
|
+
surface: "rfq",
|
|
158
|
+
version: 1,
|
|
159
|
+
quoteId: String(quote.quoteId ?? quote.id ?? "").trim(),
|
|
160
|
+
source,
|
|
161
|
+
intentHash: intent.intentHash,
|
|
162
|
+
fromChainId: intent.fromChainId,
|
|
163
|
+
toChainId: intent.toChainId,
|
|
164
|
+
sellToken: intent.sellToken,
|
|
165
|
+
buyToken: intent.buyToken,
|
|
166
|
+
sellAmount: intent.sellAmount,
|
|
167
|
+
receiver: intent.receiver,
|
|
168
|
+
router,
|
|
169
|
+
amountOut,
|
|
170
|
+
minBuyAmount,
|
|
171
|
+
quotedAtMs: Math.floor(quotedAtMs),
|
|
172
|
+
expiryMs: Math.floor(expiryMs),
|
|
173
|
+
artifact: artifactValue,
|
|
174
|
+
maker: quote.maker ? String(quote.maker) : null,
|
|
175
|
+
metadata: quote.metadata && typeof quote.metadata === "object" && !Array.isArray(quote.metadata) ? plain(quote.metadata) : {},
|
|
176
|
+
};
|
|
177
|
+
if (!out.quoteId) out.quoteId = sha256Hex({ seed: "rfq-quote", out }).slice(0, 34);
|
|
178
|
+
out.firmQuoteHash = hashFirmQuote(out);
|
|
179
|
+
return Object.freeze(out);
|
|
180
|
+
}
|