编译器
0.8.17+commit.8df45f5f
文件 1 的 11: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 的 11:Common.sol
pragma solidity ^0.8.4;
library Common {
function _validateAddress(address _addr) internal pure {
require(_addr != address(0), "Address cannot be zero");
}
function _isContract(address account) internal view returns (bool) {
return account.code.length > 0;
}
}
文件 3 的 11:ERC165.sol
pragma solidity ^0.8.0;
import "./IERC165.sol";
abstract contract ERC165 is IERC165 {
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}
文件 4 的 11:IERC165.sol
pragma solidity ^0.8.0;
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
文件 5 的 11:IERC20.sol
pragma solidity ^0.8.4;
interface IERC20 {
function totalSupply() external view returns (uint256);
function decimals() external view returns (uint8);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function balanceOf(address account) external view returns (uint256);
function transfer(address recipient, 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 sender, address recipient, uint256 amount) external returns (bool);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
}
文件 6 的 11:IStarBaseLimitOrder.sol
pragma solidity ^0.8.0;
interface IStarBaseLimitOrder {
struct Order {
address makerToken;
address takerToken;
uint160 makerAmount;
uint160 takerAmount;
address maker;
uint256 expiration;
uint256 salt;
}
event LimitOrderFilled(
address indexed maker,
address indexed taker,
bytes32 orderHash,
uint160 curTakerFillAmount,
uint160 curMakerFillAmount
);
function fillLimitOrder(
Order calldata order,
bytes memory signature,
uint160 takerFillAmount,
uint160 thresholdTakerAmount,
bytes memory takerInteraction
) external returns (uint160 curTakerFillAmount, uint160 curMakerFillAmount);
function cancelOrder(Order memory order, bytes memory signature) external;
function addWhiteList(address contractAddr) external;
function removeWhiteList(address contractAddr) external;
function changeFeeReceiver(address newFeeReceiver) external;
function changeFeeRate(uint160 feeRate) external;
}
文件 7 的 11:IStarBaseLimitOrderBot.sol
pragma solidity ^0.8.0;
interface IStarBaseLimitOrderBot {
struct SwapData {
address callSwapAddr;
bytes datas;
}
function fillStarBaseLimitOrder(
bytes memory callExternalData,
address takerToken,
uint256 minTakerTokenAmount
) external;
function doLimitOrderSwap(
uint256 curTakerFillAmount,
uint256 curMakerFillAmount,
address makerToken,
address takerToken,
address StarBaseRouteProxy,
SwapData calldata datas
) external;
}
文件 8 的 11:IStarBaseRouter.sol
pragma solidity ^0.8.4;
interface IStarBaseRouter {
function defiSwap(
uint amountIn,
uint amountOutMin,
address tokenIn,
address tokenOut,
address receiver,
address callSwapAddr,
bytes calldata datas
) external;
}
文件 9 的 11:InitializableOwnable.sol
pragma solidity ^0.8.4;
contract InitializableOwnable {
address public _OWNER_;
address public _NEW_OWNER_;
bool internal _INITIALIZED_;
event OwnershipTransferPrepared(address indexed previousOwner, address indexed newOwner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
modifier notInitialized() {
require(!_INITIALIZED_, "StarBase_INITIALIZED");
_;
}
modifier onlyOwner() {
require(msg.sender == _OWNER_, "NOT_OWNER");
_;
}
function initOwner(address newOwner) public notInitialized {
_INITIALIZED_ = true;
_OWNER_ = newOwner;
}
function transferOwnership(address newOwner) public onlyOwner {
emit OwnershipTransferPrepared(_OWNER_, newOwner);
_NEW_OWNER_ = newOwner;
}
function claimOwnership() public {
require(msg.sender == _NEW_OWNER_, "INVALID_CLAIM");
emit OwnershipTransferred(_OWNER_, _NEW_OWNER_);
_OWNER_ = _NEW_OWNER_;
_NEW_OWNER_ = address(0);
}
}
文件 10 的 11:SafeERC20.sol
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Address.sol";
import { IERC20 } from "../intf/IERC20.sol";
library SafeERC20 {
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 _callOptionalReturn(IERC20 token, bytes memory data) private {
require(Address.isContract(address(token)), "SafeERC20: call to non-contract");
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
文件 11 的 11:StarBaseLimitOrderBot.sol
pragma solidity ^0.8.4;
import { InitializableOwnable } from "./lib/InitializableOwnable.sol";
import { IERC20 } from "./intf/IERC20.sol";
import { SafeERC20 } from "./lib/SafeERC20.sol";
import { IStarBaseRouter } from "./intf/IStarBaseRouter.sol";
import { IStarBaseLimitOrderBot } from "./intf/IStarBaseLimitOrderBot.sol";
import { Common } from "./lib/Common.sol";
import { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { IStarBaseLimitOrder } from "./intf/IStarBaseLimitOrder.sol";
contract StarBaseLimitOrderBot is InitializableOwnable, IStarBaseLimitOrderBot {
using SafeERC20 for IERC20;
address public _StarBase_LIMIT_ORDER_;
address public _TOKEN_RECEIVER_;
mapping(address => bool) public isAdminListed;
event AddAdmin(address admin);
event RemoveAdmin(address admin);
event ChangeReceiver(address newReceiver);
event Fill(bytes, address, uint256);
event ChangeFeeRate(uint160 feeRate);
constructor(address owner, address tokenReceiver, address[] memory userAddr) {
Common._validateAddress(tokenReceiver);
Common._validateAddress(owner);
initOwner(owner);
_TOKEN_RECEIVER_ = tokenReceiver;
emit ChangeReceiver(tokenReceiver);
for (uint i = 0; i < userAddr.length; i++) {
isAdminListed[userAddr[i]] = true;
}
}
function fillStarBaseLimitOrder(
bytes memory callExternalData,
address takerToken,
uint256 minTakerTokenAmount
) external {
require(isAdminListed[msg.sender], "SLOB: ACCESS_DENIED");
Common._validateAddress(takerToken);
uint256 originTakerBalance = IERC20(takerToken).balanceOf(address(this));
(bool success, bytes memory data) = _StarBase_LIMIT_ORDER_.call(callExternalData);
if (!success) {
assembly {
revert(add(data, 32), mload(data))
}
}
uint256 leftTakerAmount = IERC20(takerToken).balanceOf(address(this)) - originTakerBalance;
require(leftTakerAmount >= minTakerTokenAmount, "SLOB: TAKER_AMOUNT_NOT_ENOUGH");
IERC20(takerToken).safeTransfer(_TOKEN_RECEIVER_, leftTakerAmount);
emit Fill(callExternalData, takerToken, minTakerTokenAmount);
}
function doLimitOrderSwap(
uint256 curTakerFillAmount,
uint256 curMakerFillAmount,
address makerToken,
address takerToken,
address StarBaseRouteProxy,
SwapData calldata datas
) external {
require(msg.sender == _StarBase_LIMIT_ORDER_, "SLOB: ACCESS_DENIED");
uint256 originTakerBalance = IERC20(takerToken).balanceOf(address(this));
_approve(IERC20(makerToken), StarBaseRouteProxy, curMakerFillAmount);
IStarBaseRouter(StarBaseRouteProxy).defiSwap(
curMakerFillAmount,
0,
makerToken,
takerToken,
address(this),
datas.callSwapAddr,
datas.datas
);
uint256 takerBalance = IERC20(takerToken).balanceOf(address(this));
uint256 returnTakerAmount = takerBalance - originTakerBalance;
require(returnTakerAmount >= curTakerFillAmount, "SLOB: SWAP_TAKER_AMOUNT_NOT_ENOUGH");
_approve(IERC20(takerToken), _StarBase_LIMIT_ORDER_, curTakerFillAmount);
}
function setLimitOrder(address StarBaseLimitOrder_) external onlyOwner {
require(
_checkIfContractSupportsInterface(StarBaseLimitOrder_, type(IStarBaseLimitOrder).interfaceId),
"SLOB: ADDRESS_DOES_NOT_IMPLEMENT_REQUIRED_METHODS"
);
_StarBase_LIMIT_ORDER_ = StarBaseLimitOrder_;
}
function addAdminList(address userAddr) external onlyOwner {
Common._validateAddress(userAddr);
isAdminListed[userAddr] = true;
emit AddAdmin(userAddr);
}
function removeAdminList(address userAddr) external onlyOwner {
Common._validateAddress(userAddr);
isAdminListed[userAddr] = false;
emit RemoveAdmin(userAddr);
}
function changeTokenReceiver(address newTokenReceiver) external onlyOwner {
Common._validateAddress(newTokenReceiver);
_TOKEN_RECEIVER_ = newTokenReceiver;
emit ChangeReceiver(newTokenReceiver);
}
function _checkIfContractSupportsInterface(address _contract, bytes4 interfaceId) internal view returns (bool) {
(bool success, bytes memory result) = _contract.staticcall(
abi.encodeWithSelector(ERC165.supportsInterface.selector, interfaceId)
);
if (success && result.length == 32) {
return abi.decode(result, (bool));
}
return false;
}
function supportsInterface(bytes4 interfaceId) external pure returns (bool) {
return interfaceId == type(IStarBaseLimitOrderBot).interfaceId;
}
function _approve(IERC20 token, address to, uint256 amount) internal {
uint256 allowance = token.allowance(address(this), to);
if (allowance < amount) {
if (allowance > 0) {
token.safeApprove(to, 0);
}
token.safeApprove(to, amount);
}
}
function version() external pure returns (uint256) {
return 101;
}
}
{
"compilationTarget": {
"src/StarBaseLimitOrderBot.sol": "StarBaseLimitOrderBot"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs",
"useLiteralContent": true
},
"optimizer": {
"enabled": false,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"tokenReceiver","type":"address"},{"internalType":"address[]","name":"userAddr","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"AddAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint160","name":"feeRate","type":"uint160"}],"name":"ChangeFeeRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newReceiver","type":"address"}],"name":"ChangeReceiver","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes","name":"","type":"bytes"},{"indexed":false,"internalType":"address","name":"","type":"address"},{"indexed":false,"internalType":"uint256","name":"","type":"uint256"}],"name":"Fill","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferPrepared","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"admin","type":"address"}],"name":"RemoveAdmin","type":"event"},{"inputs":[],"name":"_NEW_OWNER_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_OWNER_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_StarBase_LIMIT_ORDER_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_TOKEN_RECEIVER_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddr","type":"address"}],"name":"addAdminList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTokenReceiver","type":"address"}],"name":"changeTokenReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"curTakerFillAmount","type":"uint256"},{"internalType":"uint256","name":"curMakerFillAmount","type":"uint256"},{"internalType":"address","name":"makerToken","type":"address"},{"internalType":"address","name":"takerToken","type":"address"},{"internalType":"address","name":"StarBaseRouteProxy","type":"address"},{"components":[{"internalType":"address","name":"callSwapAddr","type":"address"},{"internalType":"bytes","name":"datas","type":"bytes"}],"internalType":"struct IStarBaseLimitOrderBot.SwapData","name":"datas","type":"tuple"}],"name":"doLimitOrderSwap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"callExternalData","type":"bytes"},{"internalType":"address","name":"takerToken","type":"address"},{"internalType":"uint256","name":"minTakerTokenAmount","type":"uint256"}],"name":"fillStarBaseLimitOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"initOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAdminListed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"userAddr","type":"address"}],"name":"removeAdminList","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"StarBaseLimitOrder_","type":"address"}],"name":"setLimitOrder","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"}]