Skip to content

Instantly share code, notes, and snippets.

@htkcodes
Created March 10, 2022 14:44
Show Gist options
  • Save htkcodes/da568c1fc2d2a8d988b0e24c3ec149a3 to your computer and use it in GitHub Desktop.
Save htkcodes/da568c1fc2d2a8d988b0e24c3ec149a3 to your computer and use it in GitHub Desktop.
-
// 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