refactor: move all remaining files to orig/ directory
Completed clean root directory structure: - Root now contains only: .git, .env, docs/, orig/ - Moved all remaining files and directories to orig/: - Config files (.claude, .dockerignore, .drone.yml, etc.) - All .env variants (except active .env) - Git config (.gitconfig, .github, .gitignore, etc.) - Tool configs (.golangci.yml, .revive.toml, etc.) - Documentation (*.md files, @prompts) - Build files (Dockerfiles, Makefile, go.mod, go.sum) - Docker compose files - All source directories (scripts, tests, tools, etc.) - Runtime directories (logs, monitoring, reports) - Dependency files (node_modules, lib, cache) - Special files (--delete) - Removed empty runtime directories (bin/, data/) V2 structure is now clean: - docs/planning/ - V2 planning documents - orig/ - Complete V1 codebase preserved - .env - Active environment config (not in git) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
259
orig/contracts/PoolDetector.sol
Normal file
259
orig/contracts/PoolDetector.sol
Normal file
@@ -0,0 +1,259 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity ^0.8.19;
|
||||
|
||||
/**
|
||||
* @title PoolDetector
|
||||
* @notice Efficient onchain pool detection for multiple DEX types
|
||||
* @dev Gas-optimized detection using assembly and batched calls
|
||||
*/
|
||||
contract PoolDetector {
|
||||
enum PoolType {
|
||||
Unknown,
|
||||
UniswapV2,
|
||||
UniswapV3,
|
||||
AlgebraV19,
|
||||
AlgebraIntegral,
|
||||
Balancer,
|
||||
Curve,
|
||||
Camelot,
|
||||
SushiswapV2,
|
||||
PancakeV3,
|
||||
KyberSwap
|
||||
}
|
||||
|
||||
struct PoolInfo {
|
||||
address pool;
|
||||
PoolType poolType;
|
||||
address token0;
|
||||
address token1;
|
||||
uint256 fee;
|
||||
bool isValid;
|
||||
uint8 confidence;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Detect pool type for a single address
|
||||
* @param pool The pool address to identify
|
||||
* @return info The pool information
|
||||
*/
|
||||
function detectPool(address pool) external view returns (PoolInfo memory info) {
|
||||
info.pool = pool;
|
||||
|
||||
// Check if contract exists
|
||||
uint256 codeSize;
|
||||
assembly {
|
||||
codeSize := extcodesize(pool)
|
||||
}
|
||||
|
||||
if (codeSize == 0) {
|
||||
info.isValid = false;
|
||||
return info;
|
||||
}
|
||||
|
||||
// Try to get token0 and token1 (common to all pools)
|
||||
(bool hasToken0, address token0) = _tryToken0(pool);
|
||||
(bool hasToken1, address token1) = _tryToken1(pool);
|
||||
|
||||
if (!hasToken0 || !hasToken1) {
|
||||
info.isValid = false;
|
||||
return info;
|
||||
}
|
||||
|
||||
info.token0 = token0;
|
||||
info.token1 = token1;
|
||||
info.isValid = true;
|
||||
|
||||
// Try UniswapV3 specific methods
|
||||
if (_isUniswapV3(pool)) {
|
||||
info.poolType = PoolType.UniswapV3;
|
||||
info.confidence = 95;
|
||||
(bool hasFee, uint256 fee) = _tryFeeV3(pool);
|
||||
if (hasFee) info.fee = fee;
|
||||
return info;
|
||||
}
|
||||
|
||||
// Try Algebra/Camelot (has globalState instead of slot0)
|
||||
if (_isAlgebra(pool)) {
|
||||
// Check for directional fees (Integral)
|
||||
if (_hasDirectionalFees(pool)) {
|
||||
info.poolType = PoolType.AlgebraIntegral;
|
||||
info.confidence = 90;
|
||||
} else {
|
||||
info.poolType = PoolType.AlgebraV19;
|
||||
info.confidence = 85;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
// Try UniswapV2/Sushiswap
|
||||
if (_isUniswapV2(pool)) {
|
||||
// Distinguish by factory
|
||||
address factory = _getFactory(pool);
|
||||
if (factory == 0xc35DADB65012eC5796536bD9864eD8773aBc74C4) {
|
||||
info.poolType = PoolType.SushiswapV2;
|
||||
} else {
|
||||
info.poolType = PoolType.UniswapV2;
|
||||
}
|
||||
info.confidence = 80;
|
||||
return info;
|
||||
}
|
||||
|
||||
// Unknown but valid pool
|
||||
info.poolType = PoolType.Unknown;
|
||||
info.confidence = 30;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Batch detect multiple pools
|
||||
* @param pools Array of pool addresses
|
||||
* @return infos Array of pool information
|
||||
*/
|
||||
function detectPools(address[] calldata pools)
|
||||
external
|
||||
view
|
||||
returns (PoolInfo[] memory infos)
|
||||
{
|
||||
infos = new PoolInfo[](pools.length);
|
||||
for (uint256 i = 0; i < pools.length; i++) {
|
||||
infos[i] = this.detectPool(pools[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Internal detection functions
|
||||
|
||||
function _isUniswapV3(address pool) private view returns (bool) {
|
||||
// Check for slot0, fee, tickSpacing, maxLiquidityPerTick
|
||||
(bool hasSlot0,) = _trySlot0(pool);
|
||||
(bool hasFee,) = _tryFeeV3(pool);
|
||||
(bool hasTickSpacing,) = _tryTickSpacing(pool);
|
||||
(bool hasMaxLiquidity,) = _tryMaxLiquidityPerTick(pool);
|
||||
|
||||
return hasSlot0 && hasFee && hasTickSpacing && hasMaxLiquidity;
|
||||
}
|
||||
|
||||
function _isAlgebra(address pool) private view returns (bool) {
|
||||
// Has globalState instead of slot0
|
||||
(bool hasGlobalState,) = _tryGlobalState(pool);
|
||||
(bool hasSlot0,) = _trySlot0(pool);
|
||||
|
||||
return hasGlobalState && !hasSlot0;
|
||||
}
|
||||
|
||||
function _isUniswapV2(address pool) private view returns (bool) {
|
||||
// Has getReserves, no slot0 or globalState
|
||||
(bool hasReserves,) = _tryGetReserves(pool);
|
||||
(bool hasSlot0,) = _trySlot0(pool);
|
||||
(bool hasGlobalState,) = _tryGlobalState(pool);
|
||||
|
||||
return hasReserves && !hasSlot0 && !hasGlobalState;
|
||||
}
|
||||
|
||||
function _hasDirectionalFees(address pool) private view returns (bool) {
|
||||
// Check for feeZto0 and fee0to1 (Algebra Integral)
|
||||
(bool success,) = pool.staticcall(
|
||||
abi.encodeWithSignature("feeZto0()")
|
||||
);
|
||||
return success;
|
||||
}
|
||||
|
||||
// Low-level call helpers
|
||||
|
||||
function _tryToken0(address pool) private view returns (bool success, address token) {
|
||||
bytes memory data;
|
||||
(success, data) = pool.staticcall(
|
||||
abi.encodeWithSignature("token0()")
|
||||
);
|
||||
if (success && data.length >= 32) {
|
||||
token = abi.decode(data, (address));
|
||||
}
|
||||
}
|
||||
|
||||
function _tryToken1(address pool) private view returns (bool success, address token) {
|
||||
bytes memory data;
|
||||
(success, data) = pool.staticcall(
|
||||
abi.encodeWithSignature("token1()")
|
||||
);
|
||||
if (success && data.length >= 32) {
|
||||
token = abi.decode(data, (address));
|
||||
}
|
||||
}
|
||||
|
||||
function _trySlot0(address pool) private view returns (bool success, bytes memory data) {
|
||||
(success, data) = pool.staticcall(
|
||||
abi.encodeWithSignature("slot0()")
|
||||
);
|
||||
}
|
||||
|
||||
function _tryGlobalState(address pool) private view returns (bool success, bytes memory data) {
|
||||
(success, data) = pool.staticcall(
|
||||
abi.encodeWithSignature("globalState()")
|
||||
);
|
||||
}
|
||||
|
||||
function _tryGetReserves(address pool) private view returns (bool success, bytes memory data) {
|
||||
(success, data) = pool.staticcall(
|
||||
abi.encodeWithSignature("getReserves()")
|
||||
);
|
||||
}
|
||||
|
||||
function _tryFeeV3(address pool) private view returns (bool success, uint256 fee) {
|
||||
bytes memory data;
|
||||
(success, data) = pool.staticcall(
|
||||
abi.encodeWithSignature("fee()")
|
||||
);
|
||||
if (success && data.length >= 32) {
|
||||
fee = abi.decode(data, (uint256));
|
||||
}
|
||||
}
|
||||
|
||||
function _tryTickSpacing(address pool) private view returns (bool success, bytes memory data) {
|
||||
(success, data) = pool.staticcall(
|
||||
abi.encodeWithSignature("tickSpacing()")
|
||||
);
|
||||
}
|
||||
|
||||
function _tryMaxLiquidityPerTick(address pool) private view returns (bool success, bytes memory data) {
|
||||
(success, data) = pool.staticcall(
|
||||
abi.encodeWithSignature("maxLiquidityPerTick()")
|
||||
);
|
||||
}
|
||||
|
||||
function _getFactory(address pool) private view returns (address factory) {
|
||||
(bool success, bytes memory data) = pool.staticcall(
|
||||
abi.encodeWithSignature("factory()")
|
||||
);
|
||||
if (success && data.length >= 32) {
|
||||
factory = abi.decode(data, (address));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @notice Efficient batch detection using multicall pattern
|
||||
* @param pools Array of pools to check
|
||||
* @return results Packed results for gas efficiency
|
||||
*/
|
||||
function batchDetectEfficient(address[] calldata pools)
|
||||
external
|
||||
view
|
||||
returns (uint256[] memory results)
|
||||
{
|
||||
results = new uint256[](pools.length);
|
||||
|
||||
for (uint256 i = 0; i < pools.length; i++) {
|
||||
// Pack result into single uint256:
|
||||
// bits 0-7: pool type
|
||||
// bits 8-15: confidence
|
||||
// bits 16-23: has token0
|
||||
// bits 24-31: has token1
|
||||
// bits 32+: fee (if applicable)
|
||||
|
||||
PoolInfo memory info = this.detectPool(pools[i]);
|
||||
|
||||
results[i] = uint256(info.poolType) |
|
||||
(uint256(info.confidence) << 8) |
|
||||
(info.token0 != address(0) ? 1 << 16 : 0) |
|
||||
(info.token1 != address(0) ? 1 << 24 : 0) |
|
||||
(info.fee << 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user