Created
December 12, 2022 00:54
-
-
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=
This file contains hidden or 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.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