Skip to content

Instantly share code, notes, and snippets.

@staccDOTsol
Created December 12, 2022 00:54
Show Gist options
  • Save staccDOTsol/66ea050851ecb47ce9613f30ae6271ba to your computer and use it in GitHub Desktop.
Save staccDOTsol/66ea050851ecb47ce9613f30ae6271ba to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.8.17+commit.8df45f5f.js&optimize=true&runs=9999999&gist=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2ERC20.sol';
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol';
import "@uniswap/v2-periphery/contracts/interfaces/IUniswapV2Router02.sol";
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol';
import "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
contract Token is Initializable, ERC20Upgradeable, ERC20BurnableUpgradeable, OwnableUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
// _disableInitializers();
}
Pool borg;
uint256 public price;
function initialize(string memory _name, string memory _ticker, uint256 _price, address _pool) initializer public {
__ERC20_init(_name, _ticker);
__ERC20Burnable_init();
__Ownable_init();
price = _price;
borg = Pool(_pool);
}
function setPrice(uint256 _newPrice) public onlyOwner {
price = _newPrice;
}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
function burn(address who, uint256 amount) public onlyOwner {
_burn(who, amount);
payable(address(owner())).call{value:borg.getPrice(amount, address(this))}("");
}
}
contract Pool is Initializable, OwnableUpgradeable {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(address _router, address _factory) {
// matic uni mainnet
// quickswap matic mainnet 0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff, 0x5757371414417b8C6CAad45bAeF941aBc7d3Ab32
// matic sushi 0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F, 0xC0AEe478e3658e2610c5F7A4A2E1777cE9e4f2Ac
// matic uni 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D, 0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f
uniswap = IUniswapV2Router02(_router);
fac = IUniswapV2Factory(_factory);
// _disableInitializers();
}
ERC20 public underlying;
ERC20 public stable;
Token public tokenA;
Token public tokenB;
address public tokenAUni;
address public tokenBUni;
address public underlyingUSDCUni;
IUniswapV2Factory fac;
IUniswapV2Router02 public uniswap;
// calculate price based on pair reserves
// calculate price based on pair reserves
// calculate price based on pair reserves
function getTokenPrice(address pairAddress, uint amount) public view returns(uint)
{
IUniswapV2Pair pair = IUniswapV2Pair(pairAddress);
ERC20 token1 = ERC20(pair.token1());
(uint Res0, uint Res1,) = pair.getReserves();
// decimals
uint res0 = Res0*(10**underlying.decimals());
return((amount*res0)/Res1); // return amount of token0 needed to buy token1
}
//
//Long, L, Short, S, 0xe06bd4f5aac8d0aa337d13ec88db6defc6eaeefe, 0xc2132d05d31c914a87c6611c10748aeb04b58e8f
function initialize(
string memory _name1,
string memory _ticker1,
string memory _name2,
string memory _ticker2,
address _underlying,
address _stable)
initializer public {
tokenA = new Token();
tokenB = new Token();
stable = ERC20(_stable);
underlying = ERC20(_underlying);
//old price both tokenA tokenB
// 391632 // moar cuz fees
// old price underlying
// 387755
// tick is permissionless, however every burn/mint calls tick too
// last tick timestamp 1670803494
// new tick timetamp
//
// new price underlying
// // annoying lol
// new price tokenA
//
//new price tokenB
//
underlyingUSDCUni = fac.getPair(_stable, _underlying);
lastTick = getTokenPrice(underlyingUSDCUni, 1);
tokenA.initialize(_name1, _ticker1, lastTick , address(this));
tokenB.initialize(_name2, _ticker2, lastTick , address(this));
tokenBUni = fac.createPair(address(tokenB), address(underlying));
tokenAUni = fac.createPair(address(tokenA), address(underlying));
lastTickTime = block.timestamp;
nextDay = lastTickTime + aDay;
}
function getPrice(uint256 amount, address which) public view returns (uint256) {
Token token = Token(which);
return token.price() * 10 ** (18-stable.decimals()) * amount * 101/100;
}
function mintEth(address to, address which) public payable {
Token token = Token(which);
tick();
token.mint(to, getPrice(msg.value, address(token)));
token.mint(address(this), msg.value/95 );
token.approve(address(uniswap), msg.value/95);
uniswap.addLiquidityETH{ value: msg.value/95 }(
which,
msg.value/95,
0,
0,
payable(address(this)),
block.timestamp + 10000
);
payable(address(token)).call{value: msg.value/100*95}("");
}
function burn(address who, uint256 amount, address which) public payable {
require(msg.value > (amount / 100), "Not enough value");
Token token = Token(which);
require(token.balanceOf(msg.sender) >= amount, "cannot burn nothing");
tick();
token.burn(who, amount);
}
uint256 public lastTickTime;
uint256 public lastTick;
uint256 aDay = 1000 * 60 * 5;
uint256 public nextDay;
function tick() public returns (uint256) {
uint256 price = getTokenPrice(underlyingUSDCUni, 1);
uint256 diff;
if (lastTick > price){
diff = price ** 2 / lastTick ** 2;
uint256 newPriceA = tokenA.price() / (diff ** 2);
tokenA.setPrice(newPriceA);
uint256 newPriceB = tokenB.price() * (diff ** 2);
tokenB.setPrice(newPriceB);
}
else if (lastTick < price){
diff = price ** 2 / lastTick ** 2;
uint256 newPriceA = tokenA.price() * (diff ** 2);
tokenA.setPrice(newPriceA);
uint256 newPriceB = tokenB.price() / (diff ** 2);
tokenB.setPrice(newPriceB);
}//1000000000000000000 / 2000
lastTick = getTokenPrice(underlyingUSDCUni, 1);
lastTickTime = block.timestamp;
if (lastTickTime > nextDay){
if (tokenA.totalSupply() > tokenB.totalSupply()){
// 1100 / 1000 1.1
uint256 diff = ( tokenA.totalSupply() / tokenB.totalSupply() - 1 ) / 4;
diff = diff * tokenA.totalSupply();
(, uint256 ethOut) = uniswap.removeLiquidityETH(
address(tokenA),
diff,
0,
0,//686255206000
msg.sender,
block.timestamp + 10000
);//6879752360000000000000
address[] memory path = new address[](2);
path[0] = uniswap.WETH();
path[1] = address(tokenB);
uniswap.swapExactETHForTokensSupportingFeeOnTransferTokens{ value: ethOut }(0,
path,
payable(address(this)),
0
);
Token(tokenB).burn(address(this), Token(tokenB).balanceOf(address(this)) / 100 * 99);
}
else if (tokenB.totalSupply() > tokenA.totalSupply()){
uint256 diff = ( tokenB.totalSupply() / tokenA.totalSupply() - 1 ) / 4;
diff = diff * tokenB.totalSupply();
(, uint256 ethOut) = uniswap.removeLiquidityETH(
address(tokenB),
diff,
0,
0,
msg.sender,
block.timestamp + 10000
);
address[] memory path = new address[](2);
path[0] = uniswap.WETH();
path[1] = address(tokenA);
uniswap.swapExactETHForTokensSupportingFeeOnTransferTokens{ value: ethOut }(0,
path,
payable(address(this)),
0
);
Token(tokenA).burn(address(this), Token(tokenA).balanceOf(address(this)) / 100 * 99);
}
address which = address(tokenA);
uint256 liq;
if (which == address(tokenA)){
liq = IUniswapV2ERC20(tokenAUni).balanceOf(address(this)) / 100;
}
else if (which == address(tokenB)){
liq = IUniswapV2ERC20(tokenBUni).balanceOf(address(this)) / 100;
}
(uint256 tokensOut, uint256 ethOut) = uniswap.removeLiquidityETH(
which,
liq,
0,
0,
msg.sender,
block.timestamp + 10000
);
uniswap.addLiquidityETH{ value: ethOut }(
which,
0,
0,
0,
payable(address(this)),
block.timestamp + 10000
);
payable(msg.sender).call{value:ethOut}("");
tokenA.burn(address(this), tokenA.balanceOf(address(this)));
which = address(tokenB);
if (which == address(tokenA)){
liq = IUniswapV2ERC20(tokenAUni).balanceOf(address(this)) / 100;
}
else if (which == address(tokenB)){
liq = IUniswapV2ERC20(tokenBUni).balanceOf(address(this)) / 100;
}
( tokensOut, ethOut) = uniswap.removeLiquidityETH(
which,
liq,
0,
0,
msg.sender,
block.timestamp + 10000
);
uniswap.addLiquidityETH{ value: ethOut }(
which,
0,
0,
0,
payable(address(this)),
block.timestamp + 10000
);
payable(msg.sender).call{value:ethOut}("");
tokenB.burn(address(this), tokenB.balanceOf(address(this)));
nextDay = block.timestamp;
}
return diff;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment