Я реализую токен, который берет комиссию за покупку/продажу, но не за передачу. Я полагаюсь на проверку «от» и «до» на наличие пар uniswap (V2 или V3), чтобы определить это как транзакцию покупки/продажи. Для V2 это довольно просто, так как я могу использовать фабричную функцию для получения адреса пары. Но для пулов V3 существует больше комбинаций, и в будущем могут быть добавлены дополнительные сборы. Итак, я хочу программно проверить, имеет ли адрес «от» или «до» функцию «token0», используя address.staticcall().
Проблема в том, что staticcall() просто не работает с возвратом, если функция «token0» не существует, любые предложения будут очень признательны. В любом случае, помочь определить, что адрес является парой/пулом без возврата, будет работать.
Вот код, который я использую (из github) - этот код вызывает функцию symbol()
Этот вызов может вернуться, если вызываемая функция не существует в контракте. Здесь я вызываю symbol(), но потенциально могу вызвать token0() или любую другую функцию
function _isUniswapV2Pair(address target) internal view returns (bool) {
address token0;
address token1;
string memory targetSymbol = _callAndParseStringReturn(
target,
hex"95d89b41" // symbol()
);
if (bytes(targetSymbol).length == 0) {
return false;
}
if (_compare(targetSymbol, "UNI-V2")) {
IUniswapV2Pair pairContract = IUniswapV2Pair(target);
try pairContract.token0() returns (address _token0) {
token0 = _token0;
} catch Error(string memory) {
return false;
} catch (bytes memory) {
return false;
}
try pairContract.token1() returns (address _token1) {
token1 = _token1;
} catch Error(string memory) {
return false;
} catch (bytes memory) {
return false;
}
} else {
return false;
}
return target == _dexFactoryV2.getPair(token0, token1); }
function _callAndParseStringReturn(address token, bytes4 selector)
internal
view
returns (string memory)
{
(bool success, bytes memory data) = token.staticcall(
abi.encodeWithSelector(selector)
);
// if not implemented, or returns empty data, return empty string
if (!success || data.length == 0) {
return "";
}
// bytes32 data always has length 32
if (data.length == 32) {
bytes32 decoded = abi.decode(data, (bytes32));
return _bytes32ToString(decoded);
} else if (data.length > 64) {
return abi.decode(data, (string));
}
return ""; }
function _bytes32ToString(bytes32 x) internal pure returns (string memory) {
bytes memory bytesString = new bytes(32);
uint256 charCount = 0;
for (uint256 j = 0; j < 32; j++) {
bytes1 char = x[j];
if (char != 0) {
bytesString[charCount] = char;
charCount++;
}
}
bytes memory bytesStringTrimmed = new bytes(charCount);
for (uint256 j = 0; j < charCount; j++) {
bytesStringTrimmed[j] = bytesString[j];
}
return string(bytesStringTrimmed); }
Я изучил документацию по Solidity и исследовал использование функций сборки для определения имени контракта, но похоже, что это невозможно.
Также попробовал несколько подходов, чтобы избежать возврата из статического вызова, если вызываемая функция не существует. Есть несколько контрактов, которые передаются для передачи в случае обмена uniswap — это может быть SwapRouter, или NFPosManager, или пользовательские токены, или любой другой контракт.
К вашему сведению, я проверяю, является ли адрес контрактом, а не адресом кошелька, прежде чем делать этот звонок.





Насколько мне известно, не существует 100% точной проверки того, реализует ли конкретный контракт конкретную функцию.
Вы можете проверить, содержит ли его байт-код селектор функции, но есть ложные срабатывания — т.е. тот же фрагмент байтов присутствует в байт-коде, даже если это не селектор функции.
Кроме того, некоторые контракты реализуют функцию fallback(), которая вызывается каждый раз, когда вы пытаетесь вызвать функцию, которая не определена в контракте. Таким образом, в некоторых случаях fallback() может быть приемлемым для внешней логики проверки, а в некоторых — нет.
Поскольку ваш вопрос, по-видимому, касается проверки пар Uniswap, возможно, этот ответ может быть полезен. Он проверяет вызовы token0() и token1() с помощью try / catch, а затем проверяет соответствие с контрактом маршрутизатора, если парный адрес зарегистрирован в Uniswap.
Обновите вопрос с полным кодом для проверки пары для V2 - у меня есть аналогичный для V3
Спасибо, Петр - я просмотрел ответ, на который вы ссылались. Ограничение этого решения заключается в том, что оно хорошо работает для UniswapV2, и я использую аналогичный подход. Однако с UniswapV3 существует несколько сборов, и для каждой комбинации может быть создан пул. Также UniswapV3 разрешает доступ к пулу, а не к паре, поэтому я предполагаю, что для одной и той же пары может быть несколько пулов. Мне нужно иметь возможность динамически проверять и нужен некоторый код, который не возвращается, если это не пул или пара, а все же контракт