Transaction Hash:
Block:
18317405 at Oct-10-2023 03:35:11 AM +UTC
Transaction Fee:
0.001762008 ETH
$4.28
Gas Used:
146,834 Gas / 12 Gwei
Emitted Events:
122 |
SaitaRealtyV2.Transfer( from=[Sender] 0x955bdf890048c3ef31cb966a05172fac6ecee025, to=0x75e89d5979E4f6Fba9F97c104c2F0AFB3F1dcB88, value=4318645707500000 )
|
123 |
SaitaRealtyV2.Transfer( from=[Sender] 0x955bdf890048c3ef31cb966a05172fac6ecee025, to=[Receiver] SaitaRealtyV2, value=227297142500000 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x142a774E...5acB646D0 | |||||
0x95222290...5CC4BAfe5
Miner
| (beaverbuild) | 9.11843528692171196 Eth | 9.119440018462865794 Eth | 0.001004731541153834 | |
0x955bdf89...C6ECEe025 |
0.0125 Eth
Nonce: 77
|
0.010737992 Eth
Nonce: 78
| 0.001762008 |
Execution Trace
SaitaRealtyV2.transfer( recipient=0x75e89d5979E4f6Fba9F97c104c2F0AFB3F1dcB88, amount=4545942850000000 ) => ( True )

-
SaitaSwapRouter.STATICCALL( )
SaitaSwapRouter.getAmountsOut( amountIn=8202337318629023, path=[0x142a774E8b52550E88E196CedD7A5835acB646D0, 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2, 0xdAC17F958D2ee523a2206206994597C13D831ec7] ) => ( amounts=[8202337318629023, 754965955492352244, 655673520] )
-
SaitaSwapPair.STATICCALL( )
-
SaitaSwapPair.STATICCALL( )
-
transfer[SaitaRealtyV2 (ln:192)]
_transfer[SaitaRealtyV2 (ln:193)]
balanceOf[SaitaRealtyV2 (ln:383)]
tokenFromReflection[SaitaRealtyV2 (ln:190)]
_getRate[SaitaRealtyV2 (ln:225)]
_getCurrentSupply[SaitaRealtyV2 (ln:359)]
_tokenTransfer[SaitaRealtyV2 (ln:393)]
_getValues[SaitaRealtyV2 (ln:413)]
_getTValues[SaitaRealtyV2 (ln:307)]
_getRValues[SaitaRealtyV2 (ln:308)]
_getRate[SaitaRealtyV2 (ln:308)]
_getCurrentSupply[SaitaRealtyV2 (ln:359)]
_reflectReflection[SaitaRealtyV2 (ln:423)]
_takeTreasury[SaitaRealtyV2 (ln:425)]
_takeCapital[SaitaRealtyV2 (ln:428)]
Transfer[SaitaRealtyV2 (ln:429)]
_takeMarketing[SaitaRealtyV2 (ln:432)]
Transfer[SaitaRealtyV2 (ln:433)]
_takeBurn[SaitaRealtyV2 (ln:436)]
Transfer[SaitaRealtyV2 (ln:437)]
Transfer[SaitaRealtyV2 (ln:440)]
Transfer[SaitaRealtyV2 (ln:442)]
_tokenTransfer[SaitaRealtyV2 (ln:395)]
_getValues[SaitaRealtyV2 (ln:413)]
_getTValues[SaitaRealtyV2 (ln:307)]
_getRValues[SaitaRealtyV2 (ln:308)]
_getRate[SaitaRealtyV2 (ln:308)]
_getCurrentSupply[SaitaRealtyV2 (ln:359)]
_reflectReflection[SaitaRealtyV2 (ln:423)]
_takeTreasury[SaitaRealtyV2 (ln:425)]
_takeCapital[SaitaRealtyV2 (ln:428)]
Transfer[SaitaRealtyV2 (ln:429)]
_takeMarketing[SaitaRealtyV2 (ln:432)]
Transfer[SaitaRealtyV2 (ln:433)]
_takeBurn[SaitaRealtyV2 (ln:436)]
Transfer[SaitaRealtyV2 (ln:437)]
Transfer[SaitaRealtyV2 (ln:440)]
Transfer[SaitaRealtyV2 (ln:442)]
_tokenTransfer[SaitaRealtyV2 (ln:398)]
_getValues[SaitaRealtyV2 (ln:413)]
_getTValues[SaitaRealtyV2 (ln:307)]
_getRValues[SaitaRealtyV2 (ln:308)]
_getRate[SaitaRealtyV2 (ln:308)]
_getCurrentSupply[SaitaRealtyV2 (ln:359)]
_reflectReflection[SaitaRealtyV2 (ln:423)]
_takeTreasury[SaitaRealtyV2 (ln:425)]
_takeCapital[SaitaRealtyV2 (ln:428)]
Transfer[SaitaRealtyV2 (ln:429)]
_takeMarketing[SaitaRealtyV2 (ln:432)]
Transfer[SaitaRealtyV2 (ln:433)]
_takeBurn[SaitaRealtyV2 (ln:436)]
Transfer[SaitaRealtyV2 (ln:437)]
Transfer[SaitaRealtyV2 (ln:440)]
Transfer[SaitaRealtyV2 (ln:442)]
WETH[SaitaRealtyV2 (ln:405)]
getAmountsOut[SaitaRealtyV2 (ln:407)]
balanceOf[SaitaRealtyV2 (ln:407)]
tokenFromReflection[SaitaRealtyV2 (ln:190)]
_getRate[SaitaRealtyV2 (ln:225)]
_getCurrentSupply[SaitaRealtyV2 (ln:359)]
swapTokensForETH[SaitaRealtyV2 (ln:408)]
WETH[SaitaRealtyV2 (ln:449)]
_approve[SaitaRealtyV2 (ln:450)]
Approval[SaitaRealtyV2 (ln:377)]
swapExactTokensForETHSupportingFeeOnTransferTokens[SaitaRealtyV2 (ln:452)]
call[SaitaRealtyV2 (ln:459)]
call[SaitaRealtyV2 (ln:462)]
balanceOf[SaitaRealtyV2 (ln:408)]
tokenFromReflection[SaitaRealtyV2 (ln:190)]
_getRate[SaitaRealtyV2 (ln:225)]
_getCurrentSupply[SaitaRealtyV2 (ln:359)]
_msgSender[SaitaRealtyV2 (ln:193)]
File 1 of 4: SaitaRealtyV2
File 2 of 4: SaitaSwapRouter
File 3 of 4: SaitaSwapPair
File 4 of 4: SaitaSwapPair
// SPDX-License-Identifier: NOLICENSE pragma solidity ^0.8.10; interface IERC20 { function totalSupply() external view returns (uint256); 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); } abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } } abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); constructor() { _setOwner(_msgSender()); } function owner() public view virtual returns (address) { return _owner; } modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } function renounceOwnership() public virtual onlyOwner { _setOwner(address(0)); } function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _setOwner(newOwner); } function _setOwner(address newOwner) internal { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } } interface IFactory{ function createPair(address tokenA, address tokenB) external returns (address pair); } interface IRouter { function factory() external pure returns (address); function WETH() external pure returns (address); function addTreasuryETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint treasury); function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external; function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); } contract SaitaRealtyV2 is IERC20, Ownable { mapping(address => uint256) private _rOwned; mapping(address => uint256) private _tOwned; mapping(address => mapping(address => uint256)) private _allowances; mapping(address => bool) private _isExcludedFromFee; mapping(address => bool) private _isExcluded; mapping(address => bool) private _isBot; mapping(address => bool) private _isPair; address[] private _excluded; bool private swapping; IRouter public router; address public pair; uint8 private constant _decimals = 9; uint256 private constant MAX = ~uint256(0); uint256 private _tTotal = 12e10 * 10**_decimals; uint256 private _rTotal = (MAX - (MAX % _tTotal)); uint256 public swapTokensAtAmount = 1_000 * 10 ** 6; uint256 public maxTxAmount = 100_000_000_000 * 10**_decimals; // Anti Dump // mapping (address => uint256) public _lastTrade; bool public coolDownEnabled = true; uint256 public coolDownTime = 30 seconds; address public capitalAddress = 0x22D5c2837FFB86392C81D3Be0aDe307F81AF10C1; address public marketingAddress = 0x2084f438b1EFf6Bd5FbdE57215eaB741CAC7aDb7; address public burnAddress = 0x000000000000000000000000000000000000dEaD; address public USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; string private constant _name = "SaitaRealtyV2"; string private constant _symbol = "SRLTY"; struct Taxes { uint256 reflection; uint256 capital; uint256 marketing; uint256 burn; uint256 treasury; } Taxes private taxes = Taxes(10,10,10,10,50); struct TotFeesPaidStruct { uint256 reflection; uint256 capital; uint256 marketing; uint256 burn; uint256 treasury; } TotFeesPaidStruct public totFeesPaid; struct valuesFromGetValues{ uint256 rAmount; uint256 rTransferAmount; uint256 rReflection; uint256 rCapital; uint256 rMarketing; uint256 rBurn; uint256 rTreasury; uint256 tTransferAmount; uint256 tReflection; uint256 tCapital; uint256 tMarketing; uint256 tBurn; uint256 tTreasury; } struct splitETHStruct{ uint256 capital; uint256 marketing; } splitETHStruct private splitETH = splitETHStruct(40,10); struct ETHAmountStruct{ uint256 capital; uint256 marketing; } ETHAmountStruct public ETHAmount; event FeesChanged(); modifier lockTheSwap { swapping = true; _; swapping = false; } modifier addressValidation(address _addr) { require(_addr != address(0), 'SaitaRealty: Zero address'); _; } constructor (address routerAddress, address owner_) { IRouter _router = IRouter(routerAddress); address _pair = IFactory(_router.factory()) .createPair(address(this), _router.WETH()); router = _router; pair = _pair; addPair(pair); excludeFromReward(pair); _setOwner(owner_); _rOwned[owner()] = _rTotal; _isExcludedFromFee[owner()] = true; _isExcludedFromFee[address(this)] = true; _isExcludedFromFee[capitalAddress] = true; _isExcludedFromFee[burnAddress] = true; _isExcludedFromFee[marketingAddress] = true; emit Transfer(address(0), owner(), _tTotal); } function name() public pure returns (string memory) { return _name; } function symbol() public pure returns (string memory) { return _symbol; } function decimals() public pure returns (uint8) { return _decimals; } function totalSupply() public view override returns (uint256) { return _tTotal; } function balanceOf(address account) public view override returns (uint256) { if (_isExcluded[account]) return _tOwned[account]; return tokenFromReflection(_rOwned[account]); } function transfer(address recipient, uint256 amount) public override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } function allowance(address owner, address spender) public view override returns (uint256) { return _allowances[owner][spender]; } function approve(address spender, uint256 amount) public override returns (bool) { _approve(_msgSender(), spender, amount); return true; } function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { uint256 currentAllowance = _allowances[sender][_msgSender()]; require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance"); _transfer(sender, recipient, amount); _approve(sender, _msgSender(), currentAllowance - amount); return true; } function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue); return true; } function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { uint256 currentAllowance = _allowances[_msgSender()][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); _approve(_msgSender(), spender, currentAllowance - subtractedValue); return true; } function isExcludedFromReward(address account) public view returns (bool) { return _isExcluded[account]; } function tokenFromReflection(uint256 rAmount) public view returns(uint256) { require(rAmount <= _rTotal, "Amount must be less than total reflections"); uint256 currentRate = _getRate(); return rAmount/currentRate; } function excludeFromReward(address account) public onlyOwner { require(!_isExcluded[account], "Account is already excluded"); require(_excluded.length <= 200, "Invalid length"); require(account != owner(), "Owner cannot be excluded"); if(_rOwned[account] > 0) { _tOwned[account] = tokenFromReflection(_rOwned[account]); } _isExcluded[account] = true; _excluded.push(account); } function includeInReward(address account) external onlyOwner() { require(_isExcluded[account], "Account is not excluded"); for (uint256 i = 0; i < _excluded.length; i++) { if (_excluded[i] == account) { _excluded[i] = _excluded[_excluded.length - 1]; _tOwned[account] = 0; _isExcluded[account] = false; _excluded.pop(); break; } } } function excludeFromFee(address account) public onlyOwner { _isExcludedFromFee[account] = true; } function includeInFee(address account) public onlyOwner { _isExcludedFromFee[account] = false; } function isExcludedFromFee(address account) public view returns(bool) { return _isExcludedFromFee[account]; } function addPair(address _pair) public onlyOwner { _isPair[_pair] = true; } function removePair(address _pair) public onlyOwner { _isPair[_pair] = false; } function isPair(address account) public view returns(bool){ return _isPair[account]; } function setTaxes(uint256 _reflection, uint256 _capital, uint256 _marketing, uint256 _burn, uint256 _treasury) public onlyOwner { taxes.reflection = _reflection; taxes.capital = _capital; taxes.marketing = _marketing; taxes.burn = _burn; taxes.treasury = _treasury; emit FeesChanged(); } function setSplitETH(uint256 _capital, uint256 _marketing) public onlyOwner { splitETH.capital = _capital; splitETH.marketing = _marketing; emit FeesChanged(); } function _reflectReflection(uint256 rReflection, uint256 tReflection) private { _rTotal -=rReflection; totFeesPaid.reflection += tReflection; } function _takeTreasury(uint256 rTreasury, uint256 tTreasury) private { totFeesPaid.treasury += tTreasury; if(_isExcluded[address(this)]) _tOwned[address(this)] += tTreasury; _rOwned[address(this)] += rTreasury; } function _takeCapital(uint256 rCapital, uint256 tCapital) private { totFeesPaid.capital += tCapital; if(_isExcluded[capitalAddress]) _tOwned[capitalAddress] += tCapital; _rOwned[capitalAddress] +=rCapital; } function _takeMarketing(uint256 rMarketing, uint256 tMarketing) private{ totFeesPaid.marketing += tMarketing; if(_isExcluded[marketingAddress]) _tOwned[marketingAddress] += tMarketing; _rOwned[marketingAddress] += rMarketing; } function _takeBurn(uint256 rBurn, uint256 tBurn) private { totFeesPaid.burn += tBurn; if(_isExcluded[marketingAddress])_tOwned[burnAddress] += tBurn; _rOwned[burnAddress] += rBurn; } function _getValues(uint256 tAmount, uint8 takeFee) private returns (valuesFromGetValues memory to_return) { to_return = _getTValues(tAmount, takeFee); (to_return.rAmount, to_return.rTransferAmount, to_return.rReflection, to_return.rCapital,to_return.rMarketing, to_return.rBurn, to_return.rTreasury) = _getRValues(to_return, tAmount, takeFee, _getRate()); return to_return; } function _getTValues(uint256 tAmount, uint8 takeFee) private returns (valuesFromGetValues memory s) { if(takeFee == 0) { s.tTransferAmount = tAmount; return s; } else if(takeFee == 1){ s.tReflection = (tAmount*taxes.reflection)/1000; s.tCapital = (tAmount*taxes.capital)/1000; s.tMarketing = tAmount*taxes.marketing/1000; s.tBurn = tAmount*taxes.burn/1000; s.tTreasury = tAmount*taxes.treasury/1000; ETHAmount.capital += s.tTreasury*splitETH.capital/taxes.treasury; ETHAmount.marketing += s.tTreasury*splitETH.marketing/taxes.treasury; s.tTransferAmount = tAmount-s.tReflection-s.tCapital-s.tTreasury-s.tMarketing-s.tBurn; return s; } else { s.tReflection = tAmount*taxes.reflection/1000; s.tMarketing = tAmount*taxes.marketing/1000; s.tBurn = tAmount*taxes.burn/1000; s.tTreasury = tAmount*splitETH.marketing/1000; ETHAmount.marketing += s.tTreasury; s.tTransferAmount = tAmount-s.tReflection-s.tTreasury-s.tMarketing-s.tBurn; return s; } } function _getRValues(valuesFromGetValues memory s, uint256 tAmount, uint8 takeFee, uint256 currentRate) private pure returns (uint256 rAmount, uint256 rTransferAmount, uint256 rReflection,uint256 rCapital,uint256 rMarketing,uint256 rBurn,uint256 rTreasury) { rAmount = tAmount*currentRate; if(takeFee == 0) { return(rAmount, rAmount, 0,0,0,0,0); }else if(takeFee == 1){ rReflection = s.tReflection*currentRate; rCapital = s.tCapital*currentRate; rTreasury = s.tTreasury*currentRate; rMarketing = s.tMarketing*currentRate; rBurn = s.tBurn*currentRate; rTransferAmount = rAmount-rReflection-rCapital-rTreasury-rMarketing-rBurn; return (rAmount, rTransferAmount, rReflection,rCapital,rMarketing,rBurn,rTreasury); } else{ rReflection = s.tReflection*currentRate; rTreasury = s.tTreasury*currentRate; rMarketing = s.tMarketing*currentRate; rBurn = s.tBurn*currentRate; rTransferAmount = rAmount-rReflection-rTreasury-rMarketing-rBurn; return (rAmount, rTransferAmount, rReflection,0,rMarketing,rBurn,rTreasury); } } function _getRate() private view returns(uint256) { (uint256 rSupply, uint256 tSupply) = _getCurrentSupply(); return rSupply/tSupply; } function _getCurrentSupply() private view returns(uint256, uint256) { uint256 rSupply = _rTotal; uint256 tSupply = _tTotal; for (uint256 i = 0; i < _excluded.length; i++) { if (_rOwned[_excluded[i]] > rSupply || _tOwned[_excluded[i]] > tSupply) return (_rTotal, _tTotal); rSupply = rSupply-_rOwned[_excluded[i]]; tSupply = tSupply-_tOwned[_excluded[i]]; } if (rSupply < _rTotal/_tTotal) return (_rTotal, _tTotal); return (rSupply, tSupply); } function _approve(address owner, address spender, uint256 amount) private { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } function _transfer(address from, address to, uint256 amount) private { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); require(amount > 0, "Zero amount"); require(amount <= balanceOf(from),"Insufficient balance"); require(!_isBot[from] && !_isBot[to], "You are a bot"); require(amount <= maxTxAmount ,"Amount is exceeding maxTxAmount"); if (coolDownEnabled) { uint256 timePassed = block.timestamp - _lastTrade[from]; require(timePassed > coolDownTime, "You must wait coolDownTime"); } if(!_isExcludedFromFee[from] && !_isExcludedFromFee[to] && !swapping) {//check this !swapping if(_isPair[from] || _isPair[to]) { _tokenTransfer(from, to, amount, 1); } else { _tokenTransfer(from, to, amount, 2); } } else { _tokenTransfer(from, to, amount, 0); } _lastTrade[from] = block.timestamp; if(!swapping && from != pair && to != pair && !_isExcludedFromFee[from] && !_isExcludedFromFee[to]){ address[] memory path = new address[](3); path[0] = address(this); path[1] = router.WETH(); path[2] = USDT; uint _amount = router.getAmountsOut(balanceOf(address(this)), path)[2]; if(_amount >= swapTokensAtAmount) swapTokensForETH(balanceOf(address(this))); } } //this method is responsible for taking all fee, if takeFee is true function _tokenTransfer(address sender, address recipient, uint256 tAmount, uint8 takeFee) private { valuesFromGetValues memory s = _getValues(tAmount, takeFee); if (_isExcluded[sender] ) { //from excluded _tOwned[sender] = _tOwned[sender] - tAmount; } if (_isExcluded[recipient]) { //to excluded _tOwned[recipient] = _tOwned[recipient] + s.tTransferAmount; } _rOwned[sender] = _rOwned[sender]-s.rAmount; _rOwned[recipient] = _rOwned[recipient]+s.rTransferAmount; if(s.rReflection > 0 || s.tReflection > 0) _reflectReflection(s.rReflection, s.tReflection); if(s.rTreasury > 0 || s.tTreasury > 0) { _takeTreasury(s.rTreasury,s.tTreasury); } if(s.rCapital > 0 || s.tCapital > 0){ _takeCapital(s.rCapital, s.tCapital); emit Transfer(sender, capitalAddress, s.tMarketing); } if(s.rMarketing > 0 || s.tMarketing > 0){ _takeMarketing(s.rMarketing, s.tMarketing); emit Transfer(sender, marketingAddress, s.tMarketing); } if(s.rBurn > 0 || s.tBurn > 0){ _takeBurn(s.rBurn, s.tBurn); emit Transfer(sender, burnAddress, s.tBurn); } emit Transfer(sender, recipient, s.tTransferAmount); if(s.tTreasury > 0){ emit Transfer(sender, address(this), s.tTreasury); } } function swapTokensForETH(uint256 tokenAmount) private lockTheSwap { // generate the uniswap pair path of token -> weth address[] memory path = new address[](2); path[0] = address(this); path[1] = router.WETH(); _approve(address(this), address(router), tokenAmount); // make the swap router.swapExactTokensForETHSupportingFeeOnTransferTokens( tokenAmount, 0, // accept any amount of ETH path, address(this), block.timestamp ); (bool success, ) = capitalAddress.call{value: (ETHAmount.capital * address(this).balance)/tokenAmount}(""); require(success, 'ETH_TRANSFER_FAILED'); ETHAmount.capital = 0; (success, ) = marketingAddress.call{value: (ETHAmount.marketing * address(this).balance)/tokenAmount}(""); require(success, 'ETH_TRANSFER_FAILED'); ETHAmount.marketing = 0; } function updateCapitalWallet(address newWallet) external onlyOwner addressValidation(newWallet) { require(capitalAddress != newWallet, 'SaitaRealty: Wallet already set'); capitalAddress = newWallet; _isExcludedFromFee[capitalAddress]; } function updateBurnWallet(address newWallet) external onlyOwner addressValidation(newWallet) { require(burnAddress != newWallet, 'SaitaRealty: Wallet already set'); burnAddress = newWallet; _isExcludedFromFee[burnAddress]; } function updateMarketingWallet(address newWallet) external onlyOwner addressValidation(newWallet) { require(marketingAddress != newWallet, 'SaitaRealty: Wallet already set'); marketingAddress = newWallet; _isExcludedFromFee[marketingAddress]; } function updateStableCoin(address _usdt) external onlyOwner addressValidation(_usdt) { require(USDT != _usdt, 'SaitaRealty: Wallet already set'); USDT = _usdt; } function updateMaxTxAmt(uint256 amount) external onlyOwner { require(amount >= 100); maxTxAmount = amount * 10**_decimals; } function updateSwapTokensAtAmount(uint256 amount) external onlyOwner { require(amount > 0); swapTokensAtAmount = amount * 10**6; } function updateCoolDownSettings(bool _enabled, uint256 _timeInSeconds) external onlyOwner{ coolDownEnabled = _enabled; coolDownTime = _timeInSeconds * 1 seconds; } function setAntibot(address account, bool state) external onlyOwner{ require(_isBot[account] != state, 'SaitaRealty: Value already set'); _isBot[account] = state; } function bulkAntiBot(address[] memory accounts, bool state) external onlyOwner { require(accounts.length <= 100, "SaitaRealty: Invalid"); for(uint256 i = 0; i < accounts.length; i++){ _isBot[accounts[i]] = state; } } function updateRouterAndPair(address newRouter, address newPair) external onlyOwner { router = IRouter(newRouter); pair = newPair; addPair(pair); } function isBot(address account) public view returns(bool){ return _isBot[account]; } function airdropTokens(address[] memory recipients, uint256[] memory amounts) external onlyOwner { require(recipients.length == amounts.length,"Invalid size"); address sender = msg.sender; for(uint256 i; i<recipients.length; i++){ address recipient = recipients[i]; uint256 rAmount = amounts[i]*_getRate(); _rOwned[sender] = _rOwned[sender]- rAmount; _rOwned[recipient] = _rOwned[recipient] + rAmount; emit Transfer(sender, recipient, amounts[i]); } } //Use this in case ETH are sent to the contract by mistake function rescueETH(uint256 weiAmount) external onlyOwner{ require(address(this).balance >= weiAmount, "insufficient ETH balance"); payable(owner()).transfer(weiAmount); } // Function to allow admin to claim *other* ERC20 tokens sent to this contract (by mistake) // Owner cannot transfer out catecoin from this smart contract function rescueAnyERC20Tokens(address _tokenAddr, address _to, uint _amount) public onlyOwner { IERC20(_tokenAddr).transfer(_to, _amount); } receive() external payable { } }
File 2 of 4: SaitaSwapRouter
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.6.0; // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false library TransferHelper { function safeApprove( address token, address to, uint256 value ) internal { // bytes4(keccak256(bytes('approve(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value)); require( success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper::safeApprove: approve failed' ); } function safeTransfer( address token, address to, uint256 value ) internal { // bytes4(keccak256(bytes('transfer(address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value)); require( success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper::safeTransfer: transfer failed' ); } function safeTransferFrom( address token, address from, address to, uint256 value ) internal { // bytes4(keccak256(bytes('transferFrom(address,address,uint256)'))); (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value)); require( success && (data.length == 0 || abi.decode(data, (bool))), 'TransferHelper::transferFrom: transferFrom failed' ); } function safeTransferETH(address to, uint256 value) internal { (bool success, ) = to.call{value: value}(new bytes(0)); require(success, 'TransferHelper::safeTransferETH: ETH transfer failed'); } } // SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint 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 (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); } pragma solidity >=0.5.0; interface ISaitaSwapFactory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; }pragma solidity >=0.5.0; interface ISaitaSwapPair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }pragma solidity >=0.6.2; interface ISaitaSwapRouter01 { function factory() external pure returns (address); function WETH() external pure returns (address); function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB, uint liquidity); function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external payable returns (uint amountToken, uint amountETH, uint liquidity); function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) external returns (uint amountA, uint amountB); function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountToken, uint amountETH); function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountA, uint amountB); function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountToken, uint amountETH); function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external returns (uint[] memory amounts); function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external returns (uint[] memory amounts); function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts); function quote(uint amountA, uint reserveA, uint reserveB) external pure returns (uint amountB); function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) external pure returns (uint amountOut); function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) external pure returns (uint amountIn); function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts); function getAmountsIn(uint amountOut, address[] calldata path) external view returns (uint[] memory amounts); }pragma solidity >=0.6.2; import './ISaitaSwapRouter01.sol'; interface ISaitaSwapRouter02 is ISaitaSwapRouter01 { function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external returns (uint amountETH); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external returns (uint amountETH); function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external payable; function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external; }// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IWETH { function deposit() external payable; function transfer(address to, uint value) external returns (bool); function withdraw(uint) external; }pragma solidity =0.6.6; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, 'ds-math-add-overflow'); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, 'ds-math-sub-underflow'); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); } }pragma solidity =0.6.6; import "../interfaces/ISaitaSwapPair.sol"; import "./SafeMath.sol"; library SaitaSwapLibrary { 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, "SaitaSwapLibrary: IDENTICAL_ADDRESSES"); (token0, token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), "SaitaSwapLibrary: ZERO_ADDRESS"); } // calculates the CREATE2 address for a pair without making any external calls function pairFor( address factory, address tokenA, address tokenB ) internal pure returns (address pair) { (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address( (uint256( keccak256( abi.encodePacked( hex"ff", factory, keccak256(abi.encodePacked(token0, token1)), hex"ce30f06d03390218a95a12e2bb31c744b142f1064ccdfd037850b4194bfbe741" // init code hash ) ) )) ); } // fetches and sorts the reserves for a pair function getReserves( address factory, address tokenA, address tokenB ) internal view returns (uint256 reserveA, uint256 reserveB) { (address token0, ) = sortTokens(tokenA, tokenB); (uint256 reserve0, uint256 reserve1, ) = ISaitaSwapPair( pairFor(factory, tokenA, tokenB) ).getReserves(); (reserveA, reserveB) = tokenA == token0 ? (reserve0, reserve1) : (reserve1, reserve0); } // given some amount of an asset and pair reserves, returns an equivalent amount of the other asset function quote( uint256 amountA, uint256 reserveA, uint256 reserveB ) internal pure returns (uint256 amountB) { require(amountA > 0, "SaitaSwapLibrary: INSUFFICIENT_AMOUNT"); require( reserveA > 0 && reserveB > 0, "SaitaSwapLibrary: INSUFFICIENT_LIQUIDITY" ); amountB = amountA.mul(reserveB) / reserveA; } // 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, "SaitaSwapLibrary: INSUFFICIENT_INPUT_AMOUNT"); require( reserveIn > 0 && reserveOut > 0, "SaitaSwapLibrary: INSUFFICIENT_LIQUIDITY" ); uint256 amountInWithFee = amountIn.mul(997); uint256 numerator = amountInWithFee.mul(reserveOut); uint256 denominator = reserveIn.mul(1000).add(amountInWithFee); amountOut = numerator / denominator; } // given an output amount of an asset and pair reserves, returns a required input amount of the other asset function getAmountIn( uint256 amountOut, uint256 reserveIn, uint256 reserveOut ) internal pure returns (uint256 amountIn) { require(amountOut > 0, "SaitaSwapLibrary: INSUFFICIENT_OUTPUT_AMOUNT"); require( reserveIn > 0 && reserveOut > 0, "SaitaSwapLibrary: INSUFFICIENT_LIQUIDITY" ); uint256 numerator = reserveIn.mul(amountOut).mul(1000); uint256 denominator = reserveOut.sub(amountOut).mul(997); amountIn = (numerator / denominator).add(1); } // performs chained getAmountOut calculations on any number of pairs function getAmountsOut( address factory, uint256 amountIn, address[] memory path ) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "SaitaSwapLibrary: INVALID_PATH"); amounts = new uint256[](path.length); amounts[0] = amountIn; for (uint256 i; i < path.length - 1; i++) { (uint256 reserveIn, uint256 reserveOut) = getReserves( factory, path[i], path[i + 1] ); amounts[i + 1] = getAmountOut(amounts[i], reserveIn, reserveOut); } } // performs chained getAmountIn calculations on any number of pairs function getAmountsIn( address factory, uint256 amountOut, address[] memory path ) internal view returns (uint256[] memory amounts) { require(path.length >= 2, "SaitaSwapLibrary: INVALID_PATH"); amounts = new uint256[](path.length); amounts[amounts.length - 1] = amountOut; for (uint256 i = path.length - 1; i > 0; i--) { (uint256 reserveIn, uint256 reserveOut) = getReserves( factory, path[i - 1], path[i] ); amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); } } }// SPDX-License-Identifier: GPL-3.0 pragma solidity =0.6.6; import "./interfaces/ISaitaSwapFactory.sol"; import "@uniswap/lib/contracts/libraries/TransferHelper.sol"; import "./interfaces/ISaitaSwapRouter02.sol"; import "./libraries/SaitaSwapLibrary.sol"; import "./libraries/SafeMath.sol"; import "./interfaces/IERC20.sol"; import "./interfaces/IWETH.sol"; contract SaitaSwapRouter is ISaitaSwapRouter02 { using SafeMath for uint; address public immutable override factory; address public immutable override WETH; modifier ensure(uint deadline) { require(deadline >= block.timestamp, "SaitaSwapRouter: EXPIRED"); _; } constructor(address _factory, address _WETH) public { factory = _factory; WETH = _WETH; } receive() external payable { assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract } // **** ADD LIQUIDITY **** function _addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin ) internal virtual returns (uint amountA, uint amountB) { // create the pair if it doesn"t exist yet if (ISaitaSwapFactory(factory).getPair(tokenA, tokenB) == address(0)) { ISaitaSwapFactory(factory).createPair(tokenA, tokenB); } (uint reserveA, uint reserveB) = SaitaSwapLibrary.getReserves(factory, tokenA, tokenB); if (reserveA == 0 && reserveB == 0) { (amountA, amountB) = (amountADesired, amountBDesired); } else { uint amountBOptimal = SaitaSwapLibrary.quote(amountADesired, reserveA, reserveB); if (amountBOptimal <= amountBDesired) { require(amountBOptimal >= amountBMin, "SaitaSwapRouter: INSUFFICIENT_B_AMOUNT"); (amountA, amountB) = (amountADesired, amountBOptimal); } else { uint amountAOptimal = SaitaSwapLibrary.quote(amountBDesired, reserveB, reserveA); assert(amountAOptimal <= amountADesired); require(amountAOptimal >= amountAMin, "SaitaSwapRouter: INSUFFICIENT_A_AMOUNT"); (amountA, amountB) = (amountAOptimal, amountBDesired); } } } function addLiquidity( address tokenA, address tokenB, uint amountADesired, uint amountBDesired, uint amountAMin, uint amountBMin, address to, uint deadline ) external virtual override ensure(deadline) returns (uint amountA, uint amountB, uint liquidity) { (amountA, amountB) = _addLiquidity(tokenA, tokenB, amountADesired, amountBDesired, amountAMin, amountBMin); address pair = SaitaSwapLibrary.pairFor(factory, tokenA, tokenB); TransferHelper.safeTransferFrom(tokenA, msg.sender, pair, amountA); TransferHelper.safeTransferFrom(tokenB, msg.sender, pair, amountB); liquidity = ISaitaSwapPair(pair).mint(to); } function addLiquidityETH( address token, uint amountTokenDesired, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) external virtual override payable ensure(deadline) returns (uint amountToken, uint amountETH, uint liquidity) { (amountToken, amountETH) = _addLiquidity( token, WETH, amountTokenDesired, msg.value, amountTokenMin, amountETHMin ); address pair = SaitaSwapLibrary.pairFor(factory, token, WETH); TransferHelper.safeTransferFrom(token, msg.sender, pair, amountToken); IWETH(WETH).deposit{value: amountETH}(); assert(IWETH(WETH).transfer(pair, amountETH)); liquidity = ISaitaSwapPair(pair).mint(to); // refund dust eth, if any if (msg.value > amountETH) TransferHelper.safeTransferETH(msg.sender, msg.value - amountETH); } // **** REMOVE LIQUIDITY **** function removeLiquidity( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline ) public virtual override ensure(deadline) returns (uint amountA, uint amountB) { address pair = SaitaSwapLibrary.pairFor(factory, tokenA, tokenB); ISaitaSwapPair(pair).transferFrom(msg.sender, pair, liquidity); // send liquidity to pair (uint amount0, uint amount1) = ISaitaSwapPair(pair).burn(to); (address token0,) = SaitaSwapLibrary.sortTokens(tokenA, tokenB); (amountA, amountB) = tokenA == token0 ? (amount0, amount1) : (amount1, amount0); require(amountA >= amountAMin, "SaitaSwapRouter: INSUFFICIENT_A_AMOUNT"); require(amountB >= amountBMin, "SaitaSwapRouter: INSUFFICIENT_B_AMOUNT"); } function removeLiquidityETH( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) public virtual override ensure(deadline) returns (uint amountToken, uint amountETH) { (amountToken, amountETH) = removeLiquidity( token, WETH, liquidity, amountTokenMin, amountETHMin, address(this), deadline ); TransferHelper.safeTransfer(token, to, amountToken); IWETH(WETH).withdraw(amountETH); TransferHelper.safeTransferETH(to, amountETH); } function removeLiquidityWithPermit( address tokenA, address tokenB, uint liquidity, uint amountAMin, uint amountBMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external virtual override returns (uint amountA, uint amountB) { address pair = SaitaSwapLibrary.pairFor(factory, tokenA, tokenB); uint value = approveMax ? uint(-1) : liquidity; ISaitaSwapPair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); (amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline); } function removeLiquidityETHWithPermit( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external virtual override returns (uint amountToken, uint amountETH) { address pair = SaitaSwapLibrary.pairFor(factory, token, WETH); uint value = approveMax ? uint(-1) : liquidity; ISaitaSwapPair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); (amountToken, amountETH) = removeLiquidityETH(token, liquidity, amountTokenMin, amountETHMin, to, deadline); } // **** REMOVE LIQUIDITY (supporting fee-on-transfer tokens) **** function removeLiquidityETHSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline ) public virtual override ensure(deadline) returns (uint amountETH) { (, amountETH) = removeLiquidity( token, WETH, liquidity, amountTokenMin, amountETHMin, address(this), deadline ); TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this))); IWETH(WETH).withdraw(amountETH); TransferHelper.safeTransferETH(to, amountETH); } function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens( address token, uint liquidity, uint amountTokenMin, uint amountETHMin, address to, uint deadline, bool approveMax, uint8 v, bytes32 r, bytes32 s ) external virtual override returns (uint amountETH) { address pair = SaitaSwapLibrary.pairFor(factory, token, WETH); uint value = approveMax ? uint(-1) : liquidity; ISaitaSwapPair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); amountETH = removeLiquidityETHSupportingFeeOnTransferTokens( token, liquidity, amountTokenMin, amountETHMin, to, deadline ); } // **** SWAP **** // requires the initial amount to have already been sent to the first pair function _swap(uint[] memory amounts, address[] memory path, address _to) internal virtual { for (uint i; i < path.length - 1; i++) { (address input, address output) = (path[i], path[i + 1]); (address token0,) = SaitaSwapLibrary.sortTokens(input, output); uint amountOut = amounts[i + 1]; (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOut) : (amountOut, uint(0)); address to = i < path.length - 2 ? SaitaSwapLibrary.pairFor(factory, output, path[i + 2]) : _to; ISaitaSwapPair(SaitaSwapLibrary.pairFor(factory, input, output)).swap( amount0Out, amount1Out, to, new bytes(0) ); } } function swapExactTokensForTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) returns (uint[] memory amounts) { amounts = SaitaSwapLibrary.getAmountsOut(factory, amountIn, path); require(amounts[amounts.length - 1] >= amountOutMin, "SaitaSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT"); TransferHelper.safeTransferFrom( path[0], msg.sender, SaitaSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0] ); _swap(amounts, path, to); } function swapTokensForExactTokens( uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) returns (uint[] memory amounts) { amounts = SaitaSwapLibrary.getAmountsIn(factory, amountOut, path); require(amounts[0] <= amountInMax, "SaitaSwapRouter: EXCESSIVE_INPUT_AMOUNT"); TransferHelper.safeTransferFrom( path[0], msg.sender, SaitaSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0] ); _swap(amounts, path, to); } function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external virtual override payable ensure(deadline) returns (uint[] memory amounts) { require(path[0] == WETH, "SaitaSwapRouter: INVALID_PATH"); amounts = SaitaSwapLibrary.getAmountsOut(factory, msg.value, path); require(amounts[amounts.length - 1] >= amountOutMin, "SaitaSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT"); IWETH(WETH).deposit{value: amounts[0]}(); assert(IWETH(WETH).transfer(SaitaSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0])); _swap(amounts, path, to); } function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline) external virtual override ensure(deadline) returns (uint[] memory amounts) { require(path[path.length - 1] == WETH, "SaitaSwapRouter: INVALID_PATH"); amounts = SaitaSwapLibrary.getAmountsIn(factory, amountOut, path); require(amounts[0] <= amountInMax, "SaitaSwapRouter: EXCESSIVE_INPUT_AMOUNT"); TransferHelper.safeTransferFrom( path[0], msg.sender, SaitaSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0] ); _swap(amounts, path, address(this)); IWETH(WETH).withdraw(amounts[amounts.length - 1]); TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); } function swapExactTokensForETH(uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline) external virtual override ensure(deadline) returns (uint[] memory amounts) { require(path[path.length - 1] == WETH, "SaitaSwapRouter: INVALID_PATH"); amounts = SaitaSwapLibrary.getAmountsOut(factory, amountIn, path); require(amounts[amounts.length - 1] >= amountOutMin, "SaitaSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT"); TransferHelper.safeTransferFrom( path[0], msg.sender, SaitaSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0] ); _swap(amounts, path, address(this)); IWETH(WETH).withdraw(amounts[amounts.length - 1]); TransferHelper.safeTransferETH(to, amounts[amounts.length - 1]); } function swapETHForExactTokens(uint amountOut, address[] calldata path, address to, uint deadline) external virtual override payable ensure(deadline) returns (uint[] memory amounts) { require(path[0] == WETH, "SaitaSwapRouter: INVALID_PATH"); amounts = SaitaSwapLibrary.getAmountsIn(factory, amountOut, path); require(amounts[0] <= msg.value, "SaitaSwapRouter: EXCESSIVE_INPUT_AMOUNT"); IWETH(WETH).deposit{value: amounts[0]}(); assert(IWETH(WETH).transfer(SaitaSwapLibrary.pairFor(factory, path[0], path[1]), amounts[0])); _swap(amounts, path, to); // refund dust eth, if any if (msg.value > amounts[0]) TransferHelper.safeTransferETH(msg.sender, msg.value - amounts[0]); } // **** SWAP (supporting fee-on-transfer tokens) **** // requires the initial amount to have already been sent to the first pair function _swapSupportingFeeOnTransferTokens(address[] memory path, address _to) internal virtual { for (uint i; i < path.length - 1; i++) { (address input, address output) = (path[i], path[i + 1]); (address token0,) = SaitaSwapLibrary.sortTokens(input, output); ISaitaSwapPair pair = ISaitaSwapPair(SaitaSwapLibrary.pairFor(factory, input, output)); uint amountInput; uint amountOutput; { // scope to avoid stack too deep errors (uint reserve0, uint reserve1,) = pair.getReserves(); (uint reserveInput, uint reserveOutput) = input == token0 ? (reserve0, reserve1) : (reserve1, reserve0); amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput); amountOutput = SaitaSwapLibrary.getAmountOut(amountInput, reserveInput, reserveOutput); } (uint amount0Out, uint amount1Out) = input == token0 ? (uint(0), amountOutput) : (amountOutput, uint(0)); address to = i < path.length - 2 ? SaitaSwapLibrary.pairFor(factory, output, path[i + 2]) : _to; pair.swap(amount0Out, amount1Out, to, new bytes(0)); } } function swapExactTokensForTokensSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) { TransferHelper.safeTransferFrom( path[0], msg.sender, SaitaSwapLibrary.pairFor(factory, path[0], path[1]), amountIn ); uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); _swapSupportingFeeOnTransferTokens(path, to); require( IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, "SaitaSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT" ); } function swapExactETHForTokensSupportingFeeOnTransferTokens( uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override payable ensure(deadline) { require(path[0] == WETH, "SaitaSwapRouter: INVALID_PATH"); uint amountIn = msg.value; IWETH(WETH).deposit{value: amountIn}(); assert(IWETH(WETH).transfer(SaitaSwapLibrary.pairFor(factory, path[0], path[1]), amountIn)); uint balanceBefore = IERC20(path[path.length - 1]).balanceOf(to); _swapSupportingFeeOnTransferTokens(path, to); require( IERC20(path[path.length - 1]).balanceOf(to).sub(balanceBefore) >= amountOutMin, "SaitaSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT" ); } function swapExactTokensForETHSupportingFeeOnTransferTokens( uint amountIn, uint amountOutMin, address[] calldata path, address to, uint deadline ) external virtual override ensure(deadline) { require(path[path.length - 1] == WETH, "SaitaSwapRouter: INVALID_PATH"); TransferHelper.safeTransferFrom( path[0], msg.sender, SaitaSwapLibrary.pairFor(factory, path[0], path[1]), amountIn ); _swapSupportingFeeOnTransferTokens(path, address(this)); uint amountOut = IERC20(WETH).balanceOf(address(this)); require(amountOut >= amountOutMin, "SaitaSwapRouter: INSUFFICIENT_OUTPUT_AMOUNT"); IWETH(WETH).withdraw(amountOut); TransferHelper.safeTransferETH(to, amountOut); } // **** LIBRARY FUNCTIONS **** function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) { return SaitaSwapLibrary.quote(amountA, reserveA, reserveB); } function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut) public pure virtual override returns (uint amountOut) { return SaitaSwapLibrary.getAmountOut(amountIn, reserveIn, reserveOut); } function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) public pure virtual override returns (uint amountIn) { return SaitaSwapLibrary.getAmountIn(amountOut, reserveIn, reserveOut); } function getAmountsOut(uint amountIn, address[] memory path) public view virtual override returns (uint[] memory amounts) { return SaitaSwapLibrary.getAmountsOut(factory, amountIn, path); } function getAmountsIn(uint amountOut, address[] memory path) public view virtual override returns (uint[] memory amounts) { return SaitaSwapLibrary.getAmountsIn(factory, amountOut, path); } }
File 3 of 4: SaitaSwapPair
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint 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 (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); } pragma solidity >=0.5.0; interface ISaitaSwapCallee { function SaitaSwapCall(address sender, uint amount0, uint amount1, bytes calldata data) external; }pragma solidity >=0.5.0; interface ISaitaSwapERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; }pragma solidity >=0.5.0; interface ISaitaSwapFactory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; }pragma solidity >=0.5.0; interface ISaitaSwapPair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }pragma solidity =0.5.16; // a library for performing various math operations library Math { function min(uint x, uint y) internal pure returns (uint z) { z = x < y ? x : y; } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } }pragma solidity =0.5.16; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, 'ds-math-add-overflow'); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, 'ds-math-sub-underflow'); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); } }pragma solidity =0.5.16; // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) // range: [0, 2**112 - 1] // resolution: 1 / 2**112 library UQ112x112 { uint224 constant Q112 = 2**112; // encode a uint112 as a UQ112x112 function encode(uint112 y) internal pure returns (uint224 z) { z = uint224(y) * Q112; // never overflows } // divide a UQ112x112 by a uint112, returning a UQ112x112 function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { z = x / uint224(y); } }// SPDX-License-Identifier: UNLICENSED pragma solidity =0.5.16; import './interfaces/ISaitaSwapERC20.sol'; import './libraries/SafeMath.sol'; contract SaitaSwapERC20 is ISaitaSwapERC20 { using SafeMath for uint; string public constant name = 'SaitaSwap LPs'; string public constant symbol = 'slp'; uint8 public constant decimals = 18; uint public totalSupply; mapping(address => uint) public balanceOf; mapping(address => mapping(address => uint)) public allowance; bytes32 public DOMAIN_SEPARATOR; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; mapping(address => uint) public nonces; event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); modifier ReChain{ uint chainId; assembly { chainId := chainid } DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes(name)), keccak256(bytes('1')), chainId, address(this) ) ); _; } constructor() public { uint chainId; assembly { chainId := chainid } DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes(name)), keccak256(bytes('1')), chainId, address(this) ) ); } function _mint(address to, uint value) internal { totalSupply = totalSupply.add(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(address(0), to, value); } function _burn(address from, uint value) internal { balanceOf[from] = balanceOf[from].sub(value); totalSupply = totalSupply.sub(value); emit Transfer(from, address(0), value); } function _approve(address owner, address spender, uint value) private { allowance[owner][spender] = value; emit Approval(owner, spender, value); } function _transfer(address from, address to, uint value) private { balanceOf[from] = balanceOf[from].sub(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(from, to, value); } function approve(address spender, uint value) external returns (bool) { _approve(msg.sender, spender, value); return true; } function transfer(address to, uint value) external returns (bool) { _transfer(msg.sender, to, value); return true; } function transferFrom(address from, address to, uint value) external returns (bool) { if (allowance[from][msg.sender] != uint(-1)) { allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); } _transfer(from, to, value); return true; } function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external ReChain { require(deadline >= block.timestamp, 'SaitaSwap: EXPIRED'); bytes32 digest = keccak256( abi.encodePacked( '\\x19\\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, 'SaitaSwap: INVALID_SIGNATURE'); _approve(owner, spender, value); } }// SPDX-License-Identifier: GPL-3.0 pragma solidity =0.5.16; import './interfaces/ISaitaSwapPair.sol'; import './SaitaSwapERC20.sol'; import './libraries/Math.sol'; import './libraries/UQ112x112.sol'; import './interfaces/IERC20.sol'; import './interfaces/ISaitaSwapFactory.sol'; import './interfaces/ISaitaSwapCallee.sol'; contract SaitaSwapPair is ISaitaSwapPair, SaitaSwapERC20 { using SafeMath for uint; using UQ112x112 for uint224; uint public constant MINIMUM_LIQUIDITY = 10**3; bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); address public factory; address public token0; address public token1; uint public SWAP_FEE_NUMERATOR=2; uint public SWAP_FEE_DENOMINATOR=1000; uint112 private reserve0; // uses single storage slot, accessible via getReserves uint112 private reserve1; // uses single storage slot, accessible via getReserves uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves uint public price0CumulativeLast; uint public price1CumulativeLast; uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event uint private unlocked = 1; modifier lock() { require(unlocked == 1, 'SaitaSwap: LOCKED'); unlocked = 0; _; unlocked = 1; } function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) { _reserve0 = reserve0; _reserve1 = reserve1; _blockTimestampLast = blockTimestampLast; } function _safeTransfer(address token, address to, uint value) private { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'SaitaSwap: TRANSFER_FAILED'); } event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); constructor() public { factory = msg.sender; } // called once by the factory at time of deployment function initialize(address _token0, address _token1) external { require(msg.sender == factory, 'SaitaSwap: FORBIDDEN'); // sufficient check token0 = _token0; token1 = _token1; } // update reserves and, on the first call per block, price accumulators function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private { require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'SaitaSwap: OVERFLOW'); uint32 blockTimestamp = uint32(block.timestamp % 2**32); uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { // * never overflows, and + overflow is desired price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed; price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed; } reserve0 = uint112(balance0); reserve1 = uint112(balance1); blockTimestampLast = blockTimestamp; emit Sync(reserve0, reserve1); } // if fee is on, mint liquidity equivalent to the growth in sqrt(k) . function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) { address feeTo = ISaitaSwapFactory(factory).feeTo(); feeOn = feeTo != address(0); uint _kLast = kLast; // gas savings if (feeOn) { if (_kLast != 0) { uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); uint rootKLast = Math.sqrt(_kLast); if (rootK > rootKLast) { uint numerator = totalSupply.mul(rootK.sub(rootKLast)); uint denominator = rootKLast; uint liquidity = numerator / denominator; if (liquidity > 0) _mint(feeTo, liquidity); } } } else if (_kLast != 0) { kLast = 0; } } // this low-level function should be called from a contract which performs important safety checks function mint(address to) external lock returns (uint liquidity) { (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings uint balance0 = IERC20(token0).balanceOf(address(this)); uint balance1 = IERC20(token1).balanceOf(address(this)); uint amount0 = balance0.sub(_reserve0); uint amount1 = balance1.sub(_reserve1); bool feeOn = _mintFee(_reserve0, _reserve1); uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee if (_totalSupply == 0) { liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens } else { liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1); } require(liquidity > 0, 'SaitaSwap: INSUFFICIENT_LIQUIDITY_MINTED'); _mint(to, liquidity); _update(balance0, balance1, _reserve0, _reserve1); if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date emit Mint(msg.sender, amount0, amount1); } // this low-level function should be called from a contract which performs important safety checks function burn(address to) external lock returns (uint amount0, uint amount1) { (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings address _token0 = token0; // gas savings address _token1 = token1; // gas savings uint balance0 = IERC20(_token0).balanceOf(address(this)); uint balance1 = IERC20(_token1).balanceOf(address(this)); uint liquidity = balanceOf[address(this)]; bool feeOn = _mintFee(_reserve0, _reserve1); uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution require(amount0 > 0 && amount1 > 0, 'SaitaSwap: INSUFFICIENT_LIQUIDITY_BURNED'); _burn(address(this), liquidity); _safeTransfer(_token0, to, amount0); _safeTransfer(_token1, to, amount1); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); _update(balance0, balance1, _reserve0, _reserve1); if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date emit Burn(msg.sender, amount0, amount1, to); } // this low-level function should be called from a contract which performs important safety checks function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock { require(amount0Out > 0 || amount1Out > 0, 'SaitaSwap: INSUFFICIENT_OUTPUT_AMOUNT'); (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings require(amount0Out < _reserve0 && amount1Out < _reserve1, 'SaitaSwap: INSUFFICIENT_LIQUIDITY'); uint balance0; uint balance1; { // scope for _token{0,1}, avoids stack too deep errors address _token0 = token0; address _token1 = token1; require(to != _token0 && to != _token1, 'SaitaSwap: INVALID_TO'); if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens if (data.length > 0) ISaitaSwapCallee(to).SaitaSwapCall(msg.sender, amount0Out, amount1Out, data); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); } uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0; uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0; require(amount0In > 0 || amount1In > 0, 'SaitaSwap: INSUFFICIENT_INPUT_AMOUNT'); { // scope for reserve{0,1}Adjusted, avoids stack too deep errors uint balance0Adjusted = balance0.mul(SWAP_FEE_DENOMINATOR).sub(amount0In.mul(SWAP_FEE_NUMERATOR)); uint balance1Adjusted = balance1.mul(SWAP_FEE_DENOMINATOR).sub(amount1In.mul(SWAP_FEE_NUMERATOR)); require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(SWAP_FEE_DENOMINATOR**SWAP_FEE_NUMERATOR), 'SaitaSwap: K'); } _update(balance0, balance1, _reserve0, _reserve1); emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); } // force balances to match reserves function skim(address to) external lock { address _token0 = token0; // gas savings address _token1 = token1; // gas savings _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0)); _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1)); } // force reserves to match balances function sync() external lock { _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1); } }
File 4 of 4: SaitaSwapPair
// SPDX-License-Identifier: MIT pragma solidity >=0.5.0; interface IERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint 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 (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); } pragma solidity >=0.5.0; interface ISaitaSwapCallee { function SaitaSwapCall(address sender, uint amount0, uint amount1, bytes calldata data) external; }pragma solidity >=0.5.0; interface ISaitaSwapERC20 { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; }pragma solidity >=0.5.0; interface ISaitaSwapFactory { event PairCreated(address indexed token0, address indexed token1, address pair, uint); function feeTo() external view returns (address); function feeToSetter() external view returns (address); function getPair(address tokenA, address tokenB) external view returns (address pair); function allPairs(uint) external view returns (address pair); function allPairsLength() external view returns (uint); function createPair(address tokenA, address tokenB) external returns (address pair); function setFeeTo(address) external; function setFeeToSetter(address) external; }pragma solidity >=0.5.0; interface ISaitaSwapPair { event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); function name() external pure returns (string memory); function symbol() external pure returns (string memory); function decimals() external pure returns (uint8); function totalSupply() external view returns (uint); function balanceOf(address owner) external view returns (uint); function allowance(address owner, address spender) external view returns (uint); function approve(address spender, uint value) external returns (bool); function transfer(address to, uint value) external returns (bool); function transferFrom(address from, address to, uint value) external returns (bool); function DOMAIN_SEPARATOR() external view returns (bytes32); function PERMIT_TYPEHASH() external pure returns (bytes32); function nonces(address owner) external view returns (uint); function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); function MINIMUM_LIQUIDITY() external pure returns (uint); function factory() external view returns (address); function token0() external view returns (address); function token1() external view returns (address); function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); function price0CumulativeLast() external view returns (uint); function price1CumulativeLast() external view returns (uint); function kLast() external view returns (uint); function mint(address to) external returns (uint liquidity); function burn(address to) external returns (uint amount0, uint amount1); function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; function skim(address to) external; function sync() external; function initialize(address, address) external; }pragma solidity =0.5.16; // a library for performing various math operations library Math { function min(uint x, uint y) internal pure returns (uint z) { z = x < y ? x : y; } // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method) function sqrt(uint y) internal pure returns (uint z) { if (y > 3) { z = y; uint x = y / 2 + 1; while (x < z) { z = x; x = (y / x + x) / 2; } } else if (y != 0) { z = 1; } } }pragma solidity =0.5.16; // a library for performing overflow-safe math, courtesy of DappHub (https://github.com/dapphub/ds-math) library SafeMath { function add(uint x, uint y) internal pure returns (uint z) { require((z = x + y) >= x, 'ds-math-add-overflow'); } function sub(uint x, uint y) internal pure returns (uint z) { require((z = x - y) <= x, 'ds-math-sub-underflow'); } function mul(uint x, uint y) internal pure returns (uint z) { require(y == 0 || (z = x * y) / y == x, 'ds-math-mul-overflow'); } }pragma solidity =0.5.16; // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) // range: [0, 2**112 - 1] // resolution: 1 / 2**112 library UQ112x112 { uint224 constant Q112 = 2**112; // encode a uint112 as a UQ112x112 function encode(uint112 y) internal pure returns (uint224 z) { z = uint224(y) * Q112; // never overflows } // divide a UQ112x112 by a uint112, returning a UQ112x112 function uqdiv(uint224 x, uint112 y) internal pure returns (uint224 z) { z = x / uint224(y); } }// SPDX-License-Identifier: UNLICENSED pragma solidity =0.5.16; import './interfaces/ISaitaSwapERC20.sol'; import './libraries/SafeMath.sol'; contract SaitaSwapERC20 is ISaitaSwapERC20 { using SafeMath for uint; string public constant name = 'SaitaSwap LPs'; string public constant symbol = 'slp'; uint8 public constant decimals = 18; uint public totalSupply; mapping(address => uint) public balanceOf; mapping(address => mapping(address => uint)) public allowance; bytes32 public DOMAIN_SEPARATOR; // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; mapping(address => uint) public nonces; event Approval(address indexed owner, address indexed spender, uint value); event Transfer(address indexed from, address indexed to, uint value); modifier ReChain{ uint chainId; assembly { chainId := chainid } DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes(name)), keccak256(bytes('1')), chainId, address(this) ) ); _; } constructor() public { uint chainId; assembly { chainId := chainid } DOMAIN_SEPARATOR = keccak256( abi.encode( keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), keccak256(bytes(name)), keccak256(bytes('1')), chainId, address(this) ) ); } function _mint(address to, uint value) internal { totalSupply = totalSupply.add(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(address(0), to, value); } function _burn(address from, uint value) internal { balanceOf[from] = balanceOf[from].sub(value); totalSupply = totalSupply.sub(value); emit Transfer(from, address(0), value); } function _approve(address owner, address spender, uint value) private { allowance[owner][spender] = value; emit Approval(owner, spender, value); } function _transfer(address from, address to, uint value) private { balanceOf[from] = balanceOf[from].sub(value); balanceOf[to] = balanceOf[to].add(value); emit Transfer(from, to, value); } function approve(address spender, uint value) external returns (bool) { _approve(msg.sender, spender, value); return true; } function transfer(address to, uint value) external returns (bool) { _transfer(msg.sender, to, value); return true; } function transferFrom(address from, address to, uint value) external returns (bool) { if (allowance[from][msg.sender] != uint(-1)) { allowance[from][msg.sender] = allowance[from][msg.sender].sub(value); } _transfer(from, to, value); return true; } function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external ReChain { require(deadline >= block.timestamp, 'SaitaSwap: EXPIRED'); bytes32 digest = keccak256( abi.encodePacked( '\\x19\\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)) ) ); address recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, 'SaitaSwap: INVALID_SIGNATURE'); _approve(owner, spender, value); } }// SPDX-License-Identifier: GPL-3.0 pragma solidity =0.5.16; import './interfaces/ISaitaSwapPair.sol'; import './SaitaSwapERC20.sol'; import './libraries/Math.sol'; import './libraries/UQ112x112.sol'; import './interfaces/IERC20.sol'; import './interfaces/ISaitaSwapFactory.sol'; import './interfaces/ISaitaSwapCallee.sol'; contract SaitaSwapPair is ISaitaSwapPair, SaitaSwapERC20 { using SafeMath for uint; using UQ112x112 for uint224; uint public constant MINIMUM_LIQUIDITY = 10**3; bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); address public factory; address public token0; address public token1; uint public SWAP_FEE_NUMERATOR=2; uint public SWAP_FEE_DENOMINATOR=1000; uint112 private reserve0; // uses single storage slot, accessible via getReserves uint112 private reserve1; // uses single storage slot, accessible via getReserves uint32 private blockTimestampLast; // uses single storage slot, accessible via getReserves uint public price0CumulativeLast; uint public price1CumulativeLast; uint public kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event uint private unlocked = 1; modifier lock() { require(unlocked == 1, 'SaitaSwap: LOCKED'); unlocked = 0; _; unlocked = 1; } function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) { _reserve0 = reserve0; _reserve1 = reserve1; _blockTimestampLast = blockTimestampLast; } function _safeTransfer(address token, address to, uint value) private { (bool success, bytes memory data) = token.call(abi.encodeWithSelector(SELECTOR, to, value)); require(success && (data.length == 0 || abi.decode(data, (bool))), 'SaitaSwap: TRANSFER_FAILED'); } event Mint(address indexed sender, uint amount0, uint amount1); event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); event Swap( address indexed sender, uint amount0In, uint amount1In, uint amount0Out, uint amount1Out, address indexed to ); event Sync(uint112 reserve0, uint112 reserve1); constructor() public { factory = msg.sender; } // called once by the factory at time of deployment function initialize(address _token0, address _token1) external { require(msg.sender == factory, 'SaitaSwap: FORBIDDEN'); // sufficient check token0 = _token0; token1 = _token1; } // update reserves and, on the first call per block, price accumulators function _update(uint balance0, uint balance1, uint112 _reserve0, uint112 _reserve1) private { require(balance0 <= uint112(-1) && balance1 <= uint112(-1), 'SaitaSwap: OVERFLOW'); uint32 blockTimestamp = uint32(block.timestamp % 2**32); uint32 timeElapsed = blockTimestamp - blockTimestampLast; // overflow is desired if (timeElapsed > 0 && _reserve0 != 0 && _reserve1 != 0) { // * never overflows, and + overflow is desired price0CumulativeLast += uint(UQ112x112.encode(_reserve1).uqdiv(_reserve0)) * timeElapsed; price1CumulativeLast += uint(UQ112x112.encode(_reserve0).uqdiv(_reserve1)) * timeElapsed; } reserve0 = uint112(balance0); reserve1 = uint112(balance1); blockTimestampLast = blockTimestamp; emit Sync(reserve0, reserve1); } // if fee is on, mint liquidity equivalent to the growth in sqrt(k) . function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) { address feeTo = ISaitaSwapFactory(factory).feeTo(); feeOn = feeTo != address(0); uint _kLast = kLast; // gas savings if (feeOn) { if (_kLast != 0) { uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); uint rootKLast = Math.sqrt(_kLast); if (rootK > rootKLast) { uint numerator = totalSupply.mul(rootK.sub(rootKLast)); uint denominator = rootKLast; uint liquidity = numerator / denominator; if (liquidity > 0) _mint(feeTo, liquidity); } } } else if (_kLast != 0) { kLast = 0; } } // this low-level function should be called from a contract which performs important safety checks function mint(address to) external lock returns (uint liquidity) { (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings uint balance0 = IERC20(token0).balanceOf(address(this)); uint balance1 = IERC20(token1).balanceOf(address(this)); uint amount0 = balance0.sub(_reserve0); uint amount1 = balance1.sub(_reserve1); bool feeOn = _mintFee(_reserve0, _reserve1); uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee if (_totalSupply == 0) { liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY); _mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens } else { liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1); } require(liquidity > 0, 'SaitaSwap: INSUFFICIENT_LIQUIDITY_MINTED'); _mint(to, liquidity); _update(balance0, balance1, _reserve0, _reserve1); if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date emit Mint(msg.sender, amount0, amount1); } // this low-level function should be called from a contract which performs important safety checks function burn(address to) external lock returns (uint amount0, uint amount1) { (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings address _token0 = token0; // gas savings address _token1 = token1; // gas savings uint balance0 = IERC20(_token0).balanceOf(address(this)); uint balance1 = IERC20(_token1).balanceOf(address(this)); uint liquidity = balanceOf[address(this)]; bool feeOn = _mintFee(_reserve0, _reserve1); uint _totalSupply = totalSupply; // gas savings, must be defined here since totalSupply can update in _mintFee amount0 = liquidity.mul(balance0) / _totalSupply; // using balances ensures pro-rata distribution amount1 = liquidity.mul(balance1) / _totalSupply; // using balances ensures pro-rata distribution require(amount0 > 0 && amount1 > 0, 'SaitaSwap: INSUFFICIENT_LIQUIDITY_BURNED'); _burn(address(this), liquidity); _safeTransfer(_token0, to, amount0); _safeTransfer(_token1, to, amount1); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); _update(balance0, balance1, _reserve0, _reserve1); if (feeOn) kLast = uint(reserve0).mul(reserve1); // reserve0 and reserve1 are up-to-date emit Burn(msg.sender, amount0, amount1, to); } // this low-level function should be called from a contract which performs important safety checks function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external lock { require(amount0Out > 0 || amount1Out > 0, 'SaitaSwap: INSUFFICIENT_OUTPUT_AMOUNT'); (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings require(amount0Out < _reserve0 && amount1Out < _reserve1, 'SaitaSwap: INSUFFICIENT_LIQUIDITY'); uint balance0; uint balance1; { // scope for _token{0,1}, avoids stack too deep errors address _token0 = token0; address _token1 = token1; require(to != _token0 && to != _token1, 'SaitaSwap: INVALID_TO'); if (amount0Out > 0) _safeTransfer(_token0, to, amount0Out); // optimistically transfer tokens if (amount1Out > 0) _safeTransfer(_token1, to, amount1Out); // optimistically transfer tokens if (data.length > 0) ISaitaSwapCallee(to).SaitaSwapCall(msg.sender, amount0Out, amount1Out, data); balance0 = IERC20(_token0).balanceOf(address(this)); balance1 = IERC20(_token1).balanceOf(address(this)); } uint amount0In = balance0 > _reserve0 - amount0Out ? balance0 - (_reserve0 - amount0Out) : 0; uint amount1In = balance1 > _reserve1 - amount1Out ? balance1 - (_reserve1 - amount1Out) : 0; require(amount0In > 0 || amount1In > 0, 'SaitaSwap: INSUFFICIENT_INPUT_AMOUNT'); { // scope for reserve{0,1}Adjusted, avoids stack too deep errors uint balance0Adjusted = balance0.mul(SWAP_FEE_DENOMINATOR).sub(amount0In.mul(SWAP_FEE_NUMERATOR)); uint balance1Adjusted = balance1.mul(SWAP_FEE_DENOMINATOR).sub(amount1In.mul(SWAP_FEE_NUMERATOR)); require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(SWAP_FEE_DENOMINATOR**SWAP_FEE_NUMERATOR), 'SaitaSwap: K'); } _update(balance0, balance1, _reserve0, _reserve1); emit Swap(msg.sender, amount0In, amount1In, amount0Out, amount1Out, to); } // force balances to match reserves function skim(address to) external lock { address _token0 = token0; // gas savings address _token1 = token1; // gas savings _safeTransfer(_token0, to, IERC20(_token0).balanceOf(address(this)).sub(reserve0)); _safeTransfer(_token1, to, IERC20(_token1).balanceOf(address(this)).sub(reserve1)); } // force reserves to match balances function sync() external lock { _update(IERC20(token0).balanceOf(address(this)), IERC20(token1).balanceOf(address(this)), reserve0, reserve1); } }