Created
March 10, 2022 14:44
-
-
Save htkcodes/da568c1fc2d2a8d988b0e24c3ec149a3 to your computer and use it in GitHub Desktop.
-
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: MIT | |
pragma solidity >=0.8.0; | |
interface IWETH { | |
function approve(address guy, uint256 wad) external returns (bool); | |
function transferFrom( | |
address src, | |
address dst, | |
uint256 wad | |
) external returns (bool); | |
function withdraw(uint256 wad) external; | |
function balanceOf(address) external view returns (uint256); | |
function symbol() external view returns (string memory); | |
function transfer(address dst, uint256 wad) external returns (bool); | |
function deposit() external payable; | |
function allowance(address, address) external view returns (uint256); | |
} | |
interface IERC20 { | |
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); | |
event Transfer(address indexed from, address indexed to, uint256 value); | |
event Approval( | |
address indexed owner, | |
address indexed spender, | |
uint256 value | |
); | |
} | |
library SafeMath { | |
function add(uint256 x, uint256 y) internal pure returns (uint256 z) { | |
require((z = x + y) >= x, "ds-math-add-overflow"); | |
} | |
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) { | |
require((z = x - y) <= x, "ds-math-sub-underflow"); | |
} | |
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) { | |
require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow"); | |
} | |
} | |
interface ChiToken { | |
function mint(uint256 value) external; | |
function freeFromUpTo(address from, uint256 value) external; | |
} | |
interface IPancakePair { | |
event Transfer(address indexed from, address indexed to, uint256 value); | |
function getReserves() | |
external | |
view | |
returns ( | |
uint112 reserve0, | |
uint112 reserve1, | |
uint32 blockTimestampLast | |
); | |
function swap( | |
uint256 amount0Out, | |
uint256 amount1Out, | |
address to, | |
bytes calldata data | |
) external; | |
} | |
library PancakeLibrary { | |
using SafeMath for uint256; | |
// returns sorted token addresses, used to handle return values from pairs sorted in this order | |
function sortTokens(address tokenA, address tokenB) | |
internal | |
pure | |
returns (address token0, address token1) | |
{ | |
require(tokenA != tokenB, "Library Sort: IDENTICAL_ADDRESSES"); | |
(token0, token1) = tokenA < tokenB | |
? (tokenA, tokenB) | |
: (tokenB, tokenA); | |
require(token0 != address(0), "Library Sort: ZERO_ADDRESS"); | |
} | |
// fetches and sorts the reserves for a pair | |
function getReserves( | |
address pairAddress, | |
address tokenA, | |
address tokenB | |
) internal view returns (uint256 reserveA, uint256 reserveB) { | |
(address token0, ) = sortTokens(tokenA, tokenB); | |
(uint256 reserve0, uint256 reserve1, ) = IPancakePair(pairAddress) | |
.getReserves(); | |
(reserveA, reserveB) = tokenA == token0 | |
? (reserve0, reserve1) | |
: (reserve1, reserve0); | |
} | |
//for use with single swap | |
// given an input amount of an asset and pair reserves, returns the maximum output amount of the other asset | |
function getAmountOut( | |
uint256 amountIn, | |
uint256 reserveIn, | |
uint256 reserveOut | |
) internal pure returns (uint256 amountOut) { | |
require(amountIn > 0, "Library: INSUFFICIENT_INPUT_AMOUNT"); | |
require( | |
reserveIn > 0 && reserveOut > 0, | |
"Library: INSUFFICIENT_LIQUIDITY" | |
); | |
uint256 amountInWithFee = amountIn.mul(9975); | |
uint256 numerator = amountInWithFee.mul(reserveOut); | |
uint256 denominator = reserveIn.mul(10000).add(amountInWithFee); | |
amountOut = numerator / denominator; | |
} | |
} | |
library gasOptimized { | |
/*/////////////////////////////////////////////////////////////// | |
IERC20 OPERATIONS | |
//////////////////////////////////////////////////////////////*/ | |
function didLastOptionalReturnCallSucceed(bool callStatus) | |
private | |
pure | |
returns (bool success) | |
{ | |
assembly { | |
// Get how many bytes the call returned. | |
let returnDataSize := returndatasize() | |
// If the call reverted: | |
if iszero(callStatus) { | |
// Copy the revert message into memory. | |
returndatacopy(0, 0, returnDataSize) | |
// Revert with the same message. | |
revert(0, returnDataSize) | |
} | |
switch returnDataSize | |
case 32 { | |
// Copy the return data into memory. | |
returndatacopy(0, 0, returnDataSize) | |
// Set success to whether it returned true. | |
success := iszero(iszero(mload(0))) | |
} | |
case 0 { | |
// There was no return data. | |
success := 1 | |
} | |
default { | |
// It returned some malformed input. | |
success := 0 | |
} | |
} | |
} | |
function safeTransferFrom( | |
IERC20 token, | |
address from, | |
address to, | |
uint256 amount | |
) internal { | |
bool callStatus; | |
assembly { | |
// Get a pointer to some free memory. | |
let freeMemoryPointer := mload(0x40) | |
// Write the abi-encoded calldata to memory piece by piece: | |
mstore( | |
freeMemoryPointer, | |
0x23b872dd00000000000000000000000000000000000000000000000000000000 | |
) // Begin with the function selector. | |
mstore( | |
add(freeMemoryPointer, 4), | |
and(from, 0xffffffffffffffffffffffffffffffffffffffff) | |
) // Mask and append the "from" argument. | |
mstore( | |
add(freeMemoryPointer, 36), | |
and(to, 0xffffffffffffffffffffffffffffffffffffffff) | |
) // Mask and append the "to" argument. | |
mstore(add(freeMemoryPointer, 68), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. | |
// Call the token and store if it succeeded or not. | |
// We use 100 because the calldata length is 4 + 32 * 3. | |
callStatus := call(gas(), token, 0, freeMemoryPointer, 100, 0, 0) | |
} | |
require( | |
didLastOptionalReturnCallSucceed(callStatus), | |
"TRANSFER_FROM_FAILED" | |
); | |
} | |
function safeTransfer( | |
IERC20 token, | |
address to, | |
uint256 amount | |
) internal { | |
bool callStatus; | |
assembly { | |
// Get a pointer to some free memory. | |
let freeMemoryPointer := mload(0x40) | |
// Write the abi-encoded calldata to memory piece by piece: | |
mstore( | |
freeMemoryPointer, | |
0xa9059cbb00000000000000000000000000000000000000000000000000000000 | |
) // Begin with the function selector. | |
mstore( | |
add(freeMemoryPointer, 4), | |
and(to, 0xffffffffffffffffffffffffffffffffffffffff) | |
) // Mask and append the "to" argument. | |
mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value. | |
// Call the token and store if it succeeded or not. | |
// We use 68 because the calldata length is 4 + 32 * 2. | |
callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0) | |
} | |
require( | |
didLastOptionalReturnCallSucceed(callStatus), | |
"TRANSFER_FAILED" | |
); | |
} | |
} | |
contract proxy { | |
ChiToken private constant CHI = | |
ChiToken(0x0000000000004946c0e9F43F4Dee607b0eF1fA1c); | |
address private constant WETH = 0xae13d989daC2f0dEbFf460aC112a837C89BAa7cd; | |
mapping(address => bool) internal authorized; | |
uint256 constant MAX_UINT = 2**256 - 1; | |
modifier discountCHI() { | |
uint256 gasStart = gasleft(); | |
_; | |
uint256 gasSpent = 21000 + gasStart - gasleft() + 16 * msg.data.length; | |
CHI.freeFromUpTo(address(this), (gasSpent + 14154) / 41947); | |
} | |
address payable owner; | |
event Received(address sender, uint256 amount); | |
constructor() { | |
owner = payable(msg.sender); | |
authorized[owner] = true; | |
} | |
modifier onlyOwner() { | |
require(msg.sender == owner, "y tho?"); | |
_; | |
} | |
modifier isAuthorized() { | |
require(isAuth(msg.sender), "bye"); | |
_; | |
} | |
function isAuth(address addr) public view returns (bool) { | |
return authorized[addr]; | |
} | |
function addAuth(address[] calldata addr) public onlyOwner { | |
for (uint256 i = 0; i < addr.length; i++) { | |
authorized[addr[i]] = true; | |
} | |
} | |
function removeAuth(address[] calldata addr) public onlyOwner { | |
for (uint256 i = 0; i < addr.length; i++) { | |
authorized[addr[i]] = false; | |
} | |
} | |
function mintCHI(uint256 value) external { | |
CHI.mint(value); | |
} | |
receive() external payable { | |
emit Received(msg.sender, msg.value); | |
} | |
function _swapSupportingFeeOnTransferTokens( | |
address[] memory path, | |
address tokenPair, | |
address _to | |
) internal virtual { | |
(address input, address output) = (path[0], path[1]); | |
(address token0, ) = PancakeLibrary.sortTokens(input, output); | |
IPancakePair pair = IPancakePair(tokenPair); | |
uint256 amountInput; | |
uint256 amountOutput; | |
(uint256 reserve0, uint256 reserve1, ) = pair.getReserves(); | |
(uint256 reserveInput, uint256 reserveOutput) = input == token0 | |
? (reserve0, reserve1) | |
: (reserve1, reserve0); | |
amountInput = IERC20(input).balanceOf(address(pair)) - reserveInput; | |
amountOutput = PancakeLibrary.getAmountOut( | |
amountInput, | |
reserveInput, | |
reserveOutput | |
); | |
(uint256 amount0Out, uint256 amount1Out) = input == token0 | |
? (uint256(0), amountOutput) | |
: (amountOutput, uint256(0)); | |
address to = _to; | |
pair.swap(amount0Out, amount1Out, to, new bytes(0)); | |
} | |
function ss( | |
//Buys and sends to wallet | |
uint256 _tokenAmount, //Balance of cost 8k gas better to send balance | |
address pair, | |
address token, | |
bool tax, | |
uint8 order | |
) external payable isAuthorized { | |
IERC20 iWETH = IERC20(WETH); | |
if (iWETH.allowance(address(this), address(this)) < MAX_UINT) { | |
require(iWETH.approve(address(this), MAX_UINT), "F.A"); | |
} | |
require(order == 0 || order == 1,'OOO?'); // 1 to buy Token with WETH, 0 to sell token for WETH | |
address[] memory path = new address[](2); | |
address who = msg.sender; | |
if (order == 0) { | |
path[0] = token; | |
path[1] = WETH; | |
} else { | |
path[1] = token; | |
path[0] = WETH; | |
} | |
if (tax) { | |
gasOptimized.safeTransferFrom( | |
IERC20(path[0]), | |
who, | |
pair, | |
_tokenAmount | |
); | |
_swapSupportingFeeOnTransferTokens(path, pair, who); | |
} else { | |
(uint256 reserveA, uint256 reserveB) = PancakeLibrary.getReserves( | |
pair, | |
path[0], | |
path[1] | |
); | |
uint256 amountOut = PancakeLibrary.getAmountOut( | |
_tokenAmount, | |
reserveA, | |
reserveB | |
); | |
gasOptimized.safeTransferFrom( | |
IERC20(path[0]), | |
who, | |
pair, | |
_tokenAmount | |
); | |
(address input, address output) = (path[0], path[1]); | |
(address token0, ) = PancakeLibrary.sortTokens(input, output); | |
(uint256 amount0Out, uint256 amount1Out) = input == token0 | |
? (uint256(0), amountOut) | |
: (amountOut, uint256(0)); | |
IPancakePair(pair).swap( | |
amount0Out, | |
amount1Out, | |
who, | |
new bytes(0) | |
); | |
} | |
} | |
function ssc( | |
//Buys and sends to wallet | |
uint256 _tokenAmount, //Balance of cost 8k gas better to send balance | |
address pair, | |
address token, | |
bool tax, | |
uint8 order | |
) external payable isAuthorized discountCHI { | |
IERC20 iWETH = IERC20(WETH); | |
if (iWETH.allowance(address(this), address(this)) < MAX_UINT) { | |
require(iWETH.approve(address(this), MAX_UINT), "F.A"); | |
} | |
require(order == 0 || order == 1,'OOO?'); // 1 to buy Token with WETH, 0 to sell token for WETH | |
address[] memory path = new address[](2); | |
address who = msg.sender; | |
if (order == 0) { | |
path[0] = token; | |
path[1] = WETH; | |
} else { | |
path[1] = token; | |
path[0] = WETH; | |
} | |
if (tax) { | |
gasOptimized.safeTransferFrom( | |
IERC20(path[0]), | |
who, | |
pair, | |
_tokenAmount | |
); | |
_swapSupportingFeeOnTransferTokens(path, pair, who); | |
} else { | |
(uint256 reserveA, uint256 reserveB) = PancakeLibrary.getReserves( | |
pair, | |
path[0], | |
path[1] | |
); | |
uint256 amountOut = PancakeLibrary.getAmountOut( | |
_tokenAmount, | |
reserveA, | |
reserveB | |
); | |
gasOptimized.safeTransferFrom( | |
IERC20(path[0]), | |
who, | |
pair, | |
_tokenAmount | |
); | |
(address input, address output) = (path[0], path[1]); | |
(address token0, ) = PancakeLibrary.sortTokens(input, output); | |
(uint256 amount0Out, uint256 amount1Out) = input == token0 | |
? (uint256(0), amountOut) | |
: (amountOut, uint256(0)); | |
IPancakePair(pair).swap( | |
amount0Out, | |
amount1Out, | |
who, | |
new bytes(0) | |
); | |
} | |
} | |
function changeOwner(address payable _newOwner) external onlyOwner { | |
owner = _newOwner; | |
} | |
function withdrawETH(uint256 _amount) external onlyOwner { | |
require(_amount <= address(this).balance, "AMOUNT_EXEEDS_BALANCE"); | |
payable(owner).transfer(_amount); | |
} | |
function withdrawToken(address _token, uint256 _amount) external onlyOwner { | |
require( | |
_amount <= IERC20(_token).balanceOf(address(this)), | |
"AMOUNT_EXEEDS_BALANCE" | |
); | |
IERC20(_token).transfer(owner, _amount); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment