Contract Overview
Balance:
0 AVAX
AVAX Value:
$0.00
My Name Tag:
Not Available, login to update
Txn Hash | Method |
Block
|
From
|
To
|
Value | [Txn Fee] | |||
---|---|---|---|---|---|---|---|---|---|
0x1894ae99743911464a59661f2b12d39f618d4eb31110bcdc483068fdf355b304 | 0x61459f61 | 16328323 | 231 days 3 hrs ago | Yield Yak: Deployer | IN | Create: SwapUtils | 0 AVAX | 0.128751381 |
[ Download CSV Export ]
Contract Name:
SwapUtils
Compiler Version
v0.8.7+commit.e28d00a7
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity =0.8.7; import "../../interfaces/IgAVAX.sol"; import "./AmplificationUtils.sol"; import "../LPToken.sol"; import "./MathUtils.sol"; /** * @title SwapUtils library * @notice A library to be used within Swap.sol. Contains functions responsible for custody and AMM functionalities. * @dev Contracts relying on this library must initialize SwapUtils.Swap struct then use this library * for SwapUtils.Swap struct. Note that this library contains both functions called by users and admins. * Admin functions should be protected within contracts using this library. */ library SwapUtils { using MathUtils for uint256; /*** EVENTS ***/ event TokenSwap( address indexed buyer, uint256 tokensSold, uint256 tokensBought, uint128 soldId, uint128 boughtId ); event AddLiquidity( address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 invariant, uint256 lpTokenSupply ); event RemoveLiquidity( address indexed provider, uint256[] tokenAmounts, uint256 lpTokenSupply ); event RemoveLiquidityOne( address indexed provider, uint256 lpTokenAmount, uint256 lpTokenSupply, uint256 boughtId, uint256 tokensBought ); event RemoveLiquidityImbalance( address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 invariant, uint256 lpTokenSupply ); event NewAdminFee(uint256 newAdminFee); event NewSwapFee(uint256 newSwapFee); struct Swap { // variables around the ramp management of A, // the amplification coefficient * n * (n - 1) // see https://curve.fi/stableswap-paper.pdf for details uint256 initialA; uint256 futureA; uint256 initialATime; uint256 futureATime; // fee calculation uint256 swapFee; uint256 adminFee; LPToken lpToken; uint256 pooledTokenId; // wETH2 contract reference IgAVAX referenceForPooledTokens; // the pool balance of each token // the contract's actual token balance might differ uint256[] balances; } // Struct storing variables used in calculations in the // calculateWithdrawOneTokenDY function to avoid stack too deep errors struct CalculateWithdrawOneTokenDYInfo { uint256 d0; uint256 d1; uint256 newY; uint256 feePerToken; uint256 preciseA; } // Struct storing variables used in calculations in the // {add,remove}Liquidity functions to avoid stack too deep errors struct ManageLiquidityInfo { uint256 d0; uint256 d1; uint256 d2; uint256 preciseA; LPToken lpToken; uint256 totalSupply; uint256[] balances; } // the precision all pools tokens will be converted to uint8 public constant POOL_PRECISION_DECIMALS = 18; // the denominator used to calculate admin and LP fees. For example, an // LP fee might be something like tradeAmount.mul(fee).div(FEE_DENOMINATOR) uint256 private constant FEE_DENOMINATOR = 10**10; // Max swap fee is 1% or 100bps of each swap uint256 public constant MAX_SWAP_FEE = 10**8; // Max adminFee is 100% of the swapFee // adminFee does not add additional fee on top of swapFee // Instead it takes a certain % of the swapFee. Therefore it has no impact on the // users but only on the earnings of LPs uint256 public constant MAX_ADMIN_FEE = 10**10; // Constant value used as max loop limit uint256 private constant MAX_LOOP_LIMIT = 256; /*** VIEW & PURE FUNCTIONS ***/ function _getAPrecise(Swap storage self) internal view returns (uint256) { return AmplificationUtils._getAPrecise(self); } /// @dev this function assumes prices are sent with the indexes that [avax,Gavax] function _pricedInBatch(Swap storage self, uint256[] memory balances) internal view returns (uint256[] memory) { uint256[] memory _p = new uint256[](balances.length); _p[0] = balances[0]; _p[1] = (balances[1] * IgAVAX(self.referenceForPooledTokens).pricePerShare( self.pooledTokenId )) / 1e18; return _p; } function _pricedOut( Swap storage self, uint256 balance, uint256 i ) internal view returns (uint256) { return i == 1 ? (balance * 1e18) / IgAVAX(self.referenceForPooledTokens).pricePerShare( self.pooledTokenId ) : balance; } function _pricedIn( Swap storage self, uint256 balance, uint256 i ) internal view returns (uint256) { return i == 1 ? (balance * IgAVAX(self.referenceForPooledTokens).pricePerShare( self.pooledTokenId )) / 1e18 : balance; } /// @dev this function assumes prices are sent with the indexes that [avax,Gavax] function _pricedOutBatch(Swap storage self, uint256[] memory balances) internal view returns (uint256[] memory) { uint256[] memory _p = new uint256[](balances.length); _p[0] = balances[0]; _p[1] = (balances[1] * 1e18) / IgAVAX(self.referenceForPooledTokens).pricePerShare(self.pooledTokenId); return _p; } /** * @notice Calculate the dy, the amount of selected token that user receives and * the fee of withdrawing in one token * @param tokenAmount the amount to withdraw in the pool's precision * @param tokenIndex which token will be withdrawn * @param self Swap struct to read from * @return the amount of token user will receive */ function calculateWithdrawOneToken( Swap storage self, uint256 tokenAmount, uint8 tokenIndex ) external view returns (uint256) { (uint256 availableTokenAmount, ) = _calculateWithdrawOneToken( self, tokenAmount, tokenIndex, self.lpToken.totalSupply() ); return availableTokenAmount; } function _calculateWithdrawOneToken( Swap storage self, uint256 tokenAmount, uint8 tokenIndex, uint256 totalSupply ) internal view returns (uint256, uint256) { uint256 dy; uint256 newY; uint256 currentY; (dy, newY, currentY) = calculateWithdrawOneTokenDY( self, tokenIndex, tokenAmount, totalSupply ); // dy_0 (without fees) // dy, dy_0 - dy uint256 dySwapFee = currentY - newY - dy; return (dy, dySwapFee); } /** * @notice Calculate the dy of withdrawing in one token * @param self Swap struct to read from * @param tokenIndex which token will be withdrawn * @param tokenAmount the amount to withdraw in the pools precision * @return the d and the new y after withdrawing one token */ function calculateWithdrawOneTokenDY( Swap storage self, uint8 tokenIndex, uint256 tokenAmount, uint256 totalSupply ) internal view returns ( uint256, uint256, uint256 ) { // Get the current D, then solve the stableswap invariant // y_i for D - tokenAmount require(tokenIndex < 2, "Token index out of range"); CalculateWithdrawOneTokenDYInfo memory v = CalculateWithdrawOneTokenDYInfo( 0, 0, 0, 0, 0 ); v.preciseA = _getAPrecise(self); v.d0 = getD(_pricedInBatch(self, self.balances), v.preciseA); v.d1 = v.d0 - ((tokenAmount * v.d0) / totalSupply); require( tokenAmount <= self.balances[tokenIndex], "Withdraw exceeds available" ); v.newY = _pricedOut( self, getYD(v.preciseA, tokenIndex, _pricedInBatch(self, self.balances), v.d1), tokenIndex ); uint256[] memory xpReduced = new uint256[](2); v.feePerToken = self.swapFee / 2; for (uint256 i = 0; i < 2; i++) { uint256 xpi = self.balances[i]; // if i == tokenIndex, dxExpected = xp[i] * d1 / d0 - newY // else dxExpected = xp[i] - (xp[i] * d1 / d0) // xpReduced[i] -= dxExpected * fee / FEE_DENOMINATOR xpReduced[i] = xpi - ((( (i == tokenIndex) ? (xpi * v.d1) / v.d0 - v.newY : xpi - ((xpi * v.d1) / (v.d0)) ) * (v.feePerToken)) / (FEE_DENOMINATOR)); } uint256 dy = xpReduced[tokenIndex] - _pricedOut( self, (getYD(v.preciseA, tokenIndex, _pricedInBatch(self, xpReduced), v.d1)), tokenIndex ); dy = dy - 1; return (dy, v.newY, self.balances[tokenIndex]); } /** * @notice Get Debt, The amount of buyback for stable pricing. * @param xp a set of pool balances. Array should be the same cardinality * as the pool. * @param a the amplification coefficient * n * (n - 1) in A_PRECISION. * See the StableSwap paper for details * @return debt the half of the D StableSwap invariant when debt is needed to be payed. */ function _getDebt( Swap storage self, uint256[] memory xp, uint256 a ) internal view returns (uint256) { uint256 halfD = getD(xp, a) / 2; if (xp[0] >= halfD) { return 0; } else { uint256 dy = xp[1] - halfD; uint256 feeHalf = (dy * self.swapFee) / FEE_DENOMINATOR / 2; uint256 debt = halfD - xp[0] + feeHalf; return debt; } } /** * @return debt the half of the D StableSwap invariant when debt is needed to be payed. */ function getDebt(Swap storage self) external view returns (uint256) { // might change when price is in. return _getDebt(self, _pricedInBatch(self, self.balances), _getAPrecise(self)); } /** * @notice Calculate the price of a token in the pool with given * balances and a particular D. * * @dev This is accomplished via solving the invariant iteratively. * See the StableSwap paper and Curve.fi implementation for further details. * * x_1**2 + x1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A) * x_1**2 + b*x_1 = c * x_1 = (x_1**2 + c) / (2*x_1 + b) * * @param a the amplification coefficient * n * (n - 1). See the StableSwap paper for details. * @param tokenIndex Index of token we are calculating for. * @param xp a set of pool balances. Array should be * the same cardinality as the pool. * @param d the stableswap invariant * @return the price of the token, in the same precision as in xp */ function getYD( uint256 a, uint8 tokenIndex, uint256[] memory xp, uint256 d ) internal pure returns (uint256) { uint256 numTokens = 2; require(tokenIndex < numTokens, "Token not found"); uint256 c = d; uint256 s; uint256 nA = a * numTokens; for (uint256 i = 0; i < numTokens; i++) { if (i != tokenIndex) { s = s + xp[i]; c = (c * d) / (xp[i] * (numTokens)); // If we were to protect the division loss we would have to keep the denominator separate // and divide at the end. However this leads to overflow with large numTokens or/and D. // c = c * D * D * D * ... overflow! } } c = (c * d * AmplificationUtils.A_PRECISION) / (nA * numTokens); uint256 b = s + ((d * AmplificationUtils.A_PRECISION) / nA); uint256 yPrev; uint256 y = d; for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) { yPrev = y; y = ((y * y) + c) / (2 * y + b - d); if (y.within1(yPrev)) { return y; } } revert("Approximation did not converge"); } /** * @notice Get D, the StableSwap invariant, based on a set of balances and a particular A. * @param xp a set of pool balances. Array should be the same cardinality * as the pool. * @param a the amplification coefficient * n * (n - 1) in A_PRECISION. * See the StableSwap paper for details * @return the invariant, at the precision of the pool */ function getD(uint256[] memory xp, uint256 a) internal pure returns (uint256) { uint256 numTokens = 2; uint256 s = xp[0] + xp[1]; if (s == 0) { return 0; } uint256 prevD; uint256 d = s; uint256 nA = a * numTokens; for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) { uint256 dP = (d**(numTokens + 1)) / (numTokens**numTokens * xp[0] * xp[1]); prevD = d; d = ((((nA * s) / AmplificationUtils.A_PRECISION) + dP * numTokens) * (d)) / (((nA - AmplificationUtils.A_PRECISION) * (d)) / (AmplificationUtils.A_PRECISION) + ((numTokens + 1) * dP)); if (d.within1(prevD)) { return d; } } // Convergence should occur in 4 loops or less. If this is reached, there may be something wrong // with the pool. If this were to occur repeatedly, LPs should withdraw via `removeLiquidity()` // function which does not rely on D. revert("D does not converge"); } /** * @notice Get the virtual price, to help calculate profit * @param self Swap struct to read from * @return the virtual price, scaled to precision of POOL_PRECISION_DECIMALS */ function getVirtualPrice(Swap storage self) external view returns (uint256) { uint256 d = getD(_pricedInBatch(self, self.balances), _getAPrecise(self)); LPToken lpToken = self.lpToken; uint256 supply = lpToken.totalSupply(); if (supply > 0) { return (d * 10**uint256(POOL_PRECISION_DECIMALS)) / supply; } return 0; } /** * @notice Calculate the new balances of the tokens given the indexes of the token * that is swapped from (FROM) and the token that is swapped to (TO). * This function is used as a helper function to calculate how much TO token * the user should receive on swap. * * @param preciseA precise form of amplification coefficient * @param tokenIndexFrom index of FROM token * @param tokenIndexTo index of TO token * @param x the new total amount of FROM token * @param xp balances of the tokens in the pool * @return the amount of TO token that should remain in the pool */ function getY( uint256 preciseA, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 x, uint256[] memory xp ) internal pure returns (uint256) { uint256 numTokens = 2; require(tokenIndexFrom != tokenIndexTo, "Can't compare token to itself"); require( tokenIndexFrom < numTokens && tokenIndexTo < numTokens, "Tokens must be in pool" ); uint256 d = getD(xp, preciseA); uint256 c = d; uint256 s = x; uint256 nA = numTokens * (preciseA); c = (c * d) / (x * numTokens); c = (c * d * (AmplificationUtils.A_PRECISION)) / (nA * numTokens); uint256 b = s + ((d * AmplificationUtils.A_PRECISION) / nA); uint256 yPrev; uint256 y = d; for (uint256 i = 0; i < MAX_LOOP_LIMIT; i++) { yPrev = y; y = ((y * y) + c) / (2 * y + b - d); if (y.within1(yPrev)) { return y; } } revert("Approximation did not converge"); } /** * @notice Externally calculates a swap between two tokens. * @param self Swap struct to read from * @param tokenIndexFrom the token to sell * @param tokenIndexTo the token to buy * @param dx the number of tokens to sell. If the token charges a fee on transfers, * use the amount that gets transferred after the fee. * @return dy the number of tokens the user will get */ function calculateSwap( Swap storage self, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx ) external view returns (uint256 dy) { (dy, ) = _calculateSwap( self, tokenIndexFrom, tokenIndexTo, dx, self.balances ); } /** * @notice Internally calculates a swap between two tokens. * * @dev The caller is expected to transfer the actual amounts (dx and dy) * using the token contracts. * * @param self Swap struct to read from * @param tokenIndexFrom the token to sell * @param tokenIndexTo the token to buy * @param dx the number of tokens to sell. If the token charges a fee on transfers, * use the amount that gets transferred after the fee. * @return dy the number of tokens the user will get * @return dyFee the associated fee */ function _calculateSwap( Swap storage self, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256[] memory balances ) internal view returns (uint256 dy, uint256 dyFee) { require( tokenIndexFrom < balances.length && tokenIndexTo < balances.length, "Token index out of range" ); uint256 x = _pricedIn(self, dx + balances[tokenIndexFrom], tokenIndexFrom); uint256[] memory pricedBalances = _pricedInBatch(self, balances); uint256 y = _pricedOut( self, getY(_getAPrecise(self), tokenIndexFrom, tokenIndexTo, x, pricedBalances), tokenIndexTo // => not id, index !!! ); dy = balances[tokenIndexTo] - y - 1; dyFee = (dy * self.swapFee) / (FEE_DENOMINATOR); dy = dy - dyFee; } /** * @notice A simple method to calculate amount of each underlying * tokens that is returned upon burning given amount of * LP tokens * * @param amount the amount of LP tokens that would to be burned on * withdrawal * @return array of amounts of tokens user will receive */ function calculateRemoveLiquidity(Swap storage self, uint256 amount) external view returns (uint256[] memory) { return _pricedOutBatch( self, _calculateRemoveLiquidity( _pricedInBatch(self, self.balances), amount, self.lpToken.totalSupply() ) ); } function _calculateRemoveLiquidity( uint256[] memory balances, uint256 amount, uint256 totalSupply ) internal pure returns (uint256[] memory) { require(amount <= totalSupply, "Cannot exceed total supply"); uint256[] memory amounts = new uint256[](2); amounts[0] = (balances[0] * amount) / totalSupply; amounts[1] = (balances[1] * amount) / totalSupply; return amounts; } /** * @notice A simple method to calculate prices from deposits or * withdrawals, excluding fees but including slippage. This is * helpful as an input into the various "min" parameters on calls * to fight front-running * * @dev This shouldn't be used outside frontends for user estimates. * * @param self Swap struct to read from * @param amounts an array of token amounts to deposit or withdrawal, * corresponding to pooledTokens. The amount should be in each * pooled token's native precision. If a token charges a fee on transfers, * use the amount that gets transferred after the fee. * @param deposit whether this is a deposit or a withdrawal * @return if deposit was true, total amount of lp token that will be minted and if * deposit was false, total amount of lp token that will be burned */ function calculateTokenAmount( Swap storage self, uint256[] calldata amounts, bool deposit ) external view returns (uint256) { uint256 a = _getAPrecise(self); uint256[] memory balances = self.balances; uint256 d0 = getD(_pricedInBatch(self, balances), a); for (uint256 i = 0; i < balances.length; i++) { if (deposit) { balances[i] = balances[i] + amounts[i]; } else { require( amounts[i] <= balances[i], "Cannot withdraw more than available" ); balances[i] = balances[i] - amounts[i]; } } uint256 d1 = getD(_pricedInBatch(self, balances), a); uint256 totalSupply = self.lpToken.totalSupply(); if (deposit) { return ((d1 - d0) * totalSupply) / d0; } else { return ((d0 - d1) * totalSupply) / d0; } } /** * @notice return accumulated amount of admin fees of the token with given index * @param self Swap struct to read from * @param index Index of the pooled token * @return admin balance in the token's precision */ function getAdminBalance(Swap storage self, uint256 index) external view returns (uint256) { require(index < 2, "Token index out of range"); if (index == 0) return address(this).balance - (self.balances[index]); if (index == 1) return self.referenceForPooledTokens.balanceOf( address(this), self.pooledTokenId ) - (self.balances[index]); return 0; } /*** STATE MODIFYING FUNCTIONS ***/ /** * @notice swap two tokens in the pool * @param self Swap struct to read from and write to * @param tokenIndexFrom the token the user wants to sell * @param tokenIndexTo the token the user wants to buy * @param dx the amount of tokens the user wants to sell * @param minDy the min amount the user would like to receive, or revert. * @return amount of token user received on swap */ function swap( Swap storage self, uint8 tokenIndexFrom, uint8 tokenIndexTo, uint256 dx, uint256 minDy ) external returns (uint256) { IgAVAX wETH2Reference = self.referenceForPooledTokens; if (tokenIndexFrom == 0) { require(dx == msg.value, "Cannot swap more/less than you sent"); } if (tokenIndexFrom == 1) { uint256 tokenId = self.pooledTokenId; require( dx <= wETH2Reference.balanceOf(msg.sender, tokenId), "Cannot swap more than you own" ); // Transfer tokens first uint256 beforeBalance = wETH2Reference.balanceOf(address(this), tokenId); wETH2Reference.safeTransferFrom( msg.sender, address(this), tokenId, dx, "" ); // Use the actual transferred amount for AMM math dx = wETH2Reference.balanceOf(address(this), tokenId) - beforeBalance; } uint256 dy; uint256 dyFee; uint256[] memory balances = self.balances; (dy, dyFee) = _calculateSwap( self, tokenIndexFrom, tokenIndexTo, dx, balances ); require(dy >= minDy, "Swap didn't result in min tokens"); uint256 dyAdminFee = (dyFee * self.adminFee) / FEE_DENOMINATOR; self.balances[tokenIndexFrom] = balances[tokenIndexFrom] + dx; self.balances[tokenIndexTo] = balances[tokenIndexTo] - dy - dyAdminFee; if (tokenIndexTo == 0) { (bool sent, ) = payable(msg.sender).call{ value: dy }(""); require(sent, "SwapUtils: Failed to send Avax"); } if (tokenIndexTo == 1) { wETH2Reference.safeTransferFrom( address(this), msg.sender, self.pooledTokenId, dy, "" ); } emit TokenSwap(msg.sender, dx, dy, tokenIndexFrom, tokenIndexTo); return dy; } /** * @notice Add liquidity to the pool * @param self Swap struct to read from and write to * @param amounts the amounts of each token to add, in their native precision * @param minToMint the minimum LP tokens adding this amount of liquidity * should mint, otherwise revert. Handy for front-running mitigation * allowed addresses. If the pool is not in the guarded launch phase, this parameter will be ignored. * @return amount of LP token user received */ function addLiquidity( Swap storage self, uint256[] memory amounts, uint256 minToMint ) external returns (uint256) { require(amounts.length == 2, "Amounts must match pooled tokens"); require( amounts[0] == msg.value, "SwapUtils: received less or more AVAX than expected" ); IgAVAX wETH2Reference = self.referenceForPooledTokens; // current state ManageLiquidityInfo memory v = ManageLiquidityInfo( 0, 0, 0, _getAPrecise(self), self.lpToken, 0, self.balances ); v.totalSupply = v.lpToken.totalSupply(); if (v.totalSupply != 0) { v.d0 = getD(_pricedInBatch(self, v.balances), v.preciseA); } uint256[] memory newBalances = new uint256[](2); newBalances[0] = v.balances[0] + msg.value; for (uint256 i = 0; i < 2; i++) { require( v.totalSupply != 0 || amounts[i] > 0, "Must supply all tokens in pool" ); } { // Transfer tokens first uint256 beforeBalance = wETH2Reference.balanceOf( address(this), self.pooledTokenId ); wETH2Reference.safeTransferFrom( msg.sender, address(this), self.pooledTokenId, amounts[1], "" ); // Update the amounts[] with actual transfer amount amounts[1] = wETH2Reference.balanceOf(address(this), self.pooledTokenId) - beforeBalance; newBalances[1] = v.balances[1] + amounts[1]; } // invariant after change v.d1 = getD(_pricedInBatch(self, newBalances), v.preciseA); require(v.d1 > v.d0, "D should increase"); // updated to reflect fees and calculate the user's LP tokens v.d2 = v.d1; uint256[] memory fees = new uint256[](2); if (v.totalSupply != 0) { uint256 feePerToken = self.swapFee / 2; for (uint256 i = 0; i < 2; i++) { uint256 idealBalance = (v.d1 * v.balances[i]) / v.d0; fees[i] = (feePerToken * (idealBalance.difference(newBalances[i]))) / (FEE_DENOMINATOR); self.balances[i] = newBalances[i] - ((fees[i] * (self.adminFee)) / (FEE_DENOMINATOR)); newBalances[i] = newBalances[i] - (fees[i]); } v.d2 = getD(_pricedInBatch(self, newBalances), v.preciseA); } else { // the initial depositor doesn't pay fees self.balances = newBalances; } uint256 toMint; if (v.totalSupply == 0) { toMint = v.d1; } else { toMint = ((v.d2 - v.d0) * v.totalSupply) / v.d0; } require(toMint >= minToMint, "Couldn't mint min requested"); // mint the user's LP tokens v.lpToken.mint(msg.sender, toMint); emit AddLiquidity(msg.sender, amounts, fees, v.d1, v.totalSupply + toMint); return toMint; } /** * @notice Burn LP tokens to remove liquidity from the pool. * @dev Liquidity can always be removed, even when the pool is paused. * @param self Swap struct to read from and write to * @param amount the amount of LP tokens to burn * @param minAmounts the minimum amounts of each token in the pool * acceptable for this burn. Useful as a front-running mitigation * @return amounts of tokens the user received */ function removeLiquidity( Swap storage self, uint256 amount, uint256[] calldata minAmounts ) external returns (uint256[] memory) { LPToken lpToken = self.lpToken; IgAVAX wETH2Reference = self.referenceForPooledTokens; require(amount <= lpToken.balanceOf(msg.sender), ">LP.balanceOf"); require(minAmounts.length == 2, "minAmounts must match poolTokens"); uint256[] memory balances = self.balances; uint256 totalSupply = lpToken.totalSupply(); uint256[] memory amounts = _pricedOutBatch( self, _calculateRemoveLiquidity( _pricedInBatch(self, balances), amount, totalSupply ) ); for (uint256 i = 0; i < amounts.length; i++) { require(amounts[i] >= minAmounts[i], "amounts[i] < minAmounts[i]"); self.balances[i] = balances[i] - amounts[i]; } lpToken.burnFrom(msg.sender, amount); (bool sent, ) = payable(msg.sender).call{ value: amounts[0] }(""); require(sent, "SwapUtils: Failed to send Avax"); wETH2Reference.safeTransferFrom( address(this), msg.sender, self.pooledTokenId, amounts[1], "" ); emit RemoveLiquidity(msg.sender, amounts, totalSupply - amount); return amounts; } /** * @notice Remove liquidity from the pool all in one token. * @param self Swap struct to read from and write to * @param tokenAmount the amount of the lp tokens to burn * @param tokenIndex the index of the token you want to receive * @param minAmount the minimum amount to withdraw, otherwise revert * @return amount chosen token that user received */ function removeLiquidityOneToken( Swap storage self, uint256 tokenAmount, uint8 tokenIndex, uint256 minAmount ) external returns (uint256) { LPToken lpToken = self.lpToken; IgAVAX wETH2Reference = self.referenceForPooledTokens; require(tokenAmount <= lpToken.balanceOf(msg.sender), ">LP.balanceOf"); require(tokenIndex < 2, "Token not found"); uint256 totalSupply = lpToken.totalSupply(); (uint256 dy, uint256 dyFee) = _calculateWithdrawOneToken( self, tokenAmount, tokenIndex, totalSupply ); require(dy >= minAmount, "dy < minAmount"); self.balances[tokenIndex] = self.balances[tokenIndex] - (dy + ((dyFee * (self.adminFee)) / (FEE_DENOMINATOR))); lpToken.burnFrom(msg.sender, tokenAmount); if (tokenIndex == 0) { (bool sent, ) = payable(msg.sender).call{ value: dy }(""); require(sent, "SwapUtils: Failed to send Avax"); } if (tokenIndex == 1) { wETH2Reference.safeTransferFrom( address(this), msg.sender, self.pooledTokenId, dy, "" ); } emit RemoveLiquidityOne( msg.sender, tokenAmount, totalSupply, tokenIndex, dy ); return dy; } /** * @notice Remove liquidity from the pool, weighted differently than the * pool's current balances. * * @param self Swap struct to read from and write to * @param amounts how much of each token to withdraw * @param maxBurnAmount the max LP token provider is willing to pay to * remove liquidity. Useful as a front-running mitigation. * @return actual amount of LP tokens burned in the withdrawal */ function removeLiquidityImbalance( Swap storage self, uint256[] memory amounts, uint256 maxBurnAmount ) public returns (uint256) { IgAVAX wETH2Reference = self.referenceForPooledTokens; ManageLiquidityInfo memory v = ManageLiquidityInfo( 0, 0, 0, _getAPrecise(self), self.lpToken, 0, self.balances ); v.totalSupply = v.lpToken.totalSupply(); require(amounts.length == 2, "Amounts should match pool tokens"); require( maxBurnAmount <= v.lpToken.balanceOf(msg.sender) && maxBurnAmount != 0, ">LP.balanceOf" ); uint256 feePerToken = self.swapFee / 2; uint256[] memory fees = new uint256[](2); { uint256[] memory balances1 = new uint256[](2); v.d0 = getD(_pricedInBatch(self, v.balances), v.preciseA); for (uint256 i = 0; i < 2; i++) { require( amounts[i] <= v.balances[i], "Cannot withdraw more than available" ); balances1[i] = v.balances[i] - amounts[i]; } v.d1 = getD(_pricedInBatch(self, balances1), v.preciseA); for (uint256 i = 0; i < 2; i++) { uint256 idealBalance = (v.d1 * v.balances[i]) / v.d0; uint256 difference = idealBalance.difference(balances1[i]); fees[i] = (feePerToken * difference) / FEE_DENOMINATOR; uint256 adminFee = self.adminFee; { self.balances[i] = balances1[i] - ((fees[i] * adminFee) / FEE_DENOMINATOR); } balances1[i] = balances1[i] - fees[i]; } v.d2 = getD(_pricedInBatch(self, balances1), v.preciseA); } uint256 tokenAmount = ((v.d0 - v.d2) * (v.totalSupply)) / v.d0; require(tokenAmount != 0, "Burnt amount cannot be zero"); tokenAmount = tokenAmount + 1; require(tokenAmount <= maxBurnAmount, "tokenAmount > maxBurnAmount"); v.lpToken.burnFrom(msg.sender, tokenAmount); (bool sent, ) = payable(msg.sender).call{ value: amounts[0] }(""); require(sent, "SwapUtils: Failed to send Avax"); wETH2Reference.safeTransferFrom( address(this), msg.sender, self.pooledTokenId, amounts[1], "" ); emit RemoveLiquidityImbalance( msg.sender, amounts, fees, v.d1, v.totalSupply - tokenAmount ); return tokenAmount; } /** * @notice withdraw all admin fees to a given address * @param self Swap struct to withdraw fees from * @param to Address to send the fees to */ function withdrawAdminFees(Swap storage self, address to) external { IgAVAX wETH2Reference = self.referenceForPooledTokens; uint256 tokenBalance = wETH2Reference.balanceOf( address(this), self.pooledTokenId ) - self.balances[1]; if (tokenBalance != 0) { wETH2Reference.safeTransferFrom( address(this), to, self.pooledTokenId, tokenBalance, "" ); } uint256 avaxBalance = address(this).balance - self.balances[0]; if (avaxBalance != 0) { (bool sent, ) = payable(msg.sender).call{ value: avaxBalance }(""); require(sent, "SwapUtils: Failed to send Avax"); } } /** * @notice Sets the admin fee * @dev adminFee cannot be higher than 100% of the swap fee * @param self Swap struct to update * @param newAdminFee new admin fee to be applied on future transactions */ function setAdminFee(Swap storage self, uint256 newAdminFee) external { require(newAdminFee <= MAX_ADMIN_FEE, "Fee is too high"); self.adminFee = newAdminFee; emit NewAdminFee(newAdminFee); } /** * @notice update the swap fee * @dev fee cannot be higher than 1% of each swap * @param self Swap struct to update * @param newSwapFee new swap fee to be applied on future transactions */ function setSwapFee(Swap storage self, uint256 newSwapFee) external { require(newSwapFee <= MAX_SWAP_FEE, "Fee is too high"); self.swapFee = newSwapFee; emit NewSwapFee(newSwapFee); } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.7; interface IgAVAX { function supportsInterface(bytes4 interfaceId) external view returns (bool); function uri(uint256) external view returns (string memory); function balanceOf(address account, uint256 id) external view returns (uint256); function balanceOfBatch(address[] memory accounts, uint256[] memory ids) external view returns (uint256[] memory); function setApprovalForAll(address operator, bool approved) external; function isApprovedForAll(address account, address operator) external view returns (bool); function safeTransferFrom( address from, address to, uint256 id, uint256 amount, bytes memory data ) external; function safeBatchTransferFrom( address from, address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) external; function burn( address account, uint256 id, uint256 value ) external; function burnBatch( address account, uint256[] memory ids, uint256[] memory values ) external; function totalSupply(uint256 id) external view returns (uint256); function exists(uint256 id) external view returns (bool); function mint( address to, uint256 id, uint256 amount, bytes memory data ) external; function mintBatch( address to, uint256[] memory ids, uint256[] memory amounts, bytes memory data ) external; function pause() external; function unpause() external; function pricePerShare(uint256 _id) external view returns (uint256); function setPricePerShare(uint256 pricePerShare_, uint256 _id) external; function isInterface(address operator, uint256 id) external view returns (bool); function setInterface( address _Interface, uint256 _id, bool isSet ) external; }
// SPDX-License-Identifier: MIT pragma solidity =0.8.7; import "./SwapUtils.sol"; /** * @title AmplificationUtils library * @notice A library to calculate and ramp the A parameter of a given `SwapUtils.Swap` struct. * This library assumes the struct is fully validated. */ library AmplificationUtils { event RampA( uint256 oldA, uint256 newA, uint256 initialTime, uint256 futureTime ); event StopRampA(uint256 currentA, uint256 time); // Constant values used in ramping A calculations uint256 public constant A_PRECISION = 100; uint256 public constant MAX_A = 10**6; uint256 private constant MAX_A_CHANGE = 2; uint256 private constant MIN_RAMP_TIME = 14 days; /** * @notice Return A, the amplification coefficient * n * (n - 1) * @dev See the StableSwap paper for details * @param self Swap struct to read from * @return A parameter */ function getA(SwapUtils.Swap storage self) external view returns (uint256) { return _getAPrecise(self) / (A_PRECISION); } /** * @notice Return A in its raw precision * @dev See the StableSwap paper for details * @param self Swap struct to read from * @return A parameter in its raw precision form */ function getAPrecise(SwapUtils.Swap storage self) external view returns (uint256) { return _getAPrecise(self); } /** * @notice Return A in its raw precision * @dev See the StableSwap paper for details * @param self Swap struct to read from * @return A parameter in its raw precision form */ function _getAPrecise(SwapUtils.Swap storage self) internal view returns (uint256) { uint256 t1 = self.futureATime; // time when ramp is finished uint256 a1 = self.futureA; // final A value when ramp is finished if (block.timestamp < t1) { uint256 t0 = self.initialATime; // time when ramp is started uint256 a0 = self.initialA; // initial A value when ramp is started if (a1 > a0) { // a0 + (a1 - a0) * (block.timestamp - t0) / (t1 - t0) return a0 + ((a1 - a0) * (block.timestamp - t0)) / (t1 - t0); } else { // a0 - (a0 - a1) * (block.timestamp - t0) / (t1 - t0) return a0 - ((a0 - a1) * (block.timestamp - t0)) / (t1 - t0); } } else { return a1; } } /** * @notice Start ramping up or down A parameter towards given futureA_ and futureTime_ * Checks if the change is too rapid, and commits the new A value only when it falls under * the limit range. * @param self Swap struct to update * @param futureA_ the new A to ramp towards * @param futureTime_ timestamp when the new A should be reached */ function rampA( SwapUtils.Swap storage self, uint256 futureA_, uint256 futureTime_ ) external { require( block.timestamp >= self.initialATime + 1 days, "Wait 1 day before starting ramp" ); require( futureTime_ >= block.timestamp + MIN_RAMP_TIME, "Insufficient ramp time" ); require( futureA_ > 0 && futureA_ < MAX_A, "futureA_ must be > 0 and < MAX_A" ); uint256 initialAPrecise = _getAPrecise(self); uint256 futureAPrecise = futureA_ * A_PRECISION; if (futureAPrecise < initialAPrecise) { require( futureAPrecise * MAX_A_CHANGE >= initialAPrecise, "futureA_ is too small" ); } else { require( futureAPrecise <= initialAPrecise * MAX_A_CHANGE, "futureA_ is too large" ); } self.initialA = initialAPrecise; self.futureA = futureAPrecise; self.initialATime = block.timestamp; self.futureATime = futureTime_; emit RampA(initialAPrecise, futureAPrecise, block.timestamp, futureTime_); } /** * @notice Stops ramping A immediately. Once this function is called, rampA() * cannot be called for another 24 hours * @param self Swap struct to update */ function stopRampA(SwapUtils.Swap storage self) external { require(self.futureATime > block.timestamp, "Ramp is already stopped"); uint256 currentA = _getAPrecise(self); self.initialA = currentA; self.futureA = currentA; self.initialATime = block.timestamp; self.futureATime = block.timestamp; emit StopRampA(currentA, block.timestamp); } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.7; import "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; /** * @title Liquidity Provider Token * @notice This token is an ERC20 detailed token with added capability to be minted by the owner. * It is used to represent user's shares when providing liquidity to swap contracts. * @dev Only Swap contracts should initialize and own LPToken contracts. */ contract LPToken is ERC20BurnableUpgradeable, OwnableUpgradeable { /** * @notice Initializes this LPToken contract with the given name and symbol * @dev The caller of this function will become the owner. A Swap contract should call this * in its initializer function. * @param name name of this token * @param symbol symbol of this token */ function initialize(string memory name, string memory symbol) external initializer returns (bool) { __Context_init_unchained(); __ERC20_init_unchained(name, symbol); __Ownable_init_unchained(); return true; } /** * @notice Mints the given amount of LPToken to the recipient. * @dev only owner can call this mint function * @param recipient address of account to receive the tokens * @param amount amount of tokens to mint */ function mint(address recipient, uint256 amount) external onlyOwner { require(amount != 0, "LPToken: cannot mint 0"); _mint(recipient, amount); } /** * @dev Overrides ERC20._beforeTokenTransfer() which get called on every transfers including * minting and burning. This ensures that Swap.updateUserWithdrawFees are called everytime. * This assumes the owner is set to a Swap contract's address. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual override(ERC20Upgradeable) { super._beforeTokenTransfer(from, to, amount); require(to != address(this), "LPToken: cannot send to itself"); } }
// SPDX-License-Identifier: MIT pragma solidity =0.8.7; /** * @title MathUtils library * @notice Contains functions for calculating differences between two uint256. */ library MathUtils { /** * @notice Compares a and b and returns true if the difference between a and b * is less than 1 or equal to each other. * @param a uint256 to compare with * @param b uint256 to compare with * @return True if the difference between a and b is less than 1 or equal, * otherwise return false */ function within1(uint256 a, uint256 b) internal pure returns (bool) { return (difference(a, b) <= 1); } /** * @notice Calculates absolute difference between a and b * @param a uint256 to compare with * @param b uint256 to compare with * @return Difference between a and b */ function difference(uint256 a, uint256 b) internal pure returns (uint256) { if (a > b) { return a - b; } return b - a; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.0; import "../ERC20Upgradeable.sol"; import "../../../utils/ContextUpgradeable.sol"; import "../../../proxy/utils/Initializable.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20BurnableUpgradeable is Initializable, ContextUpgradeable, ERC20Upgradeable { function __ERC20Burnable_init() internal onlyInitializing { } function __ERC20Burnable_init_unchained() internal onlyInitializing { } /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { _spendAllowance(account, _msgSender(), amount); _burn(account, amount); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/ContextUpgradeable.sol"; import "../proxy/utils/Initializable.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ function __Ownable_init() internal onlyInitializing { __Ownable_init_unchained(); } function __Ownable_init_unchained() internal onlyInitializing { _transferOwnership(_msgSender()); } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { require(owner() == _msgSender(), "Ownable: caller is not the owner"); _; } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions anymore. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby removing any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[49] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20Upgradeable.sol"; import "./extensions/IERC20MetadataUpgradeable.sol"; import "../../utils/ContextUpgradeable.sol"; import "../../proxy/utils/Initializable.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20Upgradeable is Initializable, ContextUpgradeable, IERC20Upgradeable, IERC20MetadataUpgradeable { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ function __ERC20_init(string memory name_, string memory symbol_) internal onlyInitializing { __ERC20_init_unchained(name_, symbol_); } function __ERC20_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, _allowances[owner][spender] + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = _allowances[owner][spender]; require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `sender` to `recipient`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; } _balances[to] += amount; emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; } _totalSupply -= amount; emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { 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); } /** * @dev Spend `amount` form the allowance of `owner` toward `spender`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[45] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; import "../proxy/utils/Initializable.sol"; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract ContextUpgradeable is Initializable { function __Context_init() internal onlyInitializing { } function __Context_init_unchained() internal onlyInitializing { } function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } /** * @dev This empty reserved space is put in place to allow future versions to add new * variables without shifting down storage in the inheritance chain. * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps */ uint256[50] private __gap; }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (proxy/utils/Initializable.sol) pragma solidity ^0.8.0; import "../../utils/AddressUpgradeable.sol"; /** * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect. * * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}. * * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity. * * [CAUTION] * ==== * Avoid leaving a contract uninitialized. * * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation * contract, which may impact the proxy. To initialize the implementation contract, you can either invoke the * initializer manually, or you can include a constructor to automatically mark it as initialized when it is deployed: * * [.hljs-theme-light.nopadding] * ``` * /// @custom:oz-upgrades-unsafe-allow constructor * constructor() initializer {} * ``` * ==== */ abstract contract Initializable { /** * @dev Indicates that the contract has been initialized. */ bool private _initialized; /** * @dev Indicates that the contract is in the process of being initialized. */ bool private _initializing; /** * @dev Modifier to protect an initializer function from being invoked twice. */ modifier initializer() { // If the contract is initializing we ignore whether _initialized is set in order to support multiple // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the // contract may have been reentered. require(_initializing ? _isConstructor() : !_initialized, "Initializable: contract is already initialized"); bool isTopLevelCall = !_initializing; if (isTopLevelCall) { _initializing = true; _initialized = true; } _; if (isTopLevelCall) { _initializing = false; } } /** * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the * {initializer} modifier, directly or indirectly. */ modifier onlyInitializing() { require(_initializing, "Initializable: contract is not initializing"); _; } function _isConstructor() private view returns (bool) { return !AddressUpgradeable.isContract(address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20Upgradeable.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20MetadataUpgradeable is IERC20Upgradeable { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library AddressUpgradeable { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCall(target, data, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); require(isContract(target), "Address: call to non-contract"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { require(isContract(target), "Address: static call to non-contract"); (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResult(success, returndata, errorMessage); } /** * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "metadata": { "useLiteralContent": true }, "libraries": {} }
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"fees","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"invariant","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpTokenSupply","type":"uint256"}],"name":"AddLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newAdminFee","type":"uint256"}],"name":"NewAdminFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newSwapFee","type":"uint256"}],"name":"NewSwapFee","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"lpTokenSupply","type":"uint256"}],"name":"RemoveLiquidity","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"fees","type":"uint256[]"},{"indexed":false,"internalType":"uint256","name":"invariant","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpTokenSupply","type":"uint256"}],"name":"RemoveLiquidityImbalance","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"provider","type":"address"},{"indexed":false,"internalType":"uint256","name":"lpTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpTokenSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"boughtId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensBought","type":"uint256"}],"name":"RemoveLiquidityOne","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"buyer","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokensSold","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"tokensBought","type":"uint256"},{"indexed":false,"internalType":"uint128","name":"soldId","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"boughtId","type":"uint128"}],"name":"TokenSwap","type":"event"},{"inputs":[],"name":"MAX_ADMIN_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SWAP_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"POOL_PRECISION_DECIMALS","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
61459f61003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106101205760003560e01c806373fd6b3e116100ac578063aa0ce1861161007b578063aa0ce186146102a0578063ab3d8544146102b3578063e0692742146102be578063e7a4db81146102d1578063f3de0362146102f157600080fd5b806373fd6b3e1461023a5780637d0481601461025a578063834b49101461026d578063a5397b221461028057600080fd5b8063467e186c116100f3578063467e186c146101b45780634b23603c146101d457806370467276146101e757806370703e4a1461020757806371906c2c1461022757600080fd5b80630296ab501461012557806324c5c7511461014457806340370edf1461016657806341b91c2614610194575b600080fd5b61012d601281565b60405160ff90911681526020015b60405180910390f35b81801561015057600080fd5b5061016461015f366004613eb3565b6102fd565b005b81801561017257600080fd5b50610186610181366004613f53565b6104df565b60405190815260200161013b565b8180156101a057600080fd5b506101866101af366004613f53565b610e1c565b8180156101c057600080fd5b506101646101cf36600461402c565b611604565b6101866101e2366004614113565b611689565b8180156101f357600080fd5b5061016461020236600461402c565b6116f4565b61021a61021536600461402c565b611772565b60405161013b919061423a565b610186610235366004613e9a565b611868565b81801561024657600080fd5b5061021a61025536600461404e565b6119a4565b61018661026836600461402c565b611e48565b61018661027b366004613eef565b611f64565b81801561028c57600080fd5b5061018661029b366004614147565b6121f3565b6101866102ae366004613e9a565b61277e565b6101866305f5e10081565b6101866102cc3660046140a1565b6127ec565b8180156102dd57600080fd5b506101866102ec3660046140d6565b612882565b6101866402540be40081565b60088201546009830180546001600160a01b03909216916000919060019081106103295761032961453d565b6000918252602090912001546007850154604051627eeac760e11b81526001600160a01b0385169162fdd58e91610364913091600401614221565b60206040518083038186803b15801561037c57600080fd5b505afa158015610390573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103b49190614195565b6103be91906144f5565b9050801561042f576007840154604051637921219560e11b81526001600160a01b0384169163f242432a916103fc91309188919087906004016141e9565b600060405180830381600087803b15801561041657600080fd5b505af115801561042a573d6000803e3d6000fd5b505050505b6000846009016000815481106104475761044761453d565b90600052602060002001544761045d91906144f5565b905080156104d857604051600090339083908381818185875af1925050503d80600081146104a7576040519150601f19603f3d011682016040523d82523d6000602084013e6104ac565b606091505b50509050806104d65760405162461bcd60e51b81526004016104cd90614310565b60405180910390fd5b505b5050505050565b600082516002146105325760405162461bcd60e51b815260206004820181905260248201527f416d6f756e7473206d757374206d6174636820706f6f6c656420746f6b656e7360448201526064016104cd565b34836000815181106105465761054661453d565b6020026020010151146105b75760405162461bcd60e51b815260206004820152603360248201527f537761705574696c733a207265636569766564206c657373206f72206d6f72656044820152720810559056081d1a185b88195e1c1958dd1959606a1b60648201526084016104cd565b60088401546040805160e0810182526000808252602082018190529181018290526001600160a01b0390921691606081016105f188612c53565b81526020018760060160009054906101000a90046001600160a01b03166001600160a01b03168152602001600081526020018760090180548060200260200160405190810160405280929190818152602001828054801561067157602002820191906000526020600020905b81548152602001906001019080831161065d575b5050505050815250905080608001516001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156106b857600080fd5b505afa1580156106cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106f09190614195565b60a082018190521561071a5761071761070d878360c00151612c5e565b8260600151612dc1565b81525b604080516002808252606082018352600092602083019080368337019050509050348260c001516000815181106107535761075361453d565b602002602001015161076591906143b1565b816000815181106107785761077861453d565b60200260200101818152505060005b60028110156108195760a08301511515806107bb575060008782815181106107b1576107b161453d565b6020026020010151115b6108075760405162461bcd60e51b815260206004820152601e60248201527f4d75737420737570706c7920616c6c20746f6b656e7320696e20706f6f6c000060448201526064016104cd565b806108118161450c565b915050610787565b506007870154604051627eeac760e11b81526000916001600160a01b0386169162fdd58e9161084d91309190600401614221565b60206040518083038186803b15801561086557600080fd5b505afa158015610879573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061089d9190614195565b9050836001600160a01b031663f242432a33308b600701548b6001815181106108c8576108c861453d565b60200260200101516040518563ffffffff1660e01b81526004016108ef94939291906141e9565b600060405180830381600087803b15801561090957600080fd5b505af115801561091d573d6000803e3d6000fd5b5050506007890154604051627eeac760e11b81528392506001600160a01b0387169162fdd58e91610952913091600401614221565b60206040518083038186803b15801561096a57600080fd5b505afa15801561097e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109a29190614195565b6109ac91906144f5565b876001815181106109bf576109bf61453d565b602002602001018181525050866001815181106109de576109de61453d565b60200260200101518360c001516001815181106109fd576109fd61453d565b6020026020010151610a0f91906143b1565b82600181518110610a2257610a2261453d565b60200260200101818152505050610a46610a3c8883612c5e565b8360600151612dc1565b60208301819052825110610a905760405162461bcd60e51b8152602060048201526011602482015270442073686f756c6420696e63726561736560781b60448201526064016104cd565b6020820151604080840191909152805160028082526060820190925260009181602001602082028036833750505060a084015190915015610ca157600060028960040154610ade91906143c9565b905060005b6002811015610c7e57600085600001518660c001518381518110610b0957610b0961453d565b60200260200101518760200151610b2091906144d6565b610b2a91906143c9565b90506402540be400610b5e868481518110610b4757610b4761453d565b602002602001015183612fa990919063ffffffff16565b610b6890856144d6565b610b7291906143c9565b848381518110610b8457610b8461453d565b6020026020010181815250506402540be4008b60050154858481518110610bad57610bad61453d565b6020026020010151610bbf91906144d6565b610bc991906143c9565b858381518110610bdb57610bdb61453d565b6020026020010151610bed91906144f5565b8b6009018381548110610c0257610c0261453d565b9060005260206000200181905550838281518110610c2257610c2261453d565b6020026020010151858381518110610c3c57610c3c61453d565b6020026020010151610c4e91906144f5565b858381518110610c6057610c6061453d565b60209081029190910101525080610c768161450c565b915050610ae3565b50610c96610c8c8a85612c5e565b8560600151612dc1565b604085015250610cb8565b8151610cb69060098a01906020850190613dd8565b505b60008360a0015160001415610cd257506020830151610d00565b835160a08501516040860151610ce99083906144f5565b610cf391906144d6565b610cfd91906143c9565b90505b86811015610d505760405162461bcd60e51b815260206004820152601b60248201527f436f756c646e2774206d696e74206d696e20726571756573746564000000000060448201526064016104cd565b83608001516001600160a01b03166340c10f1933836040518363ffffffff1660e01b8152600401610d82929190614221565b600060405180830381600087803b158015610d9c57600080fd5b505af1158015610db0573d6000803e3d6000fd5b50505050336001600160a01b03167f189c623b666b1b45b83d7178f39b8c087cb09774317ca2f53c2d3c3726f222a289848760200151858960a00151610df691906143b1565b604051610e06949392919061427e565b60405180910390a29450505050505b9392505050565b60088301546040805160e08101825260008082526020820181905291810182905290916001600160a01b031690829060608101610e5888612c53565b81526020018760060160009054906101000a90046001600160a01b03166001600160a01b031681526020016000815260200187600901805480602002602001604051908101604052809291908181526020018280548015610ed857602002820191906000526020600020905b815481526020019060010190808311610ec4575b5050505050815250905080608001516001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610f1f57600080fd5b505afa158015610f33573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f579190614195565b60a08201528451600214610fad5760405162461bcd60e51b815260206004820181905260248201527f416d6f756e74732073686f756c64206d6174636820706f6f6c20746f6b656e7360448201526064016104cd565b60808101516040516370a0823160e01b81523360048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015610ff257600080fd5b505afa158015611006573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102a9190614195565b841115801561103857508315155b6110545760405162461bcd60e51b81526004016104cd9061438a565b60006002876004015461106791906143c9565b60408051600280825260608201835292935060009290916020830190803683375050604080516002808252606082018352939450600093909250906020830190803683370190505090506110c2610c8c8a8660c00151612c5e565b845260005b6002811015611197578460c0015181815181106110e6576110e661453d565b60200260200101518982815181106111005761110061453d565b602002602001015111156111265760405162461bcd60e51b81526004016104cd90614347565b8881815181106111385761113861453d565b60200260200101518560c0015182815181106111565761115661453d565b602002602001015161116891906144f5565b82828151811061117a5761117a61453d565b60209081029190910101528061118f8161450c565b9150506110c7565b506111a5610c8c8a83612c5e565b602085015260005b600281101561133e57600085600001518660c0015183815181106111d3576111d361453d565b602002602001015187602001516111ea91906144d6565b6111f491906143c9565b9050600061120d848481518110610b4757610b4761453d565b90506402540be40061121f82886144d6565b61122991906143c9565b85848151811061123b5761123b61453d565b60200260200101818152505060008c6005015490506402540be400818786815181106112695761126961453d565b602002602001015161127b91906144d6565b61128591906143c9565b8585815181106112975761129761453d565b60200260200101516112a991906144f5565b8d60090185815481106112be576112be61453d565b90600052602060002001819055508584815181106112de576112de61453d565b60200260200101518585815181106112f8576112f861453d565b602002602001015161130a91906144f5565b85858151811061131c5761131c61453d565b60200260200101818152505050505080806113369061450c565b9150506111ad565b5061134c610c8c8a83612c5e565b60408501819052845160a086015160009350909161136a90836144f5565b61137491906144d6565b61137e91906143c9565b9050806113cd5760405162461bcd60e51b815260206004820152601b60248201527f4275726e7420616d6f756e742063616e6e6f74206265207a65726f000000000060448201526064016104cd565b6113d88160016143b1565b90508681111561142a5760405162461bcd60e51b815260206004820152601b60248201527f746f6b656e416d6f756e74203e206d61784275726e416d6f756e74000000000060448201526064016104cd565b83608001516001600160a01b03166379cc679033836040518363ffffffff1660e01b815260040161145c929190614221565b600060405180830381600087803b15801561147657600080fd5b505af115801561148a573d6000803e3d6000fd5b505050506000336001600160a01b0316896000815181106114ad576114ad61453d565b602002602001015160405160006040518083038185875af1925050503d80600081146114f5576040519150601f19603f3d011682016040523d82523d6000602084013e6114fa565b606091505b505090508061151b5760405162461bcd60e51b81526004016104cd90614310565b856001600160a01b031663f242432a30338d600701548d6001815181106115445761154461453d565b60200260200101516040518563ffffffff1660e01b815260040161156b94939291906141e9565b600060405180830381600087803b15801561158557600080fd5b505af1158015611599573d6000803e3d6000fd5b50505050336001600160a01b03167f3631c28b1f9dd213e0319fb167b554d76b6c283a41143eb400a0d1adb1af17558a858860200151868a60a001516115df91906144f5565b6040516115ef949392919061427e565b60405180910390a25098975050505050505050565b6305f5e10081111561164a5760405162461bcd60e51b815260206004820152600f60248201526e08ccaca40d2e640e8dede40d0d2ced608b1b60448201526064016104cd565b600482018190556040518181527fd88ea5155021c6f8dafa1a741e173f595cdf77ce7c17d43342131d7f06afdfe5906020015b60405180910390a15050565b60006116ea85858585896009018054806020026020016040519081016040528092919081815260200182805480156116e057602002820191906000526020600020905b8154815260200190600101908083116116cc575b5050505050612fc7565b5095945050505050565b6402540be40081111561173b5760405162461bcd60e51b815260206004820152600f60248201526e08ccaca40d2e640e8dede40d0d2ced608b1b60448201526064016104cd565b600582018190556040518181527fab599d640ca80cde2b09b128a4154a8dfe608cb80f4c9399c8b954b01fd35f389060200161167d565b606061185f8361185a6117d786876009018054806020026020016040519081016040528092919081815260200182805480156117cd57602002820191906000526020600020905b8154815260200190600101908083116117b9575b5050505050612c5e565b6006870154604080516318160ddd60e01b8152905188926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561181d57600080fd5b505afa158015611831573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118559190614195565b6130da565b6131f4565b90505b92915050565b6000806118d66118c884856009018054806020026020016040519081016040528092919081815260200182805480156117cd57602002820191906000526020600020908154815260200190600101908083116117b9575050505050612c5e565b6118d185612c53565b612dc1565b905060008360060160009054906101000a90046001600160a01b031690506000816001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561192f57600080fd5b505afa158015611943573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119679190614195565b90508015611999578061197c6012600a61442e565b61198690856144d6565b61199091906143c9565b95945050505050565b506000949350505050565b600684015460088501546040516370a0823160e01b81523360048201526060926001600160a01b0390811692169082906370a082319060240160206040518083038186803b1580156119f557600080fd5b505afa158015611a09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a2d9190614195565b861115611a4c5760405162461bcd60e51b81526004016104cd9061438a565b60028414611a9c5760405162461bcd60e51b815260206004820181905260248201527f6d696e416d6f756e7473206d757374206d6174636820706f6f6c546f6b656e7360448201526064016104cd565b600087600901805480602002602001604051908101604052809291908181526020018280548015611aec57602002820191906000526020600020905b815481526020019060010190808311611ad8575b505050505090506000836001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015611b2e57600080fd5b505afa158015611b42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b669190614195565b90506000611b828a61185a611b7b8d87612c5e565b8c866130da565b905060005b8151811015611c8257888882818110611ba257611ba261453d565b90506020020135828281518110611bbb57611bbb61453d565b60200260200101511015611c115760405162461bcd60e51b815260206004820152601a60248201527f616d6f756e74735b695d203c206d696e416d6f756e74735b695d00000000000060448201526064016104cd565b818181518110611c2357611c2361453d565b6020026020010151848281518110611c3d57611c3d61453d565b6020026020010151611c4f91906144f5565b8b6009018281548110611c6457611c6461453d565b60009182526020909120015580611c7a8161450c565b915050611b87565b5060405163079cc67960e41b81526001600160a01b038616906379cc679090611cb19033908d90600401614221565b600060405180830381600087803b158015611ccb57600080fd5b505af1158015611cdf573d6000803e3d6000fd5b505050506000336001600160a01b031682600081518110611d0257611d0261453d565b602002602001015160405160006040518083038185875af1925050503d8060008114611d4a576040519150601f19603f3d011682016040523d82523d6000602084013e611d4f565b606091505b5050905080611d705760405162461bcd60e51b81526004016104cd90614310565b846001600160a01b031663f242432a30338e6007015486600181518110611d9957611d9961453d565b60200260200101516040518563ffffffff1660e01b8152600401611dc094939291906141e9565b600060405180830381600087803b158015611dda57600080fd5b505af1158015611dee573d6000803e3d6000fd5b503392507f88d38ed598fdd809c2bf01ee49cd24b7fdabf379a83d29567952b60324d58cef9150849050611e228d876144f5565b604051611e309291906142b7565b60405180910390a2509450505050505b949350505050565b600060028210611e6a5760405162461bcd60e51b81526004016104cd906142d9565b81611ea157826009018281548110611e8457611e8461453d565b906000526020600020015447611e9a91906144f5565b9050611862565b8160011415611f5b57826009018281548110611ebf57611ebf61453d565b60009182526020909120015460088401546007850154604051627eeac760e11b81526001600160a01b039092169162fdd58e91611f0191309190600401614221565b60206040518083038186803b158015611f1957600080fd5b505afa158015611f2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f519190614195565b611e9a91906144f5565b50600092915050565b600080611f7086612c53565b9050600086600901805480602002602001604051908101604052809291908181526020018280548015611fc257602002820191906000526020600020905b815481526020019060010190808311611fae575b505050505090506000611fde611fd88984612c5e565b84612dc1565b905060005b8251811015612111578515612052578787828181106120045761200461453d565b9050602002013583828151811061201d5761201d61453d565b602002602001015161202f91906143b1565b8382815181106120415761204161453d565b6020026020010181815250506120ff565b8281815181106120645761206461453d565b602002602001015188888381811061207e5761207e61453d565b9050602002013511156120a35760405162461bcd60e51b81526004016104cd90614347565b8787828181106120b5576120b561453d565b905060200201358382815181106120ce576120ce61453d565b60200260200101516120e091906144f5565b8382815181106120f2576120f261453d565b6020026020010181815250505b806121098161450c565b915050611fe3565b5060006121276121218a85612c5e565b85612dc1565b905060008960060160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561217b57600080fd5b505afa15801561218f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121b39190614195565b905086156121e75782816121c782856144f5565b6121d191906144d6565b6121db91906143c9565b95505050505050611e40565b82816121c784836144f5565b60088501546000906001600160a01b031660ff8616612267573484146122675760405162461bcd60e51b815260206004820152602360248201527f43616e6e6f742073776170206d6f72652f6c657373207468616e20796f752073604482015262195b9d60ea1b60648201526084016104cd565b8560ff16600114156124b6576007870154604051627eeac760e11b81526001600160a01b0383169062fdd58e906122a49033908590600401614221565b60206040518083038186803b1580156122bc57600080fd5b505afa1580156122d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122f49190614195565b8511156123435760405162461bcd60e51b815260206004820152601d60248201527f43616e6e6f742073776170206d6f7265207468616e20796f75206f776e00000060448201526064016104cd565b604051627eeac760e11b81526000906001600160a01b0384169062fdd58e906123729030908690600401614221565b60206040518083038186803b15801561238a57600080fd5b505afa15801561239e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123c29190614195565b604051637921219560e11b81529091506001600160a01b0384169063f242432a906123f7903390309087908c906004016141e9565b600060405180830381600087803b15801561241157600080fd5b505af1158015612425573d6000803e3d6000fd5b5050604051627eeac760e11b81528392506001600160a01b038616915062fdd58e906124579030908790600401614221565b60206040518083038186803b15801561246f57600080fd5b505afa158015612483573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906124a79190614195565b6124b191906144f5565b955050505b60008060008960090180548060200260200160405190810160405280929190818152602001828054801561250957602002820191906000526020600020905b8154815260200190600101908083116124f5575b5050505050905061251d8a8a8a8a85612fc7565b9093509150858310156125725760405162461bcd60e51b815260206004820181905260248201527f53776170206469646e277420726573756c7420696e206d696e20746f6b656e7360448201526064016104cd565b60006402540be4008b600501548461258a91906144d6565b61259491906143c9565b905087828b60ff16815181106125ac576125ac61453d565b60200260200101516125be91906143b1565b8b6009018b60ff16815481106125d6576125d661453d565b90600052602060002001819055508084838b60ff16815181106125fb576125fb61453d565b602002602001015161260d91906144f5565b61261791906144f5565b8b6009018a60ff168154811061262f5761262f61453d565b60009182526020909120015560ff89166126ad57604051600090339086908381818185875af1925050503d8060008114612685576040519150601f19603f3d011682016040523d82523d6000602084013e61268a565b606091505b50509050806126ab5760405162461bcd60e51b81526004016104cd90614310565b505b8860ff16600114156127225760078b0154604051637921219560e11b81526001600160a01b0387169163f242432a916126ef9130913391908a906004016141e9565b600060405180830381600087803b15801561270957600080fd5b505af115801561271d573d6000803e3d6000fd5b505050505b604080518981526020810186905260ff8c8116828401528b166060820152905133917fc6c1e0630dbe9130cc068028486c0d118ddcea348550819defd5cb8c257f8a38919081900360800190a250919998505050505050505050565b6000611862826127de84856009018054806020026020016040519081016040528092919081815260200182805480156117cd57602002820191906000526020600020908154815260200190600101908083116117b9575050505050612c5e565b6127e785612c53565b61332e565b6000806116ea8585858860060160009054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561284557600080fd5b505afa158015612859573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061287d9190614195565b61340d565b600684015460088501546040516370a0823160e01b81523360048201526000926001600160a01b0390811692169082906370a082319060240160206040518083038186803b1580156128d357600080fd5b505afa1580156128e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061290b9190614195565b86111561292a5760405162461bcd60e51b81526004016104cd9061438a565b60028560ff161061296f5760405162461bcd60e51b815260206004820152600f60248201526e151bdad95b881b9bdd08199bdd5b99608a1b60448201526064016104cd565b6000826001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b1580156129aa57600080fd5b505afa1580156129be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e29190614195565b90506000806129f38a8a8a8661340d565b9150915086821015612a385760405162461bcd60e51b815260206004820152600e60248201526d191e480f081b5a5b905b5bdd5b9d60921b60448201526064016104cd565b6402540be4008a6005015482612a4e91906144d6565b612a5891906143c9565b612a6290836143b1565b8a6009018960ff1681548110612a7a57612a7a61453d565b9060005260206000200154612a8f91906144f5565b8a6009018960ff1681548110612aa757612aa761453d565b60009182526020909120015560405163079cc67960e41b81526001600160a01b038616906379cc679090612ae19033908d90600401614221565b600060405180830381600087803b158015612afb57600080fd5b505af1158015612b0f573d6000803e3d6000fd5b5050505060ff8816612b8557604051600090339084908381818185875af1925050503d8060008114612b5d576040519150601f19603f3d011682016040523d82523d6000602084013e612b62565b606091505b5050905080612b835760405162461bcd60e51b81526004016104cd90614310565b505b8760ff1660011415612bfa5760078a0154604051637921219560e11b81526001600160a01b0386169163f242432a91612bc791309133919088906004016141e9565b600060405180830381600087803b158015612be157600080fd5b505af1158015612bf5573d6000803e3d6000fd5b505050505b604080518a81526020810185905260ff8a168183015260608101849052905133917f43fb02998f4e03da2e0e6fff53fdbf0c40a9f45f145dc377fc30615d7d7a8a64919081900360800190a25098975050505050505050565b600061186282613450565b60606000825167ffffffffffffffff811115612c7c57612c7c614553565b604051908082528060200260200182016040528015612ca5578160200160208202803683370190505b50905082600081518110612cbb57612cbb61453d565b602002602001015181600081518110612cd657612cd661453d565b60209081029190910101526008840154600785015460405163f759cc3b60e01b81526004810191909152670de0b6b3a7640000916001600160a01b03169063f759cc3b9060240160206040518083038186803b158015612d3557600080fd5b505afa158015612d49573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d6d9190614195565b84600181518110612d8057612d8061453d565b6020026020010151612d9291906144d6565b612d9c91906143c9565b81600181518110612daf57612daf61453d565b60209081029190910101529392505050565b60008060029050600084600181518110612ddd57612ddd61453d565b602002602001015185600081518110612df857612df861453d565b6020026020010151612e0a91906143b1565b905080612e1c57600092505050611862565b60008181612e2a85886144d6565b905060005b610100811015612f6a57600089600181518110612e4e57612e4e61453d565b60200260200101518a600081518110612e6957612e6961453d565b60200260200101518889612e7d919061442e565b612e8791906144d6565b612e9191906144d6565b612e9c8860016143b1565b612ea6908661442e565b612eb091906143c9565b905083945080876001612ec391906143b1565b612ecd91906144d6565b606485612eda82876144f5565b612ee491906144d6565b612eee91906143c9565b612ef891906143b1565b84612f0389846144d6565b6064612f0f8a886144d6565b612f1991906143c9565b612f2391906143b1565b612f2d91906144d6565b612f3791906143c9565b9350612f4384866134f7565b15612f575783975050505050505050611862565b5080612f628161450c565b915050612e2f565b5060405162461bcd60e51b81526020600482015260136024820152724420646f6573206e6f7420636f6e766572676560681b60448201526064016104cd565b600081831115612fbd57611e9a82846144f5565b61185f83836144f5565b60008082518660ff16108015612fe0575082518560ff16105b612ffc5760405162461bcd60e51b81526004016104cd906142d9565b600061303388858960ff16815181106130175761301761453d565b60200260200101518761302a91906143b1565b8960ff1661350e565b905060006130418986612c5e565b905060006130678a61305e6130558d612c53565b8c8c88886135be565b8a60ff166137cf565b9050600181878a60ff16815181106130815761308161453d565b602002602001015161309391906144f5565b61309d91906144f5565b94506402540be4008a60040154866130b591906144d6565b6130bf91906143c9565b93506130cb84866144f5565b94505050509550959350505050565b60608183111561312c5760405162461bcd60e51b815260206004820152601a60248201527f43616e6e6f742065786365656420746f74616c20737570706c7900000000000060448201526064016104cd565b6040805160028082526060820183526000926020830190803683370190505090508284866000815181106131625761316261453d565b602002602001015161317491906144d6565b61317e91906143c9565b816000815181106131915761319161453d565b6020026020010181815250508284866001815181106131b2576131b261453d565b60200260200101516131c491906144d6565b6131ce91906143c9565b816001815181106131e1576131e161453d565b6020908102919091010152949350505050565b60606000825167ffffffffffffffff81111561321257613212614553565b60405190808252806020026020018201604052801561323b578160200160208202803683370190505b509050826000815181106132515761325161453d565b60200260200101518160008151811061326c5761326c61453d565b60209081029190910101526008840154600785015460405163f759cc3b60e01b81526001600160a01b039092169163f759cc3b916132b09160040190815260200190565b60206040518083038186803b1580156132c857600080fd5b505afa1580156132dc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133009190614195565b836001815181106133135761331361453d565b6020026020010151670de0b6b3a7640000612d9291906144d6565b600080600261333d8585612dc1565b61334791906143c9565b9050808460008151811061335d5761335d61453d565b602002602001015110613374576000915050610e15565b6000818560018151811061338a5761338a61453d565b602002602001015161339c91906144f5565b9050600060026402540be4008860040154846133b891906144d6565b6133c291906143c9565b6133cc91906143c9565b9050600081876000815181106133e4576133e461453d565b6020026020010151856133f791906144f5565b61340191906143b1565b9450610e159350505050565b600080600080600061342189888a8961387a565b9194509250905060008361343584846144f5565b61343f91906144f5565b939a93995092975050505050505050565b600381015460018201546000919042821115610e155760028401548454808311156134bb5761347f82856144f5565b61348983426144f5565b61349383866144f5565b61349d91906144d6565b6134a791906143c9565b6134b190826143b1565b9695505050505050565b6134c582856144f5565b6134cf83426144f5565b6134d985846144f5565b6134e391906144d6565b6134ed91906143c9565b6134b190826144f5565b600060016135058484612fa9565b11159392505050565b60008160011461351e5782611e40565b6008840154600785015460405163f759cc3b60e01b81526004810191909152670de0b6b3a7640000916001600160a01b03169063f759cc3b9060240160206040518083038186803b15801561357257600080fd5b505afa158015613586573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906135aa9190614195565b6135b490856144d6565b611e4091906143c9565b6000600260ff86811690861614156136185760405162461bcd60e51b815260206004820152601d60248201527f43616e277420636f6d7061726520746f6b656e20746f20697473656c6600000060448201526064016104cd565b808660ff1610801561362c5750808560ff16105b6136715760405162461bcd60e51b8152602060048201526016602482015275151bdad95b9cc81b5d5cdd081899481a5b881c1bdbdb60521b60448201526064016104cd565b600061367d8489612dc1565b90508085600061368d8b866144d6565b905061369985896144d6565b6136a385856144d6565b6136ad91906143c9565b92506136b985826144d6565b60646136c586866144d6565b6136cf91906144d6565b6136d991906143c9565b92506000816136e96064876144d6565b6136f391906143c9565b6136fd90846143b1565b9050600085815b61010081101561378657819250878483600261372091906144d6565b61372a91906143b1565b61373491906144f5565b8761373f84806144d6565b61374991906143b1565b61375391906143c9565b915061375f82846134f7565b15613774575097506119909650505050505050565b8061377e8161450c565b915050613704565b5060405162461bcd60e51b815260206004820152601e60248201527f417070726f78696d6174696f6e20646964206e6f7420636f6e7665726765000060448201526064016104cd565b6000816001146137df5782611e40565b6008840154600785015460405163f759cc3b60e01b81526001600160a01b039092169163f759cc3b916138189160040190815260200190565b60206040518083038186803b15801561383057600080fd5b505afa158015613844573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906138689190614195565b6135b484670de0b6b3a76400006144d6565b600080600060028660ff16106138a25760405162461bcd60e51b81526004016104cd906142d9565b60006040518060a0016040528060008152602001600081526020016000815260200160008152602001600081525090506138db88612c53565b6080820152600988018054604080516020808402820181019092528281526139449361393a938d938301828280156117cd57602002820191906000526020600020908154815260200190600101908083116117b9575050505050612c5e565b8260800151612dc1565b808252859061395390886144d6565b61395d91906143c9565b815161396991906144f5565b602082015260098801805460ff89169081106139875761398761453d565b90600052602060002001548611156139e15760405162461bcd60e51b815260206004820152601a60248201527f5769746864726177206578636565647320617661696c61626c6500000000000060448201526064016104cd565b613a5b88613a5283608001518a613a488d8e6009018054806020026020016040519081016040528092919081815260200182805480156117cd57602002820191906000526020600020908154815260200190600101908083116117b9575050505050612c5e565b8660200151613c1f565b8960ff166137cf565b6040828101919091528051600280825260608201835260009260208301908036833701905050905060028960040154613a9491906143c9565b606083015260005b6002811015613b805760008a6009018281548110613abc57613abc61453d565b906000526020600020015490506402540be40084606001518b60ff168414613b085785516020870151613aef90856144d6565b613af991906143c9565b613b0390846144f5565b613b32565b604086015186516020880151613b1e90866144d6565b613b2891906143c9565b613b3291906144f5565b613b3c91906144d6565b613b4691906143c9565b613b5090826144f5565b838381518110613b6257613b6261453d565b60209081029190910101525080613b788161450c565b915050613a9c565b506000613bad8a613ba485608001518c613b9a8f88612c5e565b8860200151613c1f565b8b60ff166137cf565b828a60ff1681518110613bc257613bc261453d565b6020026020010151613bd491906144f5565b9050613be16001826144f5565b90508083604001518b6009018b60ff1681548110613c0157613c0161453d565b90600052602060002001549550955095505050509450945094915050565b6000600260ff85168111613c675760405162461bcd60e51b815260206004820152600f60248201526e151bdad95b881b9bdd08199bdd5b99608a1b60448201526064016104cd565b82600080613c75848a6144d6565b905060005b84811015613d01578860ff168114613cef57878181518110613c9e57613c9e61453d565b602002602001015183613cb191906143b1565b925084888281518110613cc657613cc661453d565b6020026020010151613cd891906144d6565b613ce288866144d6565b613cec91906143c9565b93505b80613cf98161450c565b915050613c7a565b50613d0c84826144d6565b6064613d1888866144d6565b613d2291906144d6565b613d2c91906143c9565b9250600081613d3c6064896144d6565b613d4691906143c9565b613d5090846143b1565b9050600087815b610100811015613786578192508984836002613d7391906144d6565b613d7d91906143b1565b613d8791906144f5565b87613d9284806144d6565b613d9c91906143b1565b613da691906143c9565b9150613db282846134f7565b15613dc657509650611e4095505050505050565b80613dd08161450c565b915050613d57565b828054828255906000526020600020908101928215613e13579160200282015b82811115613e13578251825591602001919060010190613df8565b50613e1f929150613e23565b5090565b5b80821115613e1f5760008155600101613e24565b60008083601f840112613e4a57600080fd5b50813567ffffffffffffffff811115613e6257600080fd5b6020830191508360208260051b8501011115613e7d57600080fd5b9250929050565b803560ff81168114613e9557600080fd5b919050565b600060208284031215613eac57600080fd5b5035919050565b60008060408385031215613ec657600080fd5b8235915060208301356001600160a01b0381168114613ee457600080fd5b809150509250929050565b60008060008060608587031215613f0557600080fd5b84359350602085013567ffffffffffffffff811115613f2357600080fd5b613f2f87828801613e38565b90945092505060408501358015158114613f4857600080fd5b939692955090935050565b600080600060608486031215613f6857600080fd5b8335925060208085013567ffffffffffffffff80821115613f8857600080fd5b818701915087601f830112613f9c57600080fd5b813581811115613fae57613fae614553565b8060051b604051601f19603f83011681018181108582111715613fd357613fd3614553565b604052828152858101935084860182860187018c1015613ff257600080fd5b600095505b83861015614015578035855260019590950194938601938601613ff7565b50979a979950505050604095909501359450505050565b6000806040838503121561403f57600080fd5b50508035926020909101359150565b6000806000806060858703121561406457600080fd5b8435935060208501359250604085013567ffffffffffffffff81111561408957600080fd5b61409587828801613e38565b95989497509550505050565b6000806000606084860312156140b657600080fd5b83359250602084013591506140cd60408501613e84565b90509250925092565b600080600080608085870312156140ec57600080fd5b843593506020850135925061410360408601613e84565b9396929550929360600135925050565b6000806000806080858703121561412957600080fd5b8435935061413960208601613e84565b925061410360408601613e84565b600080600080600060a0868803121561415f57600080fd5b8535945061416f60208701613e84565b935061417d60408701613e84565b94979396509394606081013594506080013592915050565b6000602082840312156141a757600080fd5b5051919050565b600081518084526020808501945080840160005b838110156141de578151875295820195908201906001016141c2565b509495945050505050565b6001600160a01b0394851681529290931660208301526040820152606081019190915260a06080820181905260009082015260c00190565b6001600160a01b03929092168252602082015260400190565b6020808252825182820181905260009190848201906040850190845b8181101561427257835183529284019291840191600101614256565b50909695505050505050565b60808152600061429160808301876141ae565b82810360208401526142a381876141ae565b604084019590955250506060015292915050565b6040815260006142ca60408301856141ae565b90508260208301529392505050565b60208082526018908201527f546f6b656e20696e646578206f7574206f662072616e67650000000000000000604082015260600190565b6020808252601e908201527f537761705574696c733a204661696c656420746f2073656e6420417661780000604082015260600190565b60208082526023908201527f43616e6e6f74207769746864726177206d6f7265207468616e20617661696c61604082015262626c6560e81b606082015260800190565b6020808252600d908201526c1f2628173130b630b731b2a7b360991b604082015260600190565b600082198211156143c4576143c4614527565b500190565b6000826143e657634e487b7160e01b600052601260045260246000fd5b500490565b600181815b8085111561442657816000190482111561440c5761440c614527565b8085161561441957918102915b93841c93908002906143f0565b509250929050565b600061185f838360008261444457506001611862565b8161445157506000611862565b816001811461446757600281146144715761448d565b6001915050611862565b60ff84111561448257614482614527565b50506001821b611862565b5060208310610133831016604e8410600b84101617156144b0575081810a611862565b6144ba83836143eb565b80600019048211156144ce576144ce614527565b029392505050565b60008160001904831182151516156144f0576144f0614527565b500290565b60008282101561450757614507614527565b500390565b600060001982141561452057614520614527565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fdfea2646970667358221220cfdb095508b1cb4df3c69badb7239ccbc2ae7ef9d75bc73b2d765b4adf25342564736f6c63430008070033
Age | Block | Fee Address | BC Fee Address | Voting Power | Jailed | Incoming |
---|
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.