diff --git a/contracts/UniswapV2.sol b/contracts/UniswapV2.sol index aaaf80a..85ee788 100644 --- a/contracts/UniswapV2.sol +++ b/contracts/UniswapV2.sol @@ -12,7 +12,7 @@ import "./token/SafeTransfer.sol"; contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTransfer { using SafeMath128 for uint128; using SafeMath256 for uint256; - using UQ104x104 for uint232; + using UQ104x104 for uint240; struct TokenData { uint128 token0; @@ -88,12 +88,12 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran uint128 blocksElapsed = (block.number - blockNumberLast).downcast128(); // get the prices according to the reserves as of the last official interaction with the contract - uint208 priceToken0 = UQ104x104.encode(reserves.token0).qdiv(reserves.token1); - uint208 priceToken1 = UQ104x104.encode(reserves.token1).qdiv(reserves.token0); + uint240 priceToken0 = UQ104x104.encode(reserves.token0).qdiv(reserves.token1); + uint240 priceToken1 = UQ104x104.encode(reserves.token1).qdiv(reserves.token0); return ( - priceToken0Accumulated + (uint240(priceToken0) * blocksElapsed), - priceToken1Accumulated + (uint240(priceToken1) * blocksElapsed) + priceToken0Accumulated + priceToken0 * blocksElapsed, + priceToken1Accumulated + priceToken1 * blocksElapsed ); } else { return ( @@ -126,12 +126,12 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran uint32 blocksElapsed = blockNumber - blockNumberLast; // get the prices according to the reserves as of the last official interaction with the contract - uint208 priceToken0 = UQ104x104.encode(reserves.token0).qdiv(reserves.token1); - uint208 priceToken1 = UQ104x104.encode(reserves.token1).qdiv(reserves.token0); + uint240 priceToken0 = UQ104x104.encode(reserves.token0).qdiv(reserves.token1); + uint240 priceToken1 = UQ104x104.encode(reserves.token1).qdiv(reserves.token0); // multiply these prices by the number of elapsed blocks and add to the accumulators - priceToken0Accumulated = priceToken0Accumulated + (uint240(priceToken0) * blocksElapsed); - priceToken1Accumulated = priceToken1Accumulated + (uint240(priceToken1) * blocksElapsed); + priceToken0Accumulated = priceToken0Accumulated + priceToken0 * blocksElapsed; + priceToken1Accumulated = priceToken1Accumulated + priceToken1 * blocksElapsed; } // update the last block number diff --git a/contracts/libraries/UQ104x104.sol b/contracts/libraries/UQ104x104.sol index 705cffe..07d3dde 100644 --- a/contracts/libraries/UQ104x104.sol +++ b/contracts/libraries/UQ104x104.sol @@ -6,29 +6,28 @@ pragma solidity 0.5.12; // https://github.com/gnosis/solidity-arithmetic library UQ104x104 { - uint232 constant Q104 = uint232(uint104(-1)) + 1; + uint240 constant Q104 = 2**104; // we want to encode a uint128 `y` s.t. `y := y_encoded / 2**104` (i.e. with a Q104 denominator). // in other words, to encode `y` we simply multiply by `2**104`, aka Q104. // however, in the case of a traditional UQ104.104, we'd store this output in a 208-bit slot, // which would overflow for values of `y` in (`uint104(-1)`, `uint128(-1)`], so instead we need to // store the output in 232 bits (TODO check this logic). - function encode(uint128 y) internal pure returns (uint232 z) { - return uint232(y) * Q104; + function encode(uint128 y) internal pure returns (uint240 z) { + return uint240(y) * Q104; } // we want to divide a modified UQ104.104 (the output of encode) by an unencoded uint128, // and return a traditional Q104. since we're using a modified UQ104.104, though, we need to handle overflows. // for the moment, we simply truncate these to 1 and uint208(-1), though it's likely we'll handle this slightly // differently in the future - function qdiv(uint232 x, uint128 y) internal pure returns (uint208 z) { - uint232 temp = x / y; - if (temp == 0) { + function qdiv(uint240 x, uint128 y) internal pure returns (uint240 z) { + z = x / y; + + if (z == 0) { z = 1; - } else if (temp > uint208(-1)) { + } else if (z > uint208(-1)) { z = uint208(-1); - } else { - z = uint208(temp); } } }