//SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface Pool {
function tokenA() external view returns (IERC20);
function tokenB() external view returns (IERC20);
}
interface IERC20 {
function decimals() external view returns (uint8);
}
/**
* @dev This contract is not meant to be deployed. Instead, use a static call with the
* deployment bytecode as payload.
*/
contract MaverickDataSync {
struct PoolData {
address poolAddr;
address tokenA;
address tokenB;
uint8 tokenADecimals;
uint8 tokenBDecimals;
}
constructor(address[] memory pools) {
PoolData[] memory allPoolData = new PoolData[](pools.length);
for (uint256 i = 0; i < pools.length; ++i) {
address poolAddress = pools[i];
if (codeSizeIsZero(poolAddress)) continue;
PoolData memory poolData;
// Get tokens A and B
IERC20 tokenA = Pool(poolAddress).tokenA();
IERC20 tokenB = Pool(poolAddress).tokenB();
poolData.tokenA = address(tokenA);
poolData.tokenB = address(tokenB);
poolData.poolAddr = poolAddress;
// Check that tokenA and tokenB do not have codesize of 0
if (codeSizeIsZero(poolData.tokenA)) continue;
if (codeSizeIsZero(poolData.tokenB)) continue;
// Get tokenA decimals
(
bool tokenADecimalsSuccess,
bytes memory tokenADecimalsData
) = poolData.tokenA.call{gas: 20000}(
abi.encodeWithSignature("decimals()")
);
if (tokenADecimalsSuccess) {
uint256 tokenADecimals;
if (tokenADecimalsData.length == 32) {
(tokenADecimals) = abi.decode(
tokenADecimalsData,
(uint256)
);
if (tokenADecimals == 0 || tokenADecimals > 255) {
continue;
} else {
poolData.tokenADecimals = uint8(tokenADecimals);
}
} else {
continue;
}
} else {
continue;
}
// Get tokenB decimals
(
bool tokenBDecimalsSuccess,
bytes memory tokenBDecimalsData
) = poolData.tokenB.call{gas: 20000}(
abi.encodeWithSignature("decimals()")
);
if (tokenBDecimalsSuccess) {
uint256 tokenBDecimals;
if (tokenBDecimalsData.length == 32) {
(tokenBDecimals) = abi.decode(
tokenBDecimalsData,
(uint256)
);
if (tokenBDecimals == 0 || tokenBDecimals > 255) {
continue;
} else {
poolData.tokenBDecimals = uint8(tokenBDecimals);
}
} else {
continue;
}
} else {
continue;
}
allPoolData[i] = poolData;
}
// ensure abi encoding, not needed here but increase reusability for different return types
// note: abi.encode add a first 32 bytes word with the address of the original data
bytes memory _abiEncodedData = abi.encode(allPoolData);
assembly {
// Return from the start of the data (discarding the original data address)
// up to the end of the memory used
let dataStart := add(_abiEncodedData, 0x20)
return(dataStart, sub(msize(), dataStart))
}
}
function codeSizeIsZero(address target) internal view returns (bool) {
if (target.code.length == 0) {
return true;
} else {
return false;
}
}
}