编译器
0.8.19+commit.7dd6d404
文件 1 的 12:Address.sol
pragma solidity ^0.8.1;
library Address {
function isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
if (returndata.length > 0) {
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
文件 2 的 12:EOA.sol
pragma solidity ^0.8.19;
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import {IIntentHelper} from "./interfaces/IIntentHelper.sol";
import {IAA} from "./interfaces/IAA.sol";
import {IWETH, IERC20} from "./interfaces/IWETH.sol";
import {IIntentManager} from "./interfaces/IIntentManager.sol";
import {
IUniswapV2Router01,
IUniswapV2Router02
} from "./mocks/uniswapv2/interfaces/IUniswapV2Router02.sol";
contract EOA is ReentrancyGuard {
using SafeERC20 for IERC20;
using Address for address;
using Address for address payable;
enum Command {
V3_SWAP_EXACT_IN,
V3_SWAP_EXACT_OUT,
V2_SWAP_EXACT_IN,
V2_SWAP_EXACT_OUT,
V2_SWAP_EXACT_ETH_IN,
V2_SWAP_EXACT_IN_FEE
}
struct Parsed {
uint256 feePoint;
address tokenIn;
address tokenOut;
uint256 amountIn;
Call[] calls;
}
struct Call {
address target;
bytes data;
}
address public immutable WETH;
address public immutable UNISWAP_V2_ROUTER02;
IIntentManager public immutable INTENT_MANAGER;
uint256 public immutable ID_INVITE_REWARD_CLAIM;
address public claimContract;
receive() external payable {}
constructor(
address weth,
address uniswapV2Router02,
IIntentManager intentManager,
uint256 idInviteRewardClaim
) {
WETH = weth;
UNISWAP_V2_ROUTER02 = uniswapV2Router02;
INTENT_MANAGER = intentManager;
ID_INVITE_REWARD_CLAIM = idInviteRewardClaim;
IERC20(WETH).approve(UNISWAP_V2_ROUTER02, type(uint256).max);
}
function handleIntent(IAA.Intent calldata intent) external payable nonReentrant {
if (intent.intentId == ID_INVITE_REWARD_CLAIM) {
if (claimContract == address(0)) {
claimContract = INTENT_MANAGER.getValidHelper(ID_INVITE_REWARD_CLAIM);
require(claimContract != address(0), "EOA: no claim contract");
}
IIntentHelper(claimContract).parse(abi.encode(msg.sender, intent.params));
if (msg.value > 0) {
payable(msg.sender).sendValue(msg.value);
}
return;
}
address recipient = INTENT_MANAGER.getTaxRecipient();
Parsed memory parsed = _parse(intent.params);
bool isBuy = parsed.tokenIn == WETH;
uint256 fee;
if (isBuy) {
fee = (parsed.amountIn * parsed.feePoint) / 10000;
require(msg.value >= parsed.amountIn + fee, "EOA: insufficient value");
uint256 refundEther = msg.value - parsed.amountIn - fee;
if (refundEther > 0) {
payable(msg.sender).sendValue(refundEther);
}
if (fee > 0) {
payable(recipient).sendValue(fee);
}
IWETH(WETH).deposit{value: parsed.amountIn}();
} else {
if (msg.value > 0) {
payable(msg.sender).sendValue(msg.value);
}
IERC20(parsed.tokenIn).safeTransferFrom(msg.sender, address(this), parsed.amountIn);
}
for (uint256 i = 0; i < parsed.calls.length; ++i) {
Call memory call = parsed.calls[i];
call.target.functionCall(call.data, "EOA: call failed");
}
uint256 gainAmount = IERC20(parsed.tokenOut).balanceOf(address(this));
if (isBuy) {
IERC20(parsed.tokenOut).safeTransfer(msg.sender, gainAmount);
} else {
IWETH(WETH).withdraw(gainAmount);
fee = (gainAmount * parsed.feePoint) / 10000;
gainAmount -= fee;
if (gainAmount > 0) {
payable(msg.sender).sendValue(gainAmount);
}
if (address(this).balance > 0) {
payable(recipient).sendValue(address(this).balance);
}
}
emit BotEOAIntentHandled(msg.sender, intent.intentId, fee, parsed.amountIn, gainAmount);
}
function _parse(bytes calldata _params) internal view returns (Parsed memory parsed) {
(
uint8 v,
bool approve,
uint256 amountInOrOut,
uint256 minOutOrMaxIn,
bytes memory path
) = abi.decode(_params, (uint8, bool, uint256, uint256, bytes));
address[] memory v2path = new address[](2);
(v2path[0], v2path[1]) = abi.decode(path, (address, address));
parsed.feePoint = _mustHaveWETH(v2path[0], v2path[1]);
parsed.tokenIn = v2path[0];
parsed.tokenOut = v2path[1];
parsed.amountIn = amountInOrOut;
Command command = Command(v);
if (command == Command.V2_SWAP_EXACT_ETH_IN) {
parsed.calls = new Call[](1);
parsed.calls[0] = Call({
target: UNISWAP_V2_ROUTER02,
data: abi.encodeWithSelector(
IUniswapV2Router01.swapExactETHForTokens.selector,
minOutOrMaxIn,
v2path,
address(this),
block.timestamp + 15 minutes
)
});
return (parsed);
} else if (command == Command.V2_SWAP_EXACT_IN) {
if (!approve) {
parsed.calls = new Call[](1);
} else {
parsed.calls = new Call[](2);
parsed.calls[0] = Call({
target: v2path[0],
data: abi.encodeWithSelector(
IERC20.approve.selector,
UNISWAP_V2_ROUTER02,
type(uint256).max
)
});
}
parsed.calls[parsed.calls.length - 1] = Call({
target: UNISWAP_V2_ROUTER02,
data: abi.encodeWithSelector(
IUniswapV2Router01.swapExactTokensForTokens.selector,
amountInOrOut,
minOutOrMaxIn,
v2path,
address(this),
block.timestamp + 15 minutes
)
});
} else if (command == Command.V2_SWAP_EXACT_IN_FEE) {
if (!approve) {
parsed.calls = new Call[](1);
} else {
parsed.calls = new Call[](2);
parsed.calls[0] = Call({
target: v2path[0],
data: abi.encodeWithSelector(
IERC20.approve.selector,
UNISWAP_V2_ROUTER02,
type(uint256).max
)
});
}
parsed.calls[parsed.calls.length - 1] = Call({
target: UNISWAP_V2_ROUTER02,
data: abi.encodeWithSelector(
IUniswapV2Router02
.swapExactTokensForTokensSupportingFeeOnTransferTokens
.selector,
amountInOrOut,
minOutOrMaxIn,
v2path,
address(this),
block.timestamp + 15 minutes
)
});
} else {
revert("EOA: unknown command");
}
}
function _mustHaveWETH(address tokenIn, address tokenOut) internal view returns (uint256) {
address[] memory tokens = new address[](1);
if (tokenIn == WETH) {
tokens[0] = tokenOut;
} else if (tokenOut == WETH) {
tokens[0] = tokenIn;
} else {
revert("EOA: unsupported pair");
}
(, uint256[] memory points) = INTENT_MANAGER.getTaxPoints(tokens);
return points[0];
}
event BotEOAIntentHandled(
address indexed account,
uint256 indexed intentId,
uint256 tax,
uint256 payAmount,
uint256 gainAmount
);
}
文件 3 的 12:IAA.sol
pragma solidity ^0.8.19;
interface IAA {
struct Intent {
uint256 intentId;
uint256 ensureMinimumWETH;
bytes params;
}
function initialize(address admin) external;
function initialize(address operator, address admin, uint256 outerGas) external;
function handleIntent(Intent calldata intent, bytes32[] calldata) external;
}
文件 4 的 12:IERC20.sol
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
文件 5 的 12:IERC20Permit.sol
pragma solidity ^0.8.0;
interface IERC20Permit {
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function nonces(address owner) external view returns (uint256);
function DOMAIN_SEPARATOR() external view returns (bytes32);
}
文件 6 的 12:IIntentHelper.sol
pragma solidity ^0.8.19;
interface IIntentHelper {
struct Call {
address target;
uint256 value;
bytes data;
int256 gas;
}
function parse(bytes calldata params) external returns (uint256 taxPoint, Call[] memory calls);
}
文件 7 的 12:IIntentManager.sol
pragma solidity ^0.8.19;
interface IIntentManager {
function getValidHelper(uint256) external view returns (address);
function verifyForDeploy(
address account,
bytes32[] calldata proofs
) external view returns (uint32);
function verifyForHandle(
uint256 id,
address account,
bytes32[] calldata proofs
) external view returns (address, uint80, address, uint32, uint32);
function verifyForWithdraw(
address account,
bytes32[] calldata proofs
) external view returns (address, uint32);
function getTaxRecipient() external view returns (address);
function isAAOperator(address, bytes32[] calldata) external view returns (bool);
function isAdmin(address account) external view returns (bool);
function getTaxPoints(
address[] calldata tokenAddresses
) external view returns (bool[] memory isCustom, uint256[] memory taxPoints);
}
文件 8 的 12:IUniswapV2Router01.sol
pragma solidity >=0.6.2;
interface IUniswapV2Router01 {
function factory() external pure returns (address);
function WETH() external pure returns (address);
function addLiquidity(
address tokenA,
address tokenB,
uint amountADesired,
uint amountBDesired,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB, uint liquidity);
function addLiquidityETH(
address token,
uint amountTokenDesired,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external payable returns (uint amountToken, uint amountETH, uint liquidity);
function removeLiquidity(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline
) external returns (uint amountA, uint amountB);
function removeLiquidityETH(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountToken, uint amountETH);
function removeLiquidityWithPermit(
address tokenA,
address tokenB,
uint liquidity,
uint amountAMin,
uint amountBMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountA, uint amountB);
function removeLiquidityETHWithPermit(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountToken, uint amountETH);
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapTokensForExactTokens(
uint amountOut,
uint amountInMax,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline)
external
returns (uint[] memory amounts);
function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline)
external
payable
returns (uint[] memory amounts);
function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB);
function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut);
function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn);
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);
function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts);
}
文件 9 的 12:IUniswapV2Router02.sol
pragma solidity >=0.6.2;
import './IUniswapV2Router01.sol';
interface IUniswapV2Router02 is IUniswapV2Router01 {
function removeLiquidityETHSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline
) external returns (uint amountETH);
function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(
address token,
uint liquidity,
uint amountTokenMin,
uint amountETHMin,
address to,
uint deadline,
bool approveMax, uint8 v, bytes32 r, bytes32 s
) external returns (uint amountETH);
function swapExactTokensForTokensSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
function swapExactETHForTokensSupportingFeeOnTransferTokens(
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external payable;
function swapExactTokensForETHSupportingFeeOnTransferTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external;
}
文件 10 的 12:IWETH.sol
pragma solidity ^0.8.10;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IWETH is IERC20 {
function deposit() external payable;
function withdraw(uint) external;
}
文件 11 的 12:ReentrancyGuard.sol
pragma solidity ^0.8.0;
abstract contract ReentrancyGuard {
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
_status = _ENTERED;
}
function _nonReentrantAfter() private {
_status = _NOT_ENTERED;
}
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == _ENTERED;
}
}
文件 12 的 12:SafeERC20.sol
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";
library SafeERC20 {
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 oldAllowance = token.allowance(address(this), spender);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
}
}
function forceApprove(IERC20 token, address spender, uint256 value) internal {
bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
if (!_callOptionalReturnBool(token, approvalCall)) {
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
_callOptionalReturn(token, approvalCall);
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
function _callOptionalReturn(IERC20 token, bytes memory data) private {
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
(bool success, bytes memory returndata) = address(token).call(data);
return
success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
}
}
{
"compilationTarget": {
"contracts/EOA.sol": "EOA"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"weth","type":"address"},{"internalType":"address","name":"uniswapV2Router02","type":"address"},{"internalType":"contract IIntentManager","name":"intentManager","type":"address"},{"internalType":"uint256","name":"idInviteRewardClaim","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"intentId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tax","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"payAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"gainAmount","type":"uint256"}],"name":"BotEOAIntentHandled","type":"event"},{"inputs":[],"name":"ID_INVITE_REWARD_CLAIM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"INTENT_MANAGER","outputs":[{"internalType":"contract IIntentManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNISWAP_V2_ROUTER02","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"intentId","type":"uint256"},{"internalType":"uint256","name":"ensureMinimumWETH","type":"uint256"},{"internalType":"bytes","name":"params","type":"bytes"}],"internalType":"struct IAA.Intent","name":"intent","type":"tuple"}],"name":"handleIntent","outputs":[],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]