Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions src/FourMemeTokenQuoter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;

interface ITokenHelper {
function getTokenInfo(
address token
)
external
view
returns (
uint256 version,
address tokenManager,
address quote,
uint256 lastPrice,
uint256 tradingFeeRate,
uint256 minTradingFee,
uint256 launchTime,
uint256 offers,
uint256 maxOffers,
uint256 funds,
uint256 maxFunds,
bool liquidityAdded
);
}
interface ITokenSwap {
function _fees(address) external view returns (uint);
}
interface IFactory {
function getPool(address, address, uint24) external view returns (address);
function poolByPair(address, address) external view returns (address);
}


contract FourMemeTokenQuoter {
address public constant TOKEN_MANAGER = 0x5c952063c7fc8610FFDB798152D69F0B9550762b;
address public constant TOKEN_SWAP = 0x350A94c918f7A0C8d108ba90f1b242B0143572B9;
address public constant TOKEN_HELPER = 0xF251F83e40a78868FcfA3FA4599Dad6494E46034;

address public constant THENA = 0xF4C8E32EaDEC4BFe97E0F595AdD0f4450a863a11;
address public constant WETH = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
address public constant PANCAKE_QUOTER = 0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997;
address public constant PANCAKE_FACTORY = 0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865;
address public constant THENA_FACTORY = 0x306F06C147f064A010530292A1EB6737c3e378e4;

// Query token version
function getTokenVersion(address token) external view returns (uint256 version) {
(uint256 _version, , , , , , , , , , , ) = ITokenHelper(TOKEN_HELPER).getTokenInfo(token);
return _version;
}

// Query the pool address corresponding to the paired token
function getPoolAddress(address token) public view returns (address pool) {
(uint256 version, , address quoteToken, , , , , , , , , ) = ITokenHelper(TOKEN_HELPER).getTokenInfo(token);
require(version == 2, "Only version 2 supported");
require(quoteToken != WETH, "Quote token cannot be BNB");

uint24 fee = uint24(ITokenSwap(TOKEN_SWAP)._fees(quoteToken));

if (quoteToken == THENA) {
pool = IFactory(THENA_FACTORY).poolByPair(quoteToken, WETH);
} else {
require(fee > 0, "Invalid fee rate");
pool = IFactory(PANCAKE_FACTORY).getPool(quoteToken, WETH, fee);
}

require(pool != address(0), "Pool not found");
return pool;
}

// Query the fee rate of the paired token
function getFeeRate(address quoteToken) public view returns (uint24) {
return uint24(ITokenSwap(TOKEN_SWAP)._fees(quoteToken));
}

// Get complete token information
function getTokenInfo(address token) external view returns (
uint256 version,
address quoteToken,
address poolAddress,
uint24 feeRate
) {
(version, , quoteToken, , , , , , , , , ) = ITokenHelper(TOKEN_HELPER).getTokenInfo(token);

if (version == 2 && quoteToken != WETH) {
feeRate = getFeeRate(quoteToken);
if (feeRate > 0 || quoteToken == THENA) {
poolAddress = getPoolAddress(token);
}
}

return (version, quoteToken, poolAddress, feeRate);
}
}
47 changes: 47 additions & 0 deletions src/RingQuoter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IERC20 {
function balanceOf(address account) external view returns (uint256);
function decimals() external view returns (uint8);
}

interface ISwapV2Pair {
function token0() external view returns (address);
function token1() external view returns (address);
}

interface IFewWrappedToken {
function token() external view returns (address);
}

contract RingQuoter {
function getPoolTokenBalance(
address pool
)
external
view
returns (
uint256 token0Balance,
uint256 token1Balance,
uint256 underlyingAsset0Balance,
uint256 underlyingAsset1Balance
)
{
address token0 = ISwapV2Pair(pool).token0();
address token1 = ISwapV2Pair(pool).token1();
address underlyingAsset0 = IFewWrappedToken(token0).token();
address underlyingAsset1 = IFewWrappedToken(token1).token();
token0Balance = IERC20(token0).balanceOf(pool);
token1Balance = IERC20(token1).balanceOf(pool);
underlyingAsset0Balance = IERC20(underlyingAsset0).balanceOf(token0);
underlyingAsset1Balance = IERC20(underlyingAsset1).balanceOf(token1);

return (
token0Balance,
token1Balance,
underlyingAsset0Balance,
underlyingAsset1Balance
);
}
}
50 changes: 50 additions & 0 deletions test/FourMemeTokenQuoter.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Test, console2} from "forge-std/Test.sol";
import {FourMemeTokenQuoter} from "../src/FourMemeTokenQuoter.sol";

contract FourMemeTokenQuoterTest is Test {
FourMemeTokenQuoter public quoter;

address public constant TOKEN_MANAGER = 0x5c952063c7fc8610FFDB798152D69F0B9550762b;
address public constant TOKEN_SWAP = 0x350A94c918f7A0C8d108ba90f1b242B0143572B9;
address public constant TOKEN_HELPER = 0xF251F83e40a78868FcfA3FA4599Dad6494E46034;

address public constant THENA = 0xF4C8E32EaDEC4BFe97E0F595AdD0f4450a863a11;
address public constant WETH = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;
address public constant PANCAKE_QUOTER = 0xB048Bbc1Ee6b733FFfCFb9e9CeF7375518e25997;
address public constant PANCAKE_FACTORY = 0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865;
address public constant THENA_FACTORY = 0x306F06C147f064A010530292A1EB6737c3e378e4;


address constant TestToken = 0xb15EeE57E3AcC00ab15cCA0B65C2b5d0dA154444;
address constant ThenaToken = 0xbf141E43c961A8a35930b15722923fb39bDd4444;

function setUp() public {
// Fork BSC mainnet for realistic testing
vm.createSelectFork("https://bsc.blockrazor.xyz");

// Deploy the quoter contract
quoter = new FourMemeTokenQuoter();
}

function test_getTokenInfo_NormalToken() public {
(uint256 version, address quoteToken, address poolAddress, uint24 feeRate) = quoter.getTokenInfo(TestToken);
console2.log("version", version);
console2.log("quoteToken", quoteToken);
console2.log("poolAddress", poolAddress);
console2.log("feeRate", feeRate);
assert(version == 2);
assert(quoteToken == 0x8d0D000Ee44948FC98c9B98A4FA4921476f08B0d);
assert(poolAddress == 0x4a3218606AF9B4728a9F187E1c1a8c07fBC172a9);
}

function test_getTokenInfo_ThenaToken() public {
(uint256 version, address quoteToken, address poolAddress, uint24 feeRate) = quoter.getTokenInfo(ThenaToken);
console2.log("version", version);
console2.log("quoteToken", quoteToken);
console2.log("poolAddress", poolAddress);
console2.log("feeRate", feeRate);
}
}
24 changes: 24 additions & 0 deletions test/RingQuoter.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

import {RingQuoter} from "../src/RingQuoter.sol";
import {Test, console2} from "forge-std/Test.sol";

contract RingQuoterTest is Test {
RingQuoter public quoter;
address constant RingPool = 0x44deaF11892D189D1D1c0CCF3bdE7a6CCEa24405;

function setUp() public {
vm.createSelectFork("https://eth.llamarpc.com");
quoter = new RingQuoter();
}

function testGetPoolTokenBalance() public {
(uint256 token0Balance, uint256 token1Balance, uint256 underlyingAsset0Balance, uint256 underlyingAsset1Balance) = quoter.getPoolTokenBalance(RingPool);
console2.log("token0Balance", token0Balance);
console2.log("token1Balance", token1Balance);
console2.log("underlyingAsset0Balance", underlyingAsset0Balance);
console2.log("underlyingAsset1Balance", underlyingAsset1Balance);
}

}