@oracle-agent/oracle 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oracle-agent/oracle",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
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",
@@ -29,6 +29,22 @@ export const UNI_V3_CHAINS = {
29
29
  weth: "0x82aF49447D8a07e3bd95BD0d56f35241523fBab1",
30
30
  usdc: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
31
31
  },
32
+ // Robinhood Chain. Addresses mirror rhbot server/swap.js SWAP_CONFIG (the vetted
33
+ // source) and were re-proved on the live chain before being added here:
34
+ // eth_chainId == 4663, eth_getCode non-empty for every address below, and a real
35
+ // quoteExactInputSingle returned 1 WETH -> 1866.58 USDG at fee 100 (2026-07-31).
36
+ //
37
+ // Why this entry matters: LI.FI / ParaSwap / CoW do not index 4663, so the router's
38
+ // aggregator-only candidate list returned "no usable route" for every RH swap. The
39
+ // on-chain QuoterV2 is the only source that can price this chain. `usdc` is USDG
40
+ // (Global Dollar, 6-dec) — the stable quote RH pools actually use.
41
+ 4663: {
42
+ name: "robinhood",
43
+ quoter: "0x33e885ed0ec9bf04ecfb19341582aadcb4c8a9e7",
44
+ router: "0xcaf681a66d020601342297493863e78c959e5cb2",
45
+ weth: "0x0bd7d308f8e1639fab988df18a8011f41eacad73",
46
+ usdc: "0x5fc5360D0400a0Fd4f2af552ADD042D716F1d168",
47
+ },
32
48
  };
33
49
 
34
50
  export const UNI_V3_FEE_TIERS = [100, 500, 3000, 10000];
@@ -274,7 +290,7 @@ export async function uniV3PrepareExactIn(q = {}, opts = {}) {
274
290
  value: nativeInput ? quote.amountIn : "0",
275
291
  slippageGuard: bindAutoSlippageGuardToCall(quote.autoSlippage, { chainId, venue: meta.router, data }),
276
292
  },
277
- });
293
+ }, { provider: "uniswap-v3", kind: "univ3-swap-tx" });
278
294
  }
279
295
 
280
296
  export async function uniV3Health(opts = {}) {
@@ -45,6 +45,29 @@ export const ARTIFACT = Object.freeze({
45
45
  const DEFAULT_DRIFT_TOLERANCE_BPS = 100;
46
46
 
47
47
  const PREPARERS = {
48
+ // On-chain Uniswap V3. Unlike the aggregators below, this builds calldata from the
49
+ // chain's own router rather than an API's transaction payload — which is what makes
50
+ // chains no aggregator indexes (e.g. Robinhood 4663) preparable at all.
51
+ //
52
+ // The provider stamps requiresUserSignature:true / signingReady:false /
53
+ // broadcastReady:false. Preparing is NOT permission to execute: the wallet is still
54
+ // the only thing that can authorize this, and the unattended daemon surface list
55
+ // (hl, poly) is deliberately unchanged by adding this.
56
+ "uniswap-v3": async ({ chainId, tokenIn, tokenOut, amountIn, taker }, opts) => {
57
+ const { uniV3PrepareExactIn } = await import("../data/providers/uniswap-v3.mjs");
58
+ const p = await uniV3PrepareExactIn(
59
+ { chainId, tokenIn, tokenOut, amountIn, recipient: taker },
60
+ opts,
61
+ );
62
+ return {
63
+ artifactKind: ARTIFACT.TRANSACTION,
64
+ transaction: p.transaction,
65
+ requiresApproval: p.requiresApproval ?? null,
66
+ amountOut: p.quote?.amountOut ?? null,
67
+ minOut: p.quote?.amountOutMinimum ?? null,
68
+ };
69
+ },
70
+
48
71
  lifi: async ({ chainId, tokenIn, tokenOut, amountIn, taker }, opts) => {
49
72
  const { lifiPrepare } = await import("../data/providers/lifi.mjs");
50
73
  const p = await lifiPrepare(
@@ -20,6 +20,7 @@ import { paraswapPrice } from "../data/providers/paraswap.mjs";
20
20
  import { zeroxQuote } from "../data/providers/zerox.mjs";
21
21
  import { oneinchQuote } from "../data/providers/oneinch.mjs";
22
22
  import { cowQuote } from "../data/providers/cowswap.mjs";
23
+ import { uniV3QuoteExactIn, UNI_V3_CHAINS } from "../data/providers/uniswap-v3.mjs";
23
24
  import { llamaPrices } from "../data/providers/defillama.mjs";
24
25
  import { NATIVE_PRICE_KEY } from "./best-execution.mjs";
25
26
 
@@ -188,6 +189,42 @@ export function swapCandidates({
188
189
  },
189
190
  });
190
191
 
192
+ // On-chain Uniswap V3 QuoterV2. UNLIKE every other source in this list, this is
193
+ // not a third-party API — it is an eth_call against the chain itself.
194
+ //
195
+ // Why it exists here: aggregators only index chains they chose to support. On
196
+ // Robinhood Chain (4663) LI.FI/ParaSwap/CoW all return nothing, so the candidate
197
+ // list came back empty and the router reported "no usable route" — which reads
198
+ // like a permission wall but is really zero coverage. A chain with a live V3
199
+ // deployment can always be priced directly, with no API key and no indexer.
200
+ //
201
+ // Kept LAST so it acts as a floor: when aggregators do cover a chain they usually
202
+ // win on route quality, and best-execution still compares net output. This only
203
+ // decides the trade when it is the sole source that answered.
204
+ //
205
+ // Read-only. quoteExactInputSingle is a view call; this cannot sign or broadcast.
206
+ if (UNI_V3_CHAINS[Number(chainId)]) {
207
+ c.push({
208
+ source: "uniswap-v3",
209
+ run: async () => {
210
+ const q = await uniV3QuoteExactIn(
211
+ { chainId, tokenIn, tokenOut, amountIn },
212
+ opts,
213
+ );
214
+ // Gas is deliberately null, not 0: the quoter returns a gasEstimate in UNITS,
215
+ // and without a gas price that is not a USD cost. Reporting 0 would make this
216
+ // source look free and beat correctly-priced aggregators. See CoW above for
217
+ // the one case where 0 is a measured fact rather than a missing number.
218
+ return {
219
+ amountOut: q?.amountOut,
220
+ minOut: q?.minOut ?? q?.amountOutMinimum ?? null,
221
+ gasUsd: null,
222
+ meta: { onchain: true, fee: q?.fee, gasUnits: q?.gasEstimate, quoter: q?.quoter },
223
+ };
224
+ },
225
+ });
226
+ }
227
+
191
228
  return c;
192
229
  }
193
230