Contract Source Code:
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
import './interfaces/ITwapPair.sol';
import './libraries/Reserves.sol';
import './TwapLPToken.sol';
import './libraries/Math.sol';
import './interfaces/IERC20.sol';
import './interfaces/ITwapFactory.sol';
import './interfaces/ITwapOracle.sol';
contract TwapPair is Reserves, TwapLPToken, ITwapPair {
using SafeMath for uint256;
uint256 private constant PRECISION = 10**18;
uint256 public override mintFee = 0;
uint256 public override burnFee = 0;
uint256 public override swapFee = 0;
uint256 public constant override MINIMUM_LIQUIDITY = 10**3;
bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)')));
address public immutable override factory;
address public override token0;
address public override token1;
address public override oracle;
address public override trader;
uint256 private unlocked = 1;
modifier lock() {
require(unlocked == 1, 'TP06');
unlocked = 0;
_;
unlocked = 1;
}
function isContract(address addr) private view returns (bool) {
uint256 size;
assembly {
size := extcodesize(addr)
}
return size > 0;
}
function setMintFee(uint256 fee) external override {
require(msg.sender == factory, 'TP00');
require(fee != mintFee, 'TP01');
mintFee = fee;
emit SetMintFee(fee);
}
function setBurnFee(uint256 fee) external override {
require(msg.sender == factory, 'TP00');
require(fee != burnFee, 'TP01');
burnFee = fee;
emit SetBurnFee(fee);
}
function setSwapFee(uint256 fee) external override {
require(msg.sender == factory, 'TP00');
require(fee != swapFee, 'TP01');
swapFee = fee;
emit SetSwapFee(fee);
}
function setOracle(address _oracle) external override {
require(msg.sender == factory, 'TP00');
require(_oracle != oracle, 'TP01');
require(_oracle != address(0), 'TP02');
require(isContract(_oracle), 'TP1D');
oracle = _oracle;
emit SetOracle(_oracle);
}
function setTrader(address _trader) external override {
require(msg.sender == factory, 'TP00');
require(_trader != trader, 'TP01');
// Allow trader to be set as address(0) to disable interaction
trader = _trader;
emit SetTrader(_trader);
}
function collect(address to) external override lock {
require(msg.sender == factory, 'TP00');
require(to != address(0), 'TP02');
(uint256 fee0, uint256 fee1) = getFees();
if (fee0 > 0) _safeTransfer(token0, to, fee0);
if (fee1 > 0) _safeTransfer(token1, to, fee1);
setFees(0, 0);
_sync();
}
function _safeTransfer(
address token,
address to,
uint256 value
) private {
(bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value));
require(success && (data.length == 0 || abi.decode(data, (bool))), 'TP05');
}
function canTrade(address user) private view returns (bool) {
return user == trader || user == factory;
}
constructor() {
factory = msg.sender;
}
// called once by the factory at time of deployment
function initialize(
address _token0,
address _token1,
address _oracle,
address _trader
) external override {
require(msg.sender == factory, 'TP00');
require(_oracle != address(0), 'TP02');
require(isContract(_oracle), 'TP1D');
require(isContract(_token0) && isContract(_token1), 'TP10');
token0 = _token0;
token1 = _token1;
oracle = _oracle;
trader = _trader;
}
// this low-level function should be called from a contract which performs important safety checks
function mint(address to) external override lock returns (uint256 liquidityOut) {
require(canTrade(msg.sender), 'TP0C');
require(to != address(0), 'TP02');
(uint112 reserve0, uint112 reserve1) = getReserves();
(uint256 balance0, uint256 balance1) = getBalances(token0, token1);
uint256 amount0In = balance0.sub(reserve0);
uint256 amount1In = balance1.sub(reserve1);
uint256 _totalSupply = totalSupply; // gas savings
if (_totalSupply == 0) {
liquidityOut = Math.sqrt(amount0In.mul(amount1In)).sub(MINIMUM_LIQUIDITY);
_mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
} else {
liquidityOut = Math.min(amount0In.mul(_totalSupply) / reserve0, amount1In.mul(_totalSupply) / reserve1);
}
require(liquidityOut > 0, 'TP38');
if (mintFee > 0) {
uint256 fee = liquidityOut.mul(mintFee).div(PRECISION);
liquidityOut = liquidityOut.sub(fee);
_mint(factory, fee);
}
_mint(to, liquidityOut);
setReserves(balance0, balance1);
emit Mint(msg.sender, amount0In, amount1In, liquidityOut, to);
}
// this low-level function should be called from a contract which performs important safety checks
function burn(address to) external override lock returns (uint256 amount0Out, uint256 amount1Out) {
require(canTrade(msg.sender), 'TP0C');
require(to != address(0), 'TP02');
uint256 _totalSupply = totalSupply; // gas savings
require(_totalSupply > 0, 'TP36');
address _token0 = token0; // gas savings
address _token1 = token1; // gas savings
(uint256 balance0, uint256 balance1) = getBalances(token0, token1);
uint256 liquidityIn = balanceOf[address(this)];
if (msg.sender != factory && burnFee > 0) {
uint256 fee = liquidityIn.mul(burnFee).div(PRECISION);
liquidityIn = liquidityIn.sub(fee);
_transfer(address(this), factory, fee);
}
_burn(address(this), liquidityIn);
amount0Out = liquidityIn.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution
amount1Out = liquidityIn.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution
require(amount0Out > 0 && amount1Out > 0, 'TP39');
_safeTransfer(_token0, to, amount0Out);
_safeTransfer(_token1, to, amount1Out);
(balance0, balance1) = getBalances(token0, token1);
setReserves(balance0, balance1);
emit Burn(msg.sender, amount0Out, amount1Out, liquidityIn, to);
}
// this low-level function should be called from a contract which performs important safety checks
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external override lock {
require(canTrade(msg.sender), 'TP0C');
require(to != address(0), 'TP02');
require((amount0Out > 0 && amount1Out == 0) || (amount1Out > 0 && amount0Out == 0), 'TP31');
(uint112 _reserve0, uint112 _reserve1) = getReserves();
require(amount0Out < _reserve0 && amount1Out < _reserve1, 'TP07');
{
// scope for _token{0,1}, avoids stack too deep errors
address _token0 = token0;
address _token1 = token1;
require(to != _token0 && to != _token1, 'TP2D');
if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens
if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens
}
(uint256 balance0, uint256 balance1) = getBalances(token0, token1);
if (amount0Out > 0) {
// trading token1 for token0
require(balance1 > _reserve1, 'TP08');
uint256 amount1In = balance1 - _reserve1;
emit Swap(msg.sender, 0, amount1In, amount0Out, 0, to);
uint256 fee1 = amount1In.mul(swapFee).div(PRECISION);
uint256 balance1After = balance1.sub(fee1);
uint256 balance0After = ITwapOracle(oracle).tradeY(balance1After, _reserve0, _reserve1, data);
require(balance0 >= balance0After, 'TP2E');
uint256 fee0 = balance0.sub(balance0After);
addFees(fee0, fee1);
setReserves(balance0After, balance1After);
} else {
// trading token0 for token1
require(balance0 > _reserve0, 'TP08');
uint256 amount0In = balance0 - _reserve0;
emit Swap(msg.sender, amount0In, 0, 0, amount1Out, to);
uint256 fee0 = amount0In.mul(swapFee).div(PRECISION);
uint256 balance0After = balance0.sub(fee0);
uint256 balance1After = ITwapOracle(oracle).tradeX(balance0After, _reserve0, _reserve1, data);
require(balance1 >= balance1After, 'TP2E');
uint256 fee1 = balance1.sub(balance1After);
addFees(fee0, fee1);
setReserves(balance0After, balance1After);
}
}
function sync() external override lock {
require(canTrade(msg.sender), 'TP0C');
_sync();
}
// force reserves to match balances
function _sync() internal {
syncReserves(token0, token1);
uint256 tokens = balanceOf[address(this)];
if (tokens > 0) {
_transfer(address(this), factory, tokens);
}
}
function getSwapAmount0In(uint256 amount1Out, bytes calldata data)
public
view
override
returns (uint256 swapAmount0In)
{
(uint112 reserve0, uint112 reserve1) = getReserves();
uint256 balance1After = uint256(reserve1).sub(amount1Out);
uint256 balance0After = ITwapOracle(oracle).tradeY(balance1After, reserve0, reserve1, data);
return balance0After.sub(uint256(reserve0)).mul(PRECISION).ceil_div(PRECISION.sub(swapFee));
}
function getSwapAmount1In(uint256 amount0Out, bytes calldata data)
public
view
override
returns (uint256 swapAmount1In)
{
(uint112 reserve0, uint112 reserve1) = getReserves();
uint256 balance0After = uint256(reserve0).sub(amount0Out);
uint256 balance1After = ITwapOracle(oracle).tradeX(balance0After, reserve0, reserve1, data);
return balance1After.add(1).sub(uint256(reserve1)).mul(PRECISION).ceil_div(PRECISION.sub(swapFee));
}
function getSwapAmount0Out(uint256 amount1In, bytes calldata data)
public
view
override
returns (uint256 swapAmount0Out)
{
(uint112 reserve0, uint112 reserve1) = getReserves();
uint256 fee = amount1In.mul(swapFee).div(PRECISION);
uint256 balance0After = ITwapOracle(oracle).tradeY(
uint256(reserve1).add(amount1In).sub(fee),
reserve0,
reserve1,
data
);
return uint256(reserve0).sub(balance0After);
}
function getSwapAmount1Out(uint256 amount0In, bytes calldata data)
public
view
override
returns (uint256 swapAmount1Out)
{
(uint112 reserve0, uint112 reserve1) = getReserves();
uint256 fee = amount0In.mul(swapFee).div(PRECISION);
uint256 balance1After = ITwapOracle(oracle).tradeX(
uint256(reserve0).add(amount0In).sub(fee),
reserve0,
reserve1,
data
);
return uint256(reserve1).sub(balance1After);
}
function getDepositAmount0In(uint256 amount0, bytes calldata data) external view override returns (uint256) {
(uint112 reserve0, uint112 reserve1) = getReserves();
return ITwapOracle(oracle).depositTradeXIn(amount0, reserve0, reserve1, data);
}
function getDepositAmount1In(uint256 amount1, bytes calldata data) external view override returns (uint256) {
(uint112 reserve0, uint112 reserve1) = getReserves();
return ITwapOracle(oracle).depositTradeYIn(amount1, reserve0, reserve1, data);
}
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
import './ITwapERC20.sol';
import './IReserves.sol';
interface ITwapPair is ITwapERC20, IReserves {
event Mint(address indexed sender, uint256 amount0In, uint256 amount1In, uint256 liquidityOut, address indexed to);
event Burn(address indexed sender, uint256 amount0Out, uint256 amount1Out, uint256 liquidityIn, address indexed to);
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
event SetMintFee(uint256 fee);
event SetBurnFee(uint256 fee);
event SetSwapFee(uint256 fee);
event SetOracle(address account);
event SetTrader(address trader);
function MINIMUM_LIQUIDITY() external pure returns (uint256);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function oracle() external view returns (address);
function trader() external view returns (address);
function mintFee() external view returns (uint256);
function setMintFee(uint256 fee) external;
function mint(address to) external returns (uint256 liquidity);
function burnFee() external view returns (uint256);
function setBurnFee(uint256 fee) external;
function burn(address to) external returns (uint256 amount0, uint256 amount1);
function swapFee() external view returns (uint256);
function setSwapFee(uint256 fee) external;
function setOracle(address account) external;
function setTrader(address account) external;
function collect(address to) external;
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external;
function sync() external;
function initialize(
address _token0,
address _token1,
address _oracle,
address _trader
) external;
function getSwapAmount0In(uint256 amount1Out, bytes calldata data) external view returns (uint256 swapAmount0In);
function getSwapAmount1In(uint256 amount0Out, bytes calldata data) external view returns (uint256 swapAmount1In);
function getSwapAmount0Out(uint256 amount1In, bytes calldata data) external view returns (uint256 swapAmount0Out);
function getSwapAmount1Out(uint256 amount0In, bytes calldata data) external view returns (uint256 swapAmount1Out);
function getDepositAmount0In(uint256 amount0, bytes calldata data) external view returns (uint256 depositAmount0In);
function getDepositAmount1In(uint256 amount1, bytes calldata data) external view returns (uint256 depositAmount1In);
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
import '../interfaces/IReserves.sol';
import '../interfaces/IERC20.sol';
import '../libraries/SafeMath.sol';
contract Reserves is IReserves {
using SafeMath for uint256;
uint112 private reserve0;
uint112 private reserve1;
uint112 private fee0;
uint112 private fee1;
function getReserves() public view override returns (uint112, uint112) {
return (reserve0, reserve1);
}
function setReserves(uint256 balance0MinusFee, uint256 balance1MinusFee) internal {
require(balance0MinusFee != 0 && balance1MinusFee != 0, 'RS09');
reserve0 = balance0MinusFee.toUint112();
reserve1 = balance1MinusFee.toUint112();
}
function syncReserves(address token0, address token1) internal {
uint256 balance0 = IERC20(token0).balanceOf(address(this));
uint256 balance1 = IERC20(token1).balanceOf(address(this));
uint256 oldBalance0 = uint256(reserve0) + fee0;
uint256 oldBalance1 = uint256(reserve1) + fee1;
if (balance0 != oldBalance0 || balance1 != oldBalance1) {
if (oldBalance0 != 0) {
fee0 = (balance0.mul(fee0).div(oldBalance0)).toUint112();
}
if (oldBalance1 != 0) {
fee1 = (balance1.mul(fee1).div(oldBalance1)).toUint112();
}
setReserves(balance0.sub(fee0), balance1.sub(fee1));
}
}
function getFees() public view override returns (uint256, uint256) {
return (fee0, fee1);
}
function addFees(uint256 _fee0, uint256 _fee1) internal {
setFees(_fee0.add(fee0), _fee1.add(fee1));
}
function setFees(uint256 _fee0, uint256 _fee1) internal {
fee0 = _fee0.toUint112();
fee1 = _fee1.toUint112();
}
function getBalances(address token0, address token1) internal returns (uint256, uint256) {
uint256 balance0 = IERC20(token0).balanceOf(address(this));
uint256 balance1 = IERC20(token1).balanceOf(address(this));
if (fee0 > balance0) {
fee0 = uint112(balance0);
}
if (fee1 > balance1) {
fee1 = uint112(balance1);
}
return (balance0.sub(fee0), balance1.sub(fee1));
}
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
import './libraries/AbstractERC20.sol';
contract TwapLPToken is AbstractERC20 {
constructor() {
name = 'Twap LP';
symbol = 'TWAP-LP';
decimals = 18;
}
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
// a library for performing various math operations
library Math {
function min(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x < y ? x : y;
}
function max(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = x > y ? x : y;
}
// babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
function sqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
interface IERC20 {
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function decimals() external view returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool);
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
interface ITwapFactory {
event PairCreated(address indexed token0, address indexed token1, address pair, uint256);
event OwnerSet(address owner);
function owner() external view returns (address);
function getPair(address tokenA, address tokenB) external view returns (address pair);
function allPairs(uint256) external view returns (address pair);
function allPairsLength() external view returns (uint256);
function createPair(
address tokenA,
address tokenB,
address oracle,
address trader
) external returns (address pair);
function setOwner(address) external;
function setMintFee(
address tokenA,
address tokenB,
uint256 fee
) external;
function setBurnFee(
address tokenA,
address tokenB,
uint256 fee
) external;
function setSwapFee(
address tokenA,
address tokenB,
uint256 fee
) external;
function setOracle(
address tokenA,
address tokenB,
address oracle
) external;
function setTrader(
address tokenA,
address tokenB,
address trader
) external;
function collect(
address tokenA,
address tokenB,
address to
) external;
function withdraw(
address tokenA,
address tokenB,
uint256 amount,
address to
) external;
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
interface ITwapOracle {
event OwnerSet(address owner);
event UniswapPairSet(address uniswapPair);
function decimalsConverter() external view returns (int256);
function xDecimals() external view returns (uint8);
function yDecimals() external view returns (uint8);
function owner() external view returns (address);
function uniswapPair() external view returns (address);
function getPriceInfo() external view returns (uint256 priceAccumulator, uint32 priceTimestamp);
function getSpotPrice() external view returns (uint256);
function getAveragePrice(uint256 priceAccumulator, uint32 priceTimestamp) external view returns (uint256);
function setOwner(address _owner) external;
function setUniswapPair(address _uniswapPair) external;
function tradeX(
uint256 xAfter,
uint256 xBefore,
uint256 yBefore,
bytes calldata data
) external view returns (uint256 yAfter);
function tradeY(
uint256 yAfter,
uint256 yBefore,
uint256 xBefore,
bytes calldata data
) external view returns (uint256 xAfter);
function depositTradeXIn(
uint256 xLeft,
uint256 xBefore,
uint256 yBefore,
bytes calldata data
) external view returns (uint256 xIn);
function depositTradeYIn(
uint256 yLeft,
uint256 yBefore,
uint256 xBefore,
bytes calldata data
) external view returns (uint256 yIn);
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
import './IERC20.sol';
interface ITwapERC20 is IERC20 {
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint256);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
interface IReserves {
function getReserves() external view returns (uint112 reserve0, uint112 reserve1);
function getFees() external view returns (uint256 fee0, uint256 fee1);
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
// a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math)
library SafeMath {
int256 private constant _INT256_MIN = -2**255;
function add(uint256 x, uint256 y) internal pure returns (uint256 z) {
require((z = x + y) >= x, 'SM4E');
}
function sub(uint256 x, uint256 y) internal pure returns (uint256 z) {
z = sub(x, y, 'SM12');
}
function sub(
uint256 x,
uint256 y,
string memory message
) internal pure returns (uint256 z) {
require((z = x - y) <= x, message);
}
function mul(uint256 x, uint256 y) internal pure returns (uint256 z) {
require(y == 0 || (z = x * y) / y == x, 'SM2A');
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, 'SM43');
uint256 c = a / b;
return c;
}
function ceil_div(uint256 a, uint256 b) internal pure returns (uint256 c) {
c = div(a, b);
if (c == mul(a, b)) {
return c;
} else {
return add(c, 1);
}
}
function toUint32(uint256 n) internal pure returns (uint32) {
require(n <= type(uint32).max, 'SM50');
return uint32(n);
}
function toUint112(uint256 n) internal pure returns (uint112) {
require(n <= type(uint112).max, 'SM51');
return uint112(n);
}
function toInt256(uint256 unsigned) internal pure returns (int256 signed) {
require(unsigned <= uint256(type(int256).max), 'SM34');
signed = int256(unsigned);
}
// int256
function add(int256 a, int256 b) internal pure returns (int256) {
int256 c = a + b;
require((b >= 0 && c >= a) || (b < 0 && c < a), 'SM4D');
return c;
}
function sub(int256 a, int256 b) internal pure returns (int256) {
int256 c = a - b;
require((b >= 0 && c <= a) || (b < 0 && c > a), 'SM11');
return c;
}
function mul(int256 a, int256 b) internal pure returns (int256) {
// 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;
}
require(!(a == -1 && b == _INT256_MIN), 'SM29');
int256 c = a * b;
require(c / a == b, 'SM29');
return c;
}
function div(int256 a, int256 b) internal pure returns (int256) {
require(b != 0, 'SM43');
require(!(b == -1 && a == _INT256_MIN), 'SM42');
int256 c = a / b;
return c;
}
}
// SPDX-License-Identifier: GPL-3.0-or-later
// Deployed with donations via Gitcoin GR9
pragma solidity 0.7.6;
import '../interfaces/ITwapERC20.sol';
import './SafeMath.sol';
abstract contract AbstractERC20 is ITwapERC20 {
using SafeMath for uint256;
string public override name;
string public override symbol;
uint8 public override decimals;
uint256 public override totalSupply;
mapping(address => uint256) public override balanceOf;
mapping(address => mapping(address => uint256)) public override allowance;
bytes32 public constant DOMAIN_TYPEHASH =
keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)');
// keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
bytes32 public constant override PERMIT_TYPEHASH =
0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;
mapping(address => uint256) public override nonces;
function _mint(address to, uint256 value) internal {
totalSupply = totalSupply.add(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(address(0), to, value);
}
function _burn(address from, uint256 value) internal {
balanceOf[from] = balanceOf[from].sub(value);
totalSupply = totalSupply.sub(value);
emit Transfer(from, address(0), value);
}
function _approve(
address owner,
address spender,
uint256 value
) internal {
allowance[owner][spender] = value;
emit Approval(owner, spender, value);
}
function _transfer(
address from,
address to,
uint256 value
) internal {
balanceOf[from] = balanceOf[from].sub(value);
balanceOf[to] = balanceOf[to].add(value);
emit Transfer(from, to, value);
}
function approve(address spender, uint256 value) external override returns (bool) {
_approve(msg.sender, spender, value);
return true;
}
function increaseAllowance(address spender, uint256 addedValue) external override returns (bool) {
_approve(msg.sender, spender, allowance[msg.sender][spender].add(addedValue));
return true;
}
function decreaseAllowance(address spender, uint256 subtractedValue) external override returns (bool) {
uint256 currentAllowance = allowance[msg.sender][spender];
require(currentAllowance >= subtractedValue, 'TA48');
_approve(msg.sender, spender, currentAllowance.sub(subtractedValue));
return true;
}
function transfer(address to, uint256 value) external override returns (bool) {
_transfer(msg.sender, to, value);
return true;
}
function transferFrom(
address from,
address to,
uint256 value
) external override returns (bool) {
if (allowance[from][msg.sender] != uint256(-1)) {
allowance[from][msg.sender] = allowance[from][msg.sender].sub(value);
}
_transfer(from, to, value);
return true;
}
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external override {
require(deadline >= block.timestamp, 'TA04');
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
getDomainSeparator(),
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'TA2F');
_approve(owner, spender, value);
}
function getDomainSeparator() public view returns (bytes32) {
uint256 chainId;
assembly {
chainId := chainid()
}
return
keccak256(
abi.encode(DOMAIN_TYPEHASH, keccak256(bytes(name)), keccak256(bytes('1')), chainId, address(this))
);
}
}