Transaction Hash:
Block:
18259821 at Oct-02-2023 02:20:11 AM +UTC
Transaction Fee:
0.00055329988058787 ETH
$1.33
Gas Used:
76,570 Gas / 7.226066091 Gwei
Emitted Events:
128 |
UniswapV2Pair.Transfer( from=[Receiver] StakeTools, to=[Sender] 0xe5510793bb31300d6a6a2af4fdd10f0b03f30789, value=60262033218465706 )
|
129 |
StakeTools.OnWithdrawal( sender=[Sender] 0xe5510793bb31300d6a6a2af4fdd10f0b03f30789, amount=60262033218465706 )
|
Account State Difference:
Address | Before | After | State Difference | ||
---|---|---|---|---|---|
0x9768E642...76b64D288 | (Blocktools: Staking) | ||||
0xDaE6d966...FDc51971A | |||||
0xDAFEA492...692c98Bc5
Miner
| (Flashbots: Builder) | 1.397281694649183237 Eth | 1.397358264649183237 Eth | 0.00007657 | |
0xE5510793...b03F30789 |
0.011810070663619888 Eth
Nonce: 52
|
0.011256770783032018 Eth
Nonce: 53
| 0.00055329988058787 |
Execution Trace
StakeTools.CALL( )
-
UniswapV2Pair.balanceOf( 0x9768E642A7Dc053cda11e8F3362C5E276b64D288 ) => ( 133915629374368236813 )
-
UniswapV2Pair.balanceOf( 0x9768E642A7Dc053cda11e8F3362C5E276b64D288 ) => ( 133915629374368236813 )
-
UniswapV2Pair.transfer( to=0xE5510793bb31300D6a6A2aF4FDD10f0b03F30789, value=60262033218465706 ) => ( True )
File 1 of 2: StakeTools
File 2 of 2: UniswapV2Pair
//SPDX-License-Identifier: MIT // Decentralized LP Distribution Stake for Blocktools.org // Please refer to Blockpaper.Blocktools.org pragma solidity ^0.8.0; interface IERC20 { function transfer(address to, uint tokens) external returns (bool success); function transferFrom(address from, address to, uint tokens) external returns (bool success); function balanceOf(address tokenOwner) external view returns (uint balance); function approve(address spender, uint tokens) external returns (bool success); function allowance(address tokenOwner, address spender) external view returns (uint remaining); function totalSupply() external view returns (uint); event Transfer(address indexed from, address indexed to, uint tokens); event Approval(address indexed tokenOwner, address indexed spender, uint tokens); } library SafeMath { function add(uint a, uint b) internal pure returns (uint c) { c = a + b; require(c >= a); } function sub(uint a, uint b) internal pure returns (uint c) { require(b <= a); c = a - b; } function mul(uint a, uint b) internal pure returns (uint c) { c = a * b; require(a == 0 || c / a == b); } function div(uint a, uint b) internal pure returns (uint c) { require(b > 0); c = a / b; } function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } } contract Owned { address public owner; event OwnershipTransferred(address indexed _from, address indexed _to); constructor() { owner = msg.sender; } modifier onlyOwner { require(msg.sender == owner); _; } function transferOwnership(address _newOwner) public onlyOwner { owner = _newOwner; emit OwnershipTransferred(owner, _newOwner); } } contract StakeTools is Owned { using SafeMath for uint; address public BLOCKTOOLS; address public TOOLS_LP; uint public feeOnUnstake; uint public feeOnStake; uint public minimumStake; uint public totalStaked; bool public active = true; mapping(address => uint) public referralCount; mapping(address => uint) public referralRewards; mapping(address => uint) public stakes; mapping(address => uint) public stakeRewards; mapping(address => uint) private lastClock; event OnWithdrawal(address sender, uint amount); event OnStake(address sender, uint amount, uint tax); event OnUnstake(address sender, uint amount, uint tax); constructor( address _tools, address _toolsLP, uint _feeOnStake, uint _feeOnUnstake, uint _minimumStake) { BLOCKTOOLS = _tools; TOOLS_LP = _toolsLP; feeOnStake = _feeOnStake; feeOnUnstake = _feeOnUnstake; minimumStake = _minimumStake; } modifier whenActive() { require(active == true, "Staking yet to open"); _; } function checkEarnings(address _stakeholder) public view returns (uint) { uint activeDays = (block.timestamp.sub(lastClock[_stakeholder])).div(86400); uint toolsLPBalance = IERC20(TOOLS_LP).balanceOf(address(this)); uint rewards = 0; uint stakeAmount = stakes[_stakeholder].div(10**18); if (stakeAmount >= 1200) { rewards = toolsLPBalance.mul(5).mul(activeDays).mul(35).div(100000); } else if (stakeAmount >= 701) { rewards = toolsLPBalance.mul(5).mul(activeDays).mul(25).div(100000); } else if (stakeAmount >= 351) { rewards = toolsLPBalance.mul(5).mul(activeDays).mul(20).div(100000); } else if (stakeAmount >= 151) { rewards = toolsLPBalance.mul(5).mul(activeDays).mul(10).div(100000); } else if (stakeAmount >= 51) { rewards = toolsLPBalance.mul(5).mul(activeDays).mul(7).div(100000); } else if (stakeAmount >= 1) { rewards = toolsLPBalance.mul(5).mul(activeDays).mul(3).div(100000); } return rewards; } function stakeTools(uint _amount) external { require(_amount >= minimumStake, "Check minimum stake"); require(IERC20(BLOCKTOOLS).balanceOf(msg.sender) >= _amount, "Insufficient TOOLS Balance"); require(IERC20(BLOCKTOOLS).transferFrom(msg.sender, address(this), _amount), "Staking Failed"); uint stakingTax = (feeOnStake.mul(_amount)).div(1000); uint afterTax = _amount.sub(stakingTax); totalStaked = totalStaked.add(afterTax); stakeRewards[msg.sender] = (stakeRewards[msg.sender]).add(checkEarnings(msg.sender)); uint remainder = (block.timestamp.sub(lastClock[msg.sender])).mod(86400); lastClock[msg.sender] = block.timestamp.sub(remainder); stakes[msg.sender] = (stakes[msg.sender]).add(afterTax); emit OnStake(msg.sender, afterTax, stakingTax); } function unstakeTools(uint _amount) external { require(_amount <= stakes[msg.sender] && _amount > 0, "Not enough TOOLS"); uint unstakingTax = (feeOnUnstake.mul(_amount)).div(1000); uint afterTax = _amount.sub(unstakingTax); stakeRewards[msg.sender] = (stakeRewards[msg.sender]).add(checkEarnings(msg.sender)); stakes[msg.sender] = (stakes[msg.sender]).sub(_amount); uint remainder = (block.timestamp.sub(lastClock[msg.sender])).mod(86400); lastClock[msg.sender] = block.timestamp.sub(remainder); totalStaked = totalStaked.sub(_amount); IERC20(BLOCKTOOLS).transfer(msg.sender, afterTax); emit OnUnstake(msg.sender, _amount, unstakingTax); } function claimEarnings() external returns (bool success) { uint totalReward = (referralRewards[msg.sender]).add(stakeRewards[msg.sender]).add(checkEarnings(msg.sender)); require((block.timestamp - lastClock[msg.sender]) >= 86400, "Minimum claim time not reached"); require(totalReward > 0, "No rewards to claim"); require(IERC20(TOOLS_LP).balanceOf(address(this)) >= totalReward, "Not enough Tokens in Pool"); stakeRewards[msg.sender] = 0; referralRewards[msg.sender] = 0; referralCount[msg.sender] = 0; uint remainder = (block.timestamp.sub(lastClock[msg.sender])).mod(86400); lastClock[msg.sender] = block.timestamp.sub(remainder); IERC20(TOOLS_LP).transfer(msg.sender, totalReward); emit OnWithdrawal(msg.sender, totalReward); return true; } function rewardPool() external view returns (uint) { return IERC20(TOOLS_LP).balanceOf(address(this)); } function changePoolStatus() external onlyOwner() { if(active) { active = false; } else { active = true; } } function setFeeOnStake(uint _feeOnStake) external onlyOwner() { feeOnStake = _feeOnStake; } function setFeeOnUnstake(uint _feeOnUnstake) external onlyOwner() { feeOnUnstake = _feeOnUnstake; } function setMinimumStake(uint _minimumStake) external onlyOwner() { minimumStake = _minimumStake; } function rescueTools(uint _amount) external onlyOwner returns (bool success) { require((IERC20(BLOCKTOOLS).balanceOf(address(this))).sub(totalStaked) >= _amount, "Not enough Tools"); IERC20(BLOCKTOOLS).transfer(msg.sender, _amount); emit OnWithdrawal(msg.sender, _amount); return true; } function rescueLP(uint _amount) external onlyOwner returns (bool success) { require(IERC20(TOOLS_LP).balanceOf(address(this)) >= _amount, "Not enough LP"); IERC20(TOOLS_LP).transfer(msg.sender, _amount); emit OnWithdrawal(msg.sender, _amount); return true; } }
File 2 of 2: UniswapV2Pair
// File: contracts/interfaces/IUniswapV2Pair.sol pragma solidity >=0.5.0; interface IUniswapV2Pair { 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; } // File: contracts/interfaces/IUniswapV2ERC20.sol pragma solidity >=0.5.0; interface IUniswapV2ERC20 { 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; } // File: contracts/libraries/SafeMath.sol 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'); } } // File: contracts/UniswapV2ERC20.sol pragma solidity =0.5.16; contract UniswapV2ERC20 is IUniswapV2ERC20 { using SafeMath for uint; string public constant name = 'Uniswap V2'; string public constant symbol = 'UNI-V2'; 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); 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 { require(deadline >= block.timestamp, 'UniswapV2: 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, 'UniswapV2: INVALID_SIGNATURE'); _approve(owner, spender, value); } } // File: contracts/libraries/Math.sol 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; } } } // File: contracts/libraries/UQ112x112.sol 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); } } // File: contracts/interfaces/IERC20.sol 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); } // File: contracts/interfaces/IUniswapV2Factory.sol pragma solidity >=0.5.0; interface IUniswapV2Factory { 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; } // File: contracts/interfaces/IUniswapV2Callee.sol pragma solidity >=0.5.0; interface IUniswapV2Callee { function uniswapV2Call(address sender, uint amount0, uint amount1, bytes calldata data) external; } // File: contracts/UniswapV2Pair.sol pragma solidity =0.5.16; contract UniswapV2Pair is IUniswapV2Pair, UniswapV2ERC20 { 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; 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, 'UniswapV2: 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))), 'UniswapV2: 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, 'UniswapV2: 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), 'UniswapV2: 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 1/6th of the growth in sqrt(k) function _mintFee(uint112 _reserve0, uint112 _reserve1) private returns (bool feeOn) { address feeTo = IUniswapV2Factory(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 = rootK.mul(5).add(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, 'UniswapV2: 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, 'UniswapV2: 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, 'UniswapV2: INSUFFICIENT_OUTPUT_AMOUNT'); (uint112 _reserve0, uint112 _reserve1,) = getReserves(); // gas savings require(amount0Out < _reserve0 && amount1Out < _reserve1, 'UniswapV2: 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, 'UniswapV2: 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) IUniswapV2Callee(to).uniswapV2Call(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, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT'); { // scope for reserve{0,1}Adjusted, avoids stack too deep errors uint balance0Adjusted = balance0.mul(1000).sub(amount0In.mul(3)); uint balance1Adjusted = balance1.mul(1000).sub(amount1In.mul(3)); require(balance0Adjusted.mul(balance1Adjusted) >= uint(_reserve0).mul(_reserve1).mul(1000**2), 'UniswapV2: 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); } }