fix: oracle sync#8
Merged
Merged
Conversation
- correctly encode oracle sync swaps to be sent to smart pool
There was a problem hiding this comment.
Pull request overview
This PR fixes oracle-sync swap broadcasting by extending the oracle refresh flow to support both direct EOA Universal Router transactions and vault-adapter-routed transactions (enabling delegation-compatible execution), while improving user-facing messaging for native-token chains.
Changes:
- Add native-token symbol support and a new optional vault route for oracle refresh swaps.
- Update the
/api/oracle/refreshroute and the LLM tool implementation/schema to accept optional amounts,amountOutestimation, andviaVaultrouting. - Improve the frontend transaction modal display for
msg.valueand operator-only transactions.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| src/services/oraclePool.ts | Adds native-token symbol helper and supports building oracle refresh txs for EOA vs vault paths. |
| src/routes/oracle.ts | Updates refresh endpoint to default amount, accept optional vaultAddress, and adjust client-error detection. |
| src/llm/tools.ts | Updates refresh_oracle_feed tool description/parameters to support native tokens, amountOut, and viaVault. |
| src/llm/client.ts | Implements amountOut→amountIn estimation, optional vault routing, and EOA simulation/gas estimation for oracle refresh tool calls. |
| public/index.html | Enhances tx modal rendering (value display, operator-only labeling). |
Comments suppressed due to low confidence (1)
src/routes/oracle.ts:15
- The route docstring now documents an optional
vaultAddresspath, but it still says the endpoint “Returns an unsigned OPERATOR EOA transaction… targets the Universal Router, not the vault adapter.” That’s no longer always true; update these lines to describe both the vault-adapter path and the EOA path to avoid misleading callers.
* token string — ERC-20 symbol or address whose oracle feed is stale (e.g. "GRG", "USDC")
* amountEth string — Amount of native token to swap (human-readable, e.g. "0.001"). Optional; defaults to 0.001.
* chainId number — Chain where the oracle pool lives
* vaultAddress string — Optional. If provided, routes through the vault adapter (value=0, supports delegation).
* Omit for EOA path (direct to Universal Router).
*
* Returns an unsigned OPERATOR EOA transaction to be signed with the operator's
* personal wallet (not the vault). The transaction targets the Universal Router,
* not the vault adapter.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- oracle.ts: import Address type from viem (was used but not imported) - oracle.ts: use nativeSymbol in amountEth validation error message - oracle.ts: update docstring to describe both EOA and vault paths - client.ts: move nativeSymbol derivation after chain-switch so it reflects the finalised chainId (fixes stale symbol in logs/errors) - client.ts: explicitly reject requests that set both amountEth and amountOut (previously amountOut was silently ignored) - tools.ts: update refresh_oracle_feed description to reflect both the EOA path (default) and the vault-adapter path (viaVault=true) - oraclePool.ts: set operatorOnly:true on EOA-path transaction so the UI can correctly label it without relying on msg.value heuristics - index.html: derive isOperatorOnly from tx.operatorOnly OR valueBigInt>0 (vault calls never carry msg.value, so >0 is a reliable EOA signal) - index.html: show '0 (vault uses own balance)' only for vault transactions; EOA transactions with value=0 show plain '0' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- oraclePool.ts: add operatorOnly?: boolean to OraclePoolSwapResult transaction type (EOA path sets this flag; type must declare it) - oracle.ts: import isAddress from viem; use it for strict vaultAddress validation and return 400 instead of silently falling back to EOA path - client.ts: when amountOut is provided but vault/RPC missing, throw an explicit error instead of silently defaulting amountIn to 0.001; also throw when oracle estimation fails rather than falling through to default - index.html: replace Number(valueBigInt)/1e18 with BigInt-safe formatter to avoid precision loss for large msg.value amounts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- client.ts: handle estimatedIn < 0n (negative oracle int256) separately from === 0n; negative result gets its own error message distinct from the zero-estimate error - index.html: tighten comment on the msg.value heuristic — delegated vault adapter calls never require msg.value, but direct vault-owner calls (e.g. fundPool) can; the comment was misleading Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Update transaction field JSDoc to describe both paths: EOA (operatorOnly=true, targets Universal Router, msg.value=amountIn) and vault (operatorOnly absent, targets vault adapter, value=0, delegatable) - Clarify vault-path comment: vault.execute is non-payable so no msg.value is sent by caller; V4 SETTLE_ALL is satisfied from the vault's own native balance, not from msg.value (encoding alone does not eliminate settlement) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- oraclePool.ts: use 30-minute deadline for vault/delegated path (was 5 min) to accommodate queuing and user review before submission - oraclePool.ts: update file-level '## Transaction type' doc to describe both EOA path (Universal Router, msg.value=amountIn) and vault path (vault adapter, value=0, settlement from vault balance) - oracle.ts: reject zero address (0x000...000) in addition to malformed addresses — zero address passes isAddress() but is an invalid destination - client.ts: validate desiredOutRaw > 0n before calling convertTokenAmount; inputs like '0' or '-1' now fail fast with a clear error instead of propagating to confusing oracle-level errors Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- client.ts: coerce args.amountEth and args.amountOut with String() so numeric inputs from function-calling don't bypass parseUnits - client.ts: accept viaVault as boolean or string 'true' to match pattern used by other tools in this file - oracle.ts: coerce numeric amountEth to string rather than silently treating it as missing and defaulting to 0.001 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- client.ts: check vault-path guard BEFORE mutating ctx.chainId to prevent partial context mutation on throw - tools.ts: clarify vault path output destination (TAKE_ALL sends to vault) - oraclePool.ts: fix SETTLE_ALL/TAKE_ALL comments to distinguish EOA vs vault path settlement source and output recipient Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use String(args.amountOut).trim() consistently so that falsy-but-valid values like 0 and whitespace strings don't bypass or spuriously trigger the vault-path chain-switch guard. Reuse normalizedAmountOut for the amountOut const below to avoid double-coercion. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- oraclePool.ts: validate amountInWei > 0n after parseUnits to produce a clear error instead of silently building a zero-value swap calldata - oracle.ts: use Number.toFixed(18) instead of String() for numeric amountEth to avoid scientific notation (e.g. 0.0000001 → '1e-7') that parseUnits rejects; the existing parseUnits validation still catches any remaining invalid values with a 400 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/services/oraclePool.ts:380
- For the vault path, this encodes calldata using
UR_EXECUTE_ABI(payable) even though the vault exposesexecuteasnonpayableviaRIGOBLOCK_VAULT_ABI(and there are two overloads). The selector/encoding likely matches today, but using the vault ABI (orencodeVaultExecutehelper) would make the intent clearer and reduce the chance of subtle drift if the Universal Router ABI changes or if the vault adapter interface diverges.
// Encode Universal Router execute(commands, inputs, deadline)
// Vault/delegated path uses 30 minutes to accommodate queuing and user review;
// EOA path uses 5 minutes since the user signs and broadcasts immediately.
const deadlineSeconds = viaVault ? 1800 : 300;
const deadline = BigInt(Math.floor(Date.now() / 1000) + deadlineSeconds);
const calldata = encodeFunctionData({
abi: UR_EXECUTE_ABI,
functionName: "execute",
args: [V4_SWAP_COMMAND, [v4SwapInput], deadline],
});
Add explicit zero-address check at the entry point of buildOraclePoolSwapTx so future call sites don't silently generate an unusable transaction to the zero address. Both the HTTP route and LLM tool path already validate this, but defense-in-depth in the service layer ensures all callers are safe. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…tOut Introduce a toDecimalString() helper that uses Number.toFixed(18) for numeric inputs and String().trim() for other values. Apply it to both normalizedAmountOut and amountIn in the refresh_oracle_feed tool handler, mirroring the toFixed(18) fix already applied to the HTTP route in oracle.ts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- oraclePool.ts: remove misleading 'slippage protection' claims from module header and buildOraclePoolSwapTx JSDoc; the swap uses amountOutMinimum=0 (exact-input); the NAV shield enforces a value-level check, not per-token slippage - tools.ts: reword refresh_oracle_feed amountOut description from 'Desired output amount' (implies guarantee) to 'Sizing hint' with a note that actual received amount may differ and there is no on-chain min-out bound Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…SS in oracle pool
resolveTokenAddress('WETH', chainId) returns the real WETH contract address
(e.g. 0x4200...0006 on Base), not 0x0 or 0xeeee... So the existing guard
for 'ETH/WETH does not need an oracle update' was silently bypassed when
the caller passed 'WETH' (or 'WBNB', 'WPOL' on other chains).
Fix: look up the chain's wrapped-native address from TOKEN_MAP using the
W${nativeSymbol} key and add it to the normalization block so WETH/WBNB/WPOL
are mapped to ETH_ADDRESS before the guard is evaluated.
Also move nativeSymbol declaration before tokenAddr so it can be used in
the normalization condition.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix an issue that prevented an oracle-sync swap to be broadcasted