
In most applications you do not need that. uint(-1) : liquidity; IUniswapV2Pair(pair).permit(msg.sender, address(this), value, deadline, v, r, s); (amountA, amountB) = removeLiquidity(tokenA, tokenB, liquidity, amountAMin, amountBMin, to, deadline); ) external virtual override returns (uint amountToken, uint amountETH) {. mapping(address => mapping(address => address)) public getPair; event PairCreated(address indexed token0, address indexed token1, address pair, uint); constructor(address _feeToSetter) public {, function allPairsLength() external view returns (uint) {, function createPair(address tokenA, address tokenB) external returns (address pair) {. This is the flow of data and control that happens when you perform the three main actions of Uniswap: This is most common flow, used by traders: These are the secure contracts which hold the liquidity. If the time elapsed is not zero, it means we are the first exchange transaction on this block. A trader sells 24.695 A tokens and gets 25.305 B tokens. Send the output tokens to the destination. The one exception is IWETH.sol. Pairs act as automated market makers, standing ready to accept one token for the other as long as the constant product formula is preserved. (reserve0, reserve1) : (reserve1, reserve0); amountInput = IERC20(input).balanceOf(address(pair)).sub(reserveInput); amountOutput = UniswapV2Library.getAmountOut(amountInput, reserveInput, reserveOutput); (uint amount0Out, uint amount1Out) = input == token0 ? This is also where we ensure a fee of 0.3% is being sent on the swap; before sanity checking the value of K, we multiply both balances by 1000 subtracted by the amounts multiplied by 3, this means 0.3% (3/1000 = 0.003 = 0.3%) is being deducted from the balance before comparing its K value with the current reserves K value. This modifier makes sure that time limited transactions ("do X before time Y if you can") don't happen after their time limit. Read the fee destination of the factory. This is supposed to be identical value for both tokens, so the same ratio of new tokens to existing tokens. Only the WETH contract we use is authorized to do that. Download a redacted 28-page sample report on illicit funds in a liquidity pool below. This function implements ERC-20's transferFrom functionality, which allows an account to spend out the allowance provided by a different account. The proportion of the pool's liquidity provided determines the number of liquidity tokens the provider receives. Whether it is the initial deposit or a subsequent one, the number of liquidity tokens we provide is equal to the square root of the change in reserve0*reserve1 and the value of the liquidity token doesn't change (unless we get a deposit that doesn't have equal values of both types, in which case the "fine" gets distributed). This way we don't change the exchange rate. The liquidity providers provide the pool with the two tokens that can be exchanged (we'll call them Token0 and Token1). If x=1, they are equal in value and you deposit a thousand of each. A function parameter in solidity can be stored either in memory or the calldata. Because the parameters to _mintFee are the old reserve values, the fee is calculated accurately based only on pool changes due to fees. This function gives you the amount of token B you'll get in return for token A if there is no fee involved. By having an unlocked variable as part of the contract, we can prevent functions from being called while they are running (within the same transaction). Get the expected out amounts, sorted the way the pair exchange expects them to be. // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"); bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9; keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'), function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {. The second variable, allPairs, is an array that includes all the addresses of pair exchanges created by this factory. require(path[0] == WETH, 'UniswapV2Router: INVALID_PATH'); amounts = UniswapV2Library.getAmountsOut(factory, msg.value, path); IWETH(WETH).deposit{value: amounts[0]}(); assert(IWETH(WETH).transfer(UniswapV2Library.pairFor(factory, path[0], path[1]), amounts[0])); function swapTokensForExactETH(uint amountOut, uint amountInMax, address[] calldata path, address to, uint deadline).

These are the minimum acceptable amounts to deposit. This formula has the desirable property that larger trades (relative to reserves) execute at exponentially worse rates than smaller ones. Now go and write something useful and amaze us. If any of those questions are not satisfied then think again. Large liquidity pools are better than small ones, because they have more stable prices. These functions relay meta-transactions to allow users without ether to withdraw from the pool, using the permit mechanism. This token amount is the remaining 50% of total value a liquidity provider wishes to deposit. emit PairCreated(token0, token1, pair, allPairs.length); function setFeeTo(address _feeTo) external {. You do not need permission from Uniswap to create a new pair exchange. We know that between the time kLast was calculated and the present no liquidity was added or removed (because we run this calculation every time liquidity is added or removed, before it actually changes), so any change in reserve0 * reserve1 has to come from transaction fees (without them we'd keep reserve0 * reserve1 constant). Call the initialize function to tell the new exchange what two tokens it exchanges. This event is emitted when a new pair exchange is created. This is in contrast with the longest liquidity pool on Uniswap V2 being 591 days. Each cost accumulator is updated with the latest cost (reserve of the other token/reserve of this token) times the elapsed time in seconds. All the extra functionality required by traders can then be provided by periphery contracts. If the exchange rate is bad there is a profitable arbitrage opportunity that will correct the price. amounts = UniswapV2Library.getAmountsIn(factory, amountOut, path); require(amounts[0] <= amountInMax, 'UniswapV2Router: EXCESSIVE_INPUT_AMOUNT'); function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline). This function calculates the amount after the exchange fee. require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT'); require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: 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(uint amountIn, uint reserveIn, uint reserveOut) internal pure returns (uint amountOut) {. There is a minimum amount of each token the liquidity provider agrees to accept, and it must happen before the deadline. (with the TMPL quickly becoming worthless and now trading at USD 0.00). (address input, address output) = (path[i], path[i + 1]); (address token0,) = UniswapV2Library.sortTokens(input, output); (uint amount0Out, uint amount1Out) = input == token0 ? To avoid cases of division by zero, there is a minimum number of liquidity tokens that always exist (but are owned by account zero). If we neglect trading fees, we have the following: In other words, the number of tokens a trader receives for their ETH and vice versa is calculated such that after the trade, the product of the two liquidity pools is the same as it was before the trade. While order books are foundational to finance and work great for certain usecases, they suffer from a few important limitations that are especially magnified when applied to a decentralized or blockchain-native setting. For the first liquidity provider, max_tokens is the exact amount of tokens deposited. In a modifier _; is the original function call (with all the parameters). Transfer fee tokens are pretty rare, so while we need to accommodate them there's no need to all swaps to assume they go through at least one of them. These four variants all involve trading between ETH and tokens. The first USDT has had nearly 20 million addresses interacting with it. (address token0, address token1) = sortTokens(tokenA, tokenB); pair = address(uint(keccak256(abi.encodePacked(. Using the equations above, we can derive a formula for the size of the impermanent loss in terms of the price ratio between when liquidity was supplied and now. In Uniswap 2.0 traders pay a 0.30% fee to use the market. Because the amount supplied is equal to 10% of the total liquidity, the contract mints and sends the market maker liquidity tokens which entitle them to 10% of the liquidity available in the pool. Update reserve0 and reserve1, and if necessary the price accumulators and the timestamp and emit an event. address feeTo = IUniswapV2Factory(factory).feeTo(); uint rootK = Math.sqrt(uint(_reserve0).mul(_reserve1)); uint numerator = totalSupply.mul(rootK.sub(rootKLast)); uint denominator = rootK.mul(5).add(rootKLast); uint liquidity = numerator / denominator; if (liquidity > 0) _mint(feeTo, liquidity); // 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. Ajuda'ns a traduir aquest contingut. It is easier to first learn v2 and then go to v3. Withdrawing the 10% that we are entitled to would now yield 12,240 DAI and 81.7 ETH. In either case, the amounts of token0 and token1 that are deposited or withdrawn are part of the event, as well as the identity of the account that called us (sender). It looks quite simple. This function is called when we redeem tokens from the WETH contract back into ETH. Love podcasts or audiobooks? We don't want to have more than a single liquidity pool per pair of tokens. This creates points of control and adds additional layers of complexity. To see how to pool tokens in a smart contract read. require(tokenA != tokenB, 'UniswapV2Library: IDENTICAL_ADDRESSES'); (token0, token1) = tokenA < tokenB ? Note that in the current version of Yul you have to use chainid(), not chainid. However, the desired amount is a maximum, so we cannot do that. If it is already zero revert the call, make it fail. We can call a different contract in one of two ways: For the sake of backwards compatibility with token that were created prior to the ERC-20 standard, an ERC-20 call can fail either by reverting (in which case success is false) or by being successful and returning a false value (in which case there is output data, and if you decode it as a boolean you get false). Uniswap is an automated liquidity protocol powered by a constant product formula Luckily, the periphery contracts are stateless and don't hold any assets, so it is easy to deprecate it and suggest people use the replacement, UniswapV2Router02, instead. Update the state variables (reserve0, reserve1, and if needed kLast) and emit the appropriate event. It is used to transfer ERC-20 tokens in the two token accounts. The liquidity providers get their cut simply by the appreciation of their liquidity tokens. If either balance0 or balance1 (uint256) is higher than uint112(-1) (=2^112-1) (so it overflows & wraps back to 0 when converted to uint112) refuse to continue the _update to prevent overflows.

This formula, most simply expressed as x * y = k, states that trades must not change the product (k) of a pairs reserve balances (x and y). This gives users the confidence that nobody would be able to change them to point to less honest contracts. and implemented in a system of non-upgradeable smart contracts on the Ethereum blockchain. There is a risk of losing money during large and sustained movement in the underlying asset price compared to simply holding an asset. After the main function returns, release the lock. abi.encodePacked() is the message we expect to get. These functions will remove liquidity and pay back the liquidity provider. bytes memory bytecode = type(UniswapV2Pair).creationCode; bytes32 salt = keccak256(abi.encodePacked(token0, token1)); pair := create2(0, add(bytecode, 32), mload(bytecode), salt). import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; // 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) {. We assume that the two represent the same amount of value, and therefore each token0 is worth reserve1/reserve0 token1's. Same as in addLiquidity, deadline is used to set a time after which a transaction can no longer be executed. They are available for external calls, either from other contracts or decentralized applications. deadline is a time limit on the transaction, We calculate the amounts to actually deposit and then find the address of the liquidity pool. This is no longer an issue, because Solidity now supports CREATE2. Sort the two tokens by address, so we'll be able to get the address of the pair exchange for them. Calculate the amount to be purchased in each swap. Organitzacions autonomes decentralitzades (DAO), Seguretat i prevenci d'estafes a Ethereum, No s'han trobat resultats per a la teva cerca. Putting it all together we get this graph. The square roots of one, two, and three are roughly one (we use integers, so we ignore the fraction). address public immutable override factory; require(deadline >= block.timestamp, 'UniswapV2Router: EXPIRED'); constructor(address _factory, address _WETH) public {, assert(msg.sender == WETH); // only accept ETH via fallback from the WETH contract, ) internal virtual returns (uint amountA, uint amountB) {, // create the pair if it doesn't exist yet, if (IUniswapV2Factory(factory).getPair(tokenA, tokenB) == address(0)) {. But the protocol fee requires new liquidity tokens to be minted and provided to the feeTo address. They can never to redeemed, which means the pool will never be emptied completely (this saves us from division by zero in some places). -->, https://medium.com/@pintail/uniswap-a-good-deal-for-liquidity-providers-104c0b6816f2. In return, they receive a third token that represents partial ownership of the pool called a liquidity token. ", "Of course, if the price were to return to the same value as when the liquidity provider added their liquidity, this loss would disappear. Whenever liquidity is deposited into a pool, unique tokens known as liquidity tokens are minted and sent to the provider's address. These are all the interfaces that the contract needs to know about, either because the contract implements them (IUniswapV2Pair and UniswapV2ERC20) or because it calls contracts that implement them. 16 Great Chapel St, London, W1F 8FL, United Kingdom, VAT No. (tokenA, tokenB) : (tokenB, tokenA); require(token0 != address(0), 'UniswapV2: ZERO_ADDRESS'); require(getPair[token0][token1] == address(0), 'UniswapV2: PAIR_EXISTS'); // single check is sufficient. You send this contract ETH, and it mints you an equivalent amount of WETH. Imagine, for example, three tokens, A, B, and C. There are three pair exchanges, one for each pair. However, fractions are not supported by the EVM. Basically, there are two types of users: liquidity providers and traders. This function does the reverse swap, it lets a trader specify the number of output tokens he wants, and the maximum number of input tokens he is willing to pay for them. Calculate the domain separator for EIP-712. The quote function above works great if there is no fee to use the pair exchange. To see why, consider the case where the first liquidity provider deposits tokens at a ratio different from the current market rate. As explained above, this is an array because you might need to go through several pair exchanges to get from the asset you have to the asset you want. Learn on the go with our new app. This is the ABI selector for the ERC-20 transfer function. Liquidity is typically represented by discrete orders placed by individuals onto a centrally operated order book. Dividing this amount by the total liquidity token supply gives the percentage of both the ETH and ER20 reserves the provider is withdrawing. This limits the "free option" problem, where Ethereum miners can hold signed transactions and execute them based off market movements. This implies a price of 1 ETH = 100 DAI. Its difficult to know what the trade-off is between revenues from fees and losses from directional movements without knowing the amount of in-between trades. Since exchange rate can change between when a transaction is signed and when it is executed on Ethereum, max_tokens is used to bound the amount this rate can fluctuate. When a pool contract is created, its balances of each token are 0; in order for the pool to begin facilitating trades, someone must seed it with an initial deposit of each token. Each Uniswap smart contract, or pair, manages a liquidity pool made up of reserves of two ERC-20 tokens. As liquidity tokens are themselves tradable assets, liquidity providers may sell, transfer, or otherwise use their liquidity tokens in any way they see fit. So our liquidity provider lost out by 0.91 DAI by providing liquidity to Uniswap instead of just holding onto their initial ETH and DAI. This is the average across two minutes (120 seconds). This contract has problems, and should no longer be used. The first one, getPair, is a mapping that identifies a pair exchange contract based on the two ERC-20 tokens it exchanges. _swapSupportingFeeOnTransferTokens(path, address(this)); uint amountOut = IERC20(WETH).balanceOf(address(this)); require(amountOut >= amountOutMin, 'UniswapV2Router: INSUFFICIENT_OUTPUT_AMOUNT'); TransferHelper.safeTransferETH(to, amountOut); function quote(uint amountA, uint reserveA, uint reserveB) public pure virtual override returns (uint amountB) {. Liquidity tokens are minted to track the relative proportion of total reserves that each liquidity provider has contributed. This internal function transfers an amount of ERC20 tokens from the exchange to somebody else. It is somewhat cheaper in gas terms than reading a value and never using it. TransferHelper.safeTransfer(token, to, IERC20(token).balanceOf(address(this))); function removeLiquidityETHWithPermitSupportingFeeOnTransferTokens(, ) external virtual override returns (uint amountETH) {, amountETH = removeLiquidityETHSupportingFeeOnTransferTokens(, token, liquidity, amountTokenMin, amountETHMin, to, deadline, // 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 {. require(msg.sender == feeToSetter, 'UniswapV2: FORBIDDEN'); function setFeeToSetter(address _feeToSetter) external {. Uniswap focuses on the strengths of Ethereum to reimagine token swaps from first principles. The periphery contracts are the API (application program interface) for Uniswap. Every swap function accepts a. This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply. Is there a whitepaper that is unique with specific benchmarks and goals? It obviates the need for trusted intermediaries, prioritizing decentralization, censorship resistance, it the better. They are also the maximum amounts of A and B to be deposited. Uniswap liquidity pools are autonomous and use the Constant Product Market Maker (x * y = k). The ETH reserve associated with an ERC20 token exchange is the ETH balance of the exchange smart contract. Use the UniswapV2ERC20._mint function to actually create the additional liquidity tokens and assign them to feeTo. The user has already sent us the ETH, so if there is any extra left over (because the other token is less valuable than the user thought), we need to issue a refund. This contract implements the actual pool that exchanges tokens. By time: 590 days, 19 hours and 54 minutes. Each storage cell is 256 bits long. This parameter contains the addresses of the ERC-20 contracts. This contract inherits from UniswapV2ERC20, which provides the the ERC-20 functions for the liquidity tokens. require(deadline >= block.timestamp, 'UniswapV2: EXPIRED'); keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline)). (uint reserve0, uint reserve1,) = pair.getReserves(); (uint reserveInput, uint reserveOutput) = input == token0 ? Uniswap v2 allows exchanges for any pair of ERC-20 tokens, but ether (ETH) itself isn't an ERC-20 token. That number is MINIMUM_LIQUIDITY, a thousand. It changes when a liquidity provider deposits or withdraws tokens, and it increases slightly because of the 0.3% market fee. This hash is the identifier for the transaction type. In both cases, the trader has to give this periphery contract first an allowance to allow it to transfer them. Don't accept transactions after the deadline. Provide the periphery account with an allowance in the amount to be swapped. If the function is called internally, as _swap above, then the parameters have to be stored in memory. Uniswap is open-source software licensed under the It should be called from a periphery contract that calls it after adding the liquidity in the same transaction (so nobody else would be able to submit a transaction that claims the new liquidity before the legitimate owner). The rug pull withdrew liquidity of 154 ETH & 2,926,099 TMPL tokens. Liquidity is withdrawn at the same ratio as the reserves at the time of withdrawal. If the function is an entry point to the contract, called directly from a user (using a transaction) or from a different contract, then the parameter's value can be taken directly from the call data. The simplest case of removing liquidity. It is OK to do the transfer first and then verify it is legitimate, because if it isn't we'll revert out of all the state changes. At the current price then, our liquidity is worth a total of 219.09 DAI. A participant looking to provide liquidity or make markets must actively manage their orders, continuously updating them in response to the activity of others in the marketplace. The contract handles wrapping the ETH for the liquidity provider. When this code was written that opcode was not yet supported by Solidity, so it was necessary to manually get the code. This function can be called by a transaction to deposit liquidity. The feeTo address accumulates the liquidity tokens for the protocol fee, and feeToSetter is the address allowed to change feeTo to a different address. You can see the square root function later in this article. Those are in the periphery so they can be updated as needed. Transactions on Ethereum cost ether (ETH), which is equivalent to real money. This price calculation is the reason we need to know the old reserve sizes. In that case the return value buffer has a non-zero length, and when decoded as a boolean value it is. This contract implements the ERC-20 liquidity token. Uniswap incentivizes users to add liquidity to trading pools by rewarding providers with the fees generated when other users trade with those pools. . kLast is this value. To have your token traded on Uniswap V2, a token creator must create a liquidity pool. Actually call the pair exchange to swap the tokens. This function is called every time tokens are deposited or withdrawn. Use an interface definition to create a function call. Notice that Solidity functions can return multiple values. In the time of the first deposit we don't know the relative value of the two tokens, so we just multiply the amounts and take a square root, assuming that the deposit provides us with equal value in both tokens. Every pool is an exchange between two ERC-20 tokens, the factory is a central point that connects all of these pools. This is the internal function to swap tokens that have transfer or storage fees to solve (this issue). This function does roughly the same thing, but it gets the output amount and provides the input. We want the address of the new exchange to be deterministic, so it can be calculated in advance off chain (this can be useful for layer 2 transactions). Again, the sender and the destination may not be the same. Each Uniswap liquidity pool is a trading venue for a pair of ERC20 tokens. These are the addresses of the ERC-20 token contracts. uint public constant MINIMUM_LIQUIDITY = 10**3; bytes4 private constant SELECTOR = bytes4(keccak256(bytes('transfer(address,uint256)'))); 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 kLast; // reserve0 * reserve1, as of immediately after the most recent liquidity event. From the perspective of the called contract calldata is read only. The periphery contract sends us the tokens before calling us for the swap. If you made it here, congratulations! (uint reserveIn, uint reserveOut) = getReserves(factory, path[i - 1], path[i]); amounts[i - 1] = getAmountIn(amounts[i], reserveIn, reserveOut); // SPDX-License-Identifier: GPL-3.0-or-later, // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false. The SafeMath library is used to avoid overflows and underflows. Consider the case where a liquidity provider adds 10,000 DAI and 100 WETH to a pool (for a total value of $20,000), the liquidity pool is now 100,000 DAI and 1,000 ETH in total. However, it is trivial to send the same transaction twice (this is a form of replay attack). balance1 - (_reserve1 - amount1Out) : 0; require(amount0In > 0 || amount1In > 0, 'UniswapV2: INSUFFICIENT_INPUT_AMOUNT'); { // scope for reserve{0,1}Adjusted, avoids stack too deep errors. For instance, It is being used by Uniswap, an active decentralized cryptocurrency exchange on Ethereum. Since liquidity providers must deposit at the current exchange rate, the Uniswap smart contracts use ethAmount to determine the amount of ERC20 tokens that must be deposited.

Access to storage is a lot more expensive than access to the volatile memory that is released when the function call to the contract ends, so we use an internal variable to save on gas. require(unlocked == 1, 'UniswapV2: LOCKED'); function getReserves() public view returns (uint112 _reserve0, uint112 _reserve1, uint32 _blockTimestampLast) {. This is the function that implements the permissions. keccak256(abi.encodePacked(token0, token1)), hex'96e8ac4277198ff8b6f785478aa9a39f403cb768dd02cbee326c3e7da348845f' // init code hash, // fetches and sorts the reserves for a pair, function getReserves(address factory, address tokenA, address tokenB) internal view returns (uint reserveA, uint reserveB) {. This is a sanity check to make sure we don't lose from the swap. This complicated calculation of fees is explained in the whitepaper on page 5. return UniswapV2Library.quote(amountA, reserveA, reserveB); function getAmountOut(uint amountIn, uint reserveIn, uint reserveOut). Hopefully by now you've understood the considerations in writing a real-life application (as opposed to short sample programs) and are better to be able to write contracts for your own use cases. Coinfirm has developed reports for liquidity pools specially tailored to financial institutions and large liquidity providers, to enable them to leverage the yields of DeFi whilst being able to mitigate regulatory risk. It is similar to the OpenWhisk ERC-20 contract, so I will only explain the part that is different, the permit functionality. If not, send it to the next pair exchange. If unlocked is equal to one, set it to zero. address recoveredAddress = ecrecover(digest, v, r, s); require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE'); import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Factory.sol'; import '@uniswap/lib/contracts/libraries/TransferHelper.sol'; import './interfaces/IUniswapV2Router02.sol'; import './libraries/UniswapV2Library.sol'; contract UniswapV2Router02 is IUniswapV2Router02 {. If x=2, A is twice the value of B (you get two B tokens for each A token) so you deposit a thousand B tokens, but only 500 A tokens.
Grammarly Essay Check,
Nebraska Psychology License,
Capitalist Ethics Example,
Definition Of Cheap Labour,
Does Cotton Stretch With Wear,