编译器
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:IStarBaseDCA.sol
pragma solidity ^0.8.0;
interface IStarBaseDCA {
struct Order {
uint160 cycleSecondsApart;
uint160 numberOfTrade;
address inputToken;
address outputToken;
address maker;
uint160 inAmount;
uint256 minOutAmountPerCycle;
uint256 maxOutAmountPerCycle;
uint256 expiration;
uint256 salt;
}
function fillDCA(
Order memory order,
bytes memory signature,
bytes memory takerInteraction
) external returns (uint256 curTakerFillAmount);
function cancelOrder(Order memory order, bytes memory signature) external;
}
文件 7 的 11:IStarBaseDCABot.sol
pragma solidity ^0.8.0;
interface IStarBaseDCABot {
function fillStarBaseDCA(bytes memory callExternalData, address outputToken, uint256 minOutputTokenAmount) 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:StarBaseDCABot.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 { ERC165 } from "@openzeppelin/contracts/utils/introspection/ERC165.sol";
import { Common } from "./lib/Common.sol";
import { IStarBaseDCA } from "./intf/IStarBaseDCA.sol";
import { IStarBaseDCABot } from "./intf/IStarBaseDCABot.sol";
contract StarBaseDCABot is InitializableOwnable, ERC165 {
using SafeERC20 for IERC20;
address public _StarBase_DCA_;
address public _TOKEN_RECEIVER_;
mapping(address => bool) public isAdminListed;
address public _Setup_Tool_;
event AddAdmin(address indexed admin);
event RemoveAdmin(address indexed admin);
event ChangeReceiver(address indexed newReceiver);
event Fill(bytes, address, uint256);
struct SwapData {
address callSwapAddr;
bytes datas;
}
constructor(address owner, address tokenReceiver, address[] memory userAddr) {
Common._validateAddress(owner);
Common._validateAddress(tokenReceiver);
initOwner(owner);
_TOKEN_RECEIVER_ = tokenReceiver;
emit ChangeReceiver(_TOKEN_RECEIVER_);
for (uint i = 0; i < userAddr.length; i++) {
isAdminListed[userAddr[i]] = true;
emit AddAdmin(userAddr[i]);
}
}
function fillStarBaseDCA(
bytes memory callExternalData,
address outputToken,
uint256 minOutputTokenAmount
) external {
require(isAdminListed[msg.sender], "SDCAB: ACCESS_DENIED");
Common._validateAddress(outputToken);
uint256 originTakerBalance = IERC20(outputToken).balanceOf(address(this));
(bool success, bytes memory data) = _StarBase_DCA_.call(callExternalData);
if (!success) {
assembly {
revert(add(data, 32), mload(data))
}
}
uint256 leftTakerAmount = IERC20(outputToken).balanceOf(address(this)) - originTakerBalance;
require(leftTakerAmount >= minOutputTokenAmount, "SDCAB: TAKER_AMOUNT_NOT_ENOUGH");
IERC20(outputToken).safeTransfer(_TOKEN_RECEIVER_, leftTakerAmount);
emit Fill(callExternalData, outputToken, minOutputTokenAmount);
}
function doDCASwap(
uint256 inAmount,
uint256 minOutAmount,
uint256 maxOutAmount,
address inputToken,
address outputToken,
address StarBaseRouteProxy,
SwapData calldata datas
) external returns (uint256 returnTakerAmount) {
Common._validateAddress(inputToken);
Common._validateAddress(outputToken);
Common._validateAddress(StarBaseRouteProxy);
require(msg.sender == _StarBase_DCA_, "SDCAB: ACCESS_DENIED");
uint256 originTakerBalance = IERC20(outputToken).balanceOf(address(this));
_approve(IERC20(inputToken), StarBaseRouteProxy, inAmount);
IStarBaseRouter(StarBaseRouteProxy).defiSwap(
inAmount,
minOutAmount,
inputToken,
outputToken,
address(this),
datas.callSwapAddr,
datas.datas
);
returnTakerAmount = IERC20(outputToken).balanceOf(address(this)) - originTakerBalance;
require(returnTakerAmount >= minOutAmount, "SDCAB: SWAP_TAKER_AMOUNT_NOT_ENOUGH");
if (returnTakerAmount > maxOutAmount) {
returnTakerAmount = maxOutAmount;
}
_approve(IERC20(outputToken), _StarBase_DCA_, returnTakerAmount);
}
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) public pure override(ERC165) returns (bool) {
return interfaceId == type(IStarBaseDCABot).interfaceId;
}
function setDcaContract(address StarBaseDCA) external onlyOwner {
require(
_checkIfContractSupportsInterface(StarBaseDCA, type(IStarBaseDCA).interfaceId),
"SLOP: ADDRESS_DOES_NOT_IMPLEMENT_REQUIRED_METHODS"
);
_StarBase_DCA_ = StarBaseDCA;
}
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 _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/StarBaseDCABot.sol": "StarBaseDCABot"
},
"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":true,"internalType":"address","name":"admin","type":"address"}],"name":"AddAdmin","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"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":true,"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":"_Setup_Tool_","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_StarBase_DCA_","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":"inAmount","type":"uint256"},{"internalType":"uint256","name":"minOutAmount","type":"uint256"},{"internalType":"uint256","name":"maxOutAmount","type":"uint256"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"StarBaseRouteProxy","type":"address"},{"components":[{"internalType":"address","name":"callSwapAddr","type":"address"},{"internalType":"bytes","name":"datas","type":"bytes"}],"internalType":"struct StarBaseDCABot.SwapData","name":"datas","type":"tuple"}],"name":"doDCASwap","outputs":[{"internalType":"uint256","name":"returnTakerAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"callExternalData","type":"bytes"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"uint256","name":"minOutputTokenAmount","type":"uint256"}],"name":"fillStarBaseDCA","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":"StarBaseDCA","type":"address"}],"name":"setDcaContract","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"}]