Contract Name:
FlashArbitrageCOREBuyer
Contract Source Code:
File 1 of 1 : FlashArbitrageCOREBuyer
// _________ ________ _____________________
// \_ ___ \ \_____ \\______ \_ _____/
// / \ \/ / | \| _/| __)_
// \ \____/ | \ | \| \
// \______ /\_______ /____|_ /_______ /
// \/ \/ \/ \/
// ___________.____ _____ _________ ___ ___
// \_ _____/| | / _ \ / _____// | \
// | __) | | / /_\ \ \_____ \/ ~ \
// | \ | |___/ | \/ \ Y /
// \___ / |_______ \____|__ /_______ /\___|_ /
// \/ \/ \/ \/ \/
// _____ ____________________.________________________ _____ ___________________
// / _ \\______ \______ \ \__ ___/\______ \ / _ \ / _____/\_ _____/
// / /_\ \| _/| | _/ | | | | _/ / /_\ \/ \ ___ | __)_
// / | \ | \| | \ | | | | | \/ | \ \_\ \| \
// \____|__ /____|_ /|______ /___| |____| |____|_ /\____|__ /\______ /_______ /
// \/ \/ \/ \/ \/ \/ \/
// CORE BUYER
//
// This contract buys CORE for tokens inside it (which it gets from the controller upon successfull arbitrage)
// And then sends it to the farming vault boosting everyones APY
//
// Become impossible to ignore.
//
// Sources flattened with hardhat v2.0.1 https://hardhat.org
// File @uniswap/v2-core/contracts/interfaces/[email protected]
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint value);
event Transfer(address indexed from, address indexed to, uint value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint);
function balanceOf(address owner) external view returns (uint);
function allowance(address owner, address spender) external view returns (uint);
function approve(address spender, uint value) external returns (bool);
function transfer(address to, uint value) external returns (bool);
function transferFrom(address from, address to, uint value) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint);
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
event Mint(address indexed sender, uint amount0, uint amount1);
event Burn(address indexed sender, uint amount0, uint amount1, address indexed to);
event Swap(
address indexed sender,
uint amount0In,
uint amount1In,
uint amount0Out,
uint amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
function price0CumulativeLast() external view returns (uint);
function price1CumulativeLast() external view returns (uint);
function kLast() external view returns (uint);
function mint(address to) external returns (uint liquidity);
function burn(address to) external returns (uint amount0, uint amount1);
function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}
// File @uniswap/lib/contracts/libraries/[email protected]
pragma solidity >=0.5.0;
library AddressStringUtil {
// converts an address to the uppercase hex string, extracting only len bytes (up to 20, multiple of 2)
function toAsciiString(address addr, uint len) pure internal returns (string memory) {
require(len % 2 == 0 && len > 0 && len <= 40, "AddressStringUtil: INVALID_LEN");
bytes memory s = new bytes(len);
uint addrNum = uint(addr);
for (uint i = 0; i < len / 2; i++) {
// shift right and truncate all but the least significant byte to extract the byte at position 19-i
uint8 b = uint8(addrNum >> (8 * (19 - i)));
// first hex character is the most significant 4 bits
uint8 hi = b >> 4;
// second hex character is the least significant 4 bits
uint8 lo = b - (hi << 4);
s[2 * i] = char(hi);
s[2 * i + 1] = char(lo);
}
return string(s);
}
// hi and lo are only 4 bits and between 0 and 16
// this method converts those values to the unicode/ascii code point for the hex representation
// uses upper case for the characters
function char(uint8 b) pure private returns (byte c) {
if (b < 10) {
return byte(b + 0x30);
} else {
return byte(b + 0x37);
}
}
}
// File @uniswap/lib/contracts/libraries/[email protected]
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.5.0;
// produces token descriptors from inconsistent or absent ERC20 symbol implementations that can return string or bytes32
// this library will always produce a string symbol to represent the token
library SafeERC20Namer {
function bytes32ToString(bytes32 x) pure private returns (string memory) {
bytes memory bytesString = new bytes(32);
uint charCount = 0;
for (uint j = 0; j < 32; j++) {
byte char = x[j];
if (char != 0) {
bytesString[charCount] = char;
charCount++;
}
}
bytes memory bytesStringTrimmed = new bytes(charCount);
for (uint j = 0; j < charCount; j++) {
bytesStringTrimmed[j] = bytesString[j];
}
return string(bytesStringTrimmed);
}
// assumes the data is in position 2
function parseStringData(bytes memory b) pure private returns (string memory) {
uint charCount = 0;
// first parse the charCount out of the data
for (uint i = 32; i < 64; i++) {
charCount <<= 8;
charCount += uint8(b[i]);
}
bytes memory bytesStringTrimmed = new bytes(charCount);
for (uint i = 0; i < charCount; i++) {
bytesStringTrimmed[i] = b[i + 64];
}
return string(bytesStringTrimmed);
}
// uses a heuristic to produce a token name from the address
// the heuristic returns the full hex of the address string in upper case
function addressToName(address token) pure private returns (string memory) {
return AddressStringUtil.toAsciiString(token, 40);
}
// uses a heuristic to produce a token symbol from the address
// the heuristic returns the first 6 hex of the address string in upper case
function addressToSymbol(address token) pure private returns (string memory) {
return AddressStringUtil.toAsciiString(token, 6);
}
// calls an external view token contract method that returns a symbol or name, and parses the output into a string
function callAndParseStringReturn(address token, bytes4 selector) view private 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 "";
}
// attempts to extract the token symbol. if it does not implement symbol, returns a symbol derived from the address
function tokenSymbol(address token) internal view returns (string memory) {
// 0x95d89b41 = bytes4(keccak256("symbol()"))
string memory symbol = callAndParseStringReturn(token, 0x95d89b41);
if (bytes(symbol).length == 0) {
// fallback to 6 uppercase hex of address
return addressToSymbol(token);
}
return symbol;
}
// attempts to extract the token name. if it does not implement name, returns a name derived from the address
function tokenName(address token) internal view returns (string memory) {
// 0x06fdde03 = bytes4(keccak256("name()"))
string memory name = callAndParseStringReturn(token, 0x06fdde03);
if (bytes(name).length == 0) {
// fallback to full hex of address
return addressToName(token);
}
return name;
}
}
// File @uniswap/v2-core/contracts/interfaces/[email protected]
pragma solidity >=0.5.0;
interface IUniswapV2Factory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint);
function feeTo() external view returns (address);
function feeToSetter() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint) external view returns (address pair);
function allPairsLength() external view returns (uint);
function createPair(address tokenA, address tokenB) external returns (address pair);
function setFeeTo(address) external;
function setFeeToSetter(address) external;
}
// File contracts/v612/ICOREGlobals.sol
// COPYRIGHT cVault.finance TEAM
// NO COPY
// COPY = BAD
// This code is provided with no assurances or guarantees of any kind. Use at your own responsibility.
interface ICOREGlobals {
function CORETokenAddress() external view returns (address);
function COREGlobalsAddress() external view returns (address);
function COREDelegatorAddress() external view returns (address);
function COREVaultAddress() external returns (address);
function COREWETHUniPair() external view returns (address);
function UniswapFactory() external view returns (address);
function TransferHandler() external view returns (address);
function addDelegatorStateChangePermission(address that, bool status) external;
function isStateChangeApprovedContract(address that) external view returns (bool);
}
// File @openzeppelin/contracts-ethereum-package/contracts/token/ERC20/[email protected]
pragma solidity ^0.6.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
// File @openzeppelin/contracts-ethereum-package/contracts/math/[email protected]
pragma solidity ^0.6.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return sub(a, b, "SafeMath: subtraction overflow");
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return div(a, b, "SafeMath: division by zero");
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, errorMessage);
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return mod(a, b, "SafeMath: modulo by zero");
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts with custom message when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b != 0, errorMessage);
return a % b;
}
}
// File @openzeppelin/contracts/GSN/[email protected]
pragma solidity ^0.6.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
// File @openzeppelin/contracts/access/[email protected]
pragma solidity ^0.6.0;
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(_owner == _msgSender(), "Ownable: caller is not the owner");
_;
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
// File contracts/v612/FlashArbitrageCOREBuyer.sol
pragma solidity 0.6.12;
pragma experimental ABIEncoderV2;
// import "hardhat/console.sol";
interface ICOREVault {
function addPendingRewards(uint256 _) external;
}
contract FlashArbitrageCOREBuyer is Ownable {
using SafeMath for uint256;
event COREBought(uint256 amount);
mapping(address => bool) supportedPair;
IERC20 public immutable CORE;
address public immutable wETH;
ICOREVault public immutable coreVault;
IUniswapV2Factory public immutable uniswapFactory;
address public immutable CORExWETHPair;
constructor (address _coreGlobals) public {
ICOREGlobals globals = ICOREGlobals(_coreGlobals);
CORE = IERC20(globals.CORETokenAddress());
uniswapFactory = IUniswapV2Factory(globals.UniswapFactory());
coreVault = ICOREVault(globals.COREVaultAddress());
CORExWETHPair = globals.COREWETHUniPair();
wETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;
supportedPair[globals.COREWETHUniPair()] = true;
supportedPair[0x6fad7D44640c5cd0120DEeC0301e8cf850BecB68] = true; // CORE/cBTC
}
function buyAndGiveOutCOREForToken(address _token) public {
// We check if this token is CORE token if it is we just send it out
if(_token == address(CORE)) {
// return breaks out no need to else..else..
return sendCOREToVault();
}
uint256 balInputToken = IERC20(_token).balanceOf(address(this));
address pairWithCORE = uniswapFactory.getPair(_token, address(CORE));
// We check if there is a pair for CORE token with that token
if(pairWithCORE != address(0) && supportedPair[pairWithCORE]){ // we check supported pair so people don't make 1 liquidity pair iwth CORE
// It mens we have a pair with CORE
// So we should just swap with it
//Suport FoT tokens
uint256 amountOut = swapSupportingFeeOnTransfertokens(_token, pairWithCORE, balInputToken);
emit COREBought(amountOut);
return sendCOREToVault();
}
// This is the case we are not finding a pair with CORE so we try to find one with wETH
address pairWithWETH = uniswapFactory.getPair(_token, wETH);
if(pairWithWETH != address(0)) {
uint256 amountOut = swapSupportingFeeOnTransfertokens(_token, pairWithWETH, balInputToken);
amountOut = swapSupportingFeeOnTransfertokens(wETH, CORExWETHPair, amountOut);
emit COREBought(amountOut);
sendCOREToVault();
}
else {
revert("FA COREBuyer : Unsupported token");
}
}
function swapSupportingFeeOnTransfertokens(address _inputToken, address _pair, uint256 amountIn) internal returns (uint256 amountOut) {
IUniswapV2Pair pair = IUniswapV2Pair(_pair);
// We check the balance before
uint256 balanceOfTargetTokenUniBefore = IERC20(_inputToken).balanceOf(_pair);
// Then transfers
safeTransfer(_inputToken, _pair, amountIn);
// And check it again to get the delta
// This is to support fee on tranfer tokens
uint256 balanceOfTargetTokenUniAfter = IERC20(_inputToken).balanceOf(_pair);
bool token0Out = pair.token1() == _inputToken;
(uint256 reserve0, uint256 reserve1,) = pair.getReserves();
// console.log("balanceOfTargetTokenUniBefore", balanceOfTargetTokenUniBefore);
// console.log("balanceOfTargetTokenUniAfter", balanceOfTargetTokenUniAfter);
if(token0Out) {
amountOut = getAmountOut(
balanceOfTargetTokenUniAfter - balanceOfTargetTokenUniBefore,
reserve1,
reserve0
);
// console.log("amountOut",amountOut);
pair.swap(amountOut,0, address(this), "");
}
else {
amountOut = getAmountOut(
balanceOfTargetTokenUniAfter - balanceOfTargetTokenUniBefore,
reserve0,
reserve1
);
pair.swap(0,amountOut, address(this), "");
}
}
function sendCOREToVault() internal {
uint256 balanceCORE = CORE.balanceOf(address(this));
CORE.transfer(address(coreVault), balanceCORE);
coreVault.addPendingRewards(0);
}
function addSupportedPair(address _pair, bool _shouldBeSupported) onlyOwner public {
supportedPair[_pair] = _shouldBeSupported;
}
function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) internal pure returns (uint256 amountOut) {
require(amountIn > 0, 'UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT');
require(reserveIn > 0 && reserveOut > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
uint amountInWithFee = amountIn.mul(997);
uint numerator = amountInWithFee.mul(reserveOut);
uint denominator = reserveIn.mul(1000).add(amountInWithFee);
amountOut = numerator / denominator;
}
///////////////////
//// Helper functions
//////////////////
function sendETH(address payable to, uint256 amt) internal {
// console.log("I'm transfering ETH", amt/1e18, to);
// throw exception on failure
to.transfer(amt);
}
function safeTransfer(address token, address to, uint256 value) internal {
// bytes4(keccak256(bytes('transfer(address,uint256)')));
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'FA Controller: TRANSFER_FAILED');
}
// A function that lets owner remove any tokens from this addrss
// note this address shoudn't hold any tokens
// And if it does that means someting already went wrong or someone send them to this address
function rescueUnsupportedTokens(address token, uint256 amt) public onlyOwner {
IERC20(token).transfer(owner(), amt);
}
function rescueETH(uint256 amt) public {
sendETH(0xd5b47B80668840e7164C1D1d81aF8a9d9727B421, amt);
}
}