mock out price accumulator
This commit is contained in:
@ -4,6 +4,7 @@ import "./interfaces/IUniswapV2.sol";
|
|||||||
|
|
||||||
import "./libraries/Math.sol";
|
import "./libraries/Math.sol";
|
||||||
import "./libraries/SafeMath128.sol";
|
import "./libraries/SafeMath128.sol";
|
||||||
|
import "./libraries/MOCK_Decimal.sol";
|
||||||
|
|
||||||
import "./token/ERC20.sol";
|
import "./token/ERC20.sol";
|
||||||
import "./token/SafeTransfer.sol";
|
import "./token/SafeTransfer.sol";
|
||||||
@ -22,8 +23,9 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran
|
|||||||
address public token1;
|
address public token1;
|
||||||
|
|
||||||
TokenData private reserves;
|
TokenData private reserves;
|
||||||
TokenData private reservesCumulative;
|
|
||||||
TokenData private reservesCumulativeOverflows;
|
MOCK_Decimal.Decimal private accumulatedPriceToken0; // mocked accumulated price of token0 / token1
|
||||||
|
MOCK_Decimal.Decimal private accumulatedPriceToken1; // mocked accumulated price of token1 / token0
|
||||||
uint256 private blockNumberLast;
|
uint256 private blockNumberLast;
|
||||||
|
|
||||||
bool private notEntered = true;
|
bool private notEntered = true;
|
||||||
@ -77,39 +79,32 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran
|
|||||||
return (reserves.token0, reserves.token1);
|
return (reserves.token0, reserves.token1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getReservesCumulative() external view returns (uint128, uint128, uint128, uint128) {
|
function getAccumulatedPrices() external view returns (uint256, uint256) {
|
||||||
require(blockNumberLast > 0, "UniswapV2: NOT_INITIALIZED");
|
require(blockNumberLast > 0, "UniswapV2: NOT_INITIALIZED");
|
||||||
|
|
||||||
TokenData memory reservesCumulativeNext;
|
|
||||||
TokenData memory reservesCumulativeOverflowsNext;
|
|
||||||
// replicate the logic in update
|
// replicate the logic in update
|
||||||
if (block.number > blockNumberLast) {
|
if (block.number > blockNumberLast) {
|
||||||
uint128 blocksElapsed = (block.number - blockNumberLast).downcast128();
|
uint128 blocksElapsed = (block.number - blockNumberLast).downcast128();
|
||||||
|
|
||||||
TokenData memory remaindersMul;
|
// get the prices according to the reserves as of the last official interaction with the contract
|
||||||
TokenData memory overflowsMul;
|
MOCK_Decimal.Decimal memory priceToken0 = MOCK_Decimal.div(reserves.token0, reserves.token1);
|
||||||
(remaindersMul.token0, overflowsMul.token0) = reserves.token0.omul(blocksElapsed);
|
MOCK_Decimal.Decimal memory priceToken1 = MOCK_Decimal.div(reserves.token1, reserves.token0);
|
||||||
(remaindersMul.token1, overflowsMul.token1) = reserves.token1.omul(blocksElapsed);
|
|
||||||
|
|
||||||
TokenData memory overflowsAdd;
|
// multiply these prices by the number of elapsed blocks
|
||||||
(reservesCumulativeNext.token0, overflowsAdd.token0) = reservesCumulative.token0.oadd(remaindersMul.token0);
|
MOCK_Decimal.Decimal memory priceToken0Accumulated = MOCK_Decimal.mul(priceToken0, blocksElapsed);
|
||||||
(reservesCumulativeNext.token1, overflowsAdd.token1) = reservesCumulative.token1.oadd(remaindersMul.token1);
|
MOCK_Decimal.Decimal memory priceToken1Accumulated = MOCK_Decimal.mul(priceToken1, blocksElapsed);
|
||||||
|
|
||||||
reservesCumulativeOverflowsNext = TokenData({
|
|
||||||
token0: reservesCumulativeOverflows.token0.add(overflowsMul.token0.add(overflowsAdd.token0)),
|
|
||||||
token1: reservesCumulativeOverflows.token1.add(overflowsMul.token1.add(overflowsAdd.token1))
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
reservesCumulativeNext = reservesCumulative;
|
|
||||||
reservesCumulativeOverflowsNext = reservesCumulativeOverflows;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// add the accumulated prices to the global accumulators
|
||||||
return (
|
return (
|
||||||
reservesCumulativeNext.token0,
|
MOCK_Decimal.add(accumulatedPriceToken0, priceToken0Accumulated).data,
|
||||||
reservesCumulativeNext.token1,
|
MOCK_Decimal.add(accumulatedPriceToken1, priceToken1Accumulated).data
|
||||||
reservesCumulativeOverflowsNext.token0,
|
|
||||||
reservesCumulativeOverflowsNext.token1
|
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
accumulatedPriceToken0.data,
|
||||||
|
accumulatedPriceToken1.data
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getBlockNumberLast() external view returns (uint256) {
|
function getBlockNumberLast() external view returns (uint256) {
|
||||||
@ -133,30 +128,17 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran
|
|||||||
if (blockNumberLast > 0) {
|
if (blockNumberLast > 0) {
|
||||||
uint128 blocksElapsed = (block.number - blockNumberLast).downcast128();
|
uint128 blocksElapsed = (block.number - blockNumberLast).downcast128();
|
||||||
|
|
||||||
// TODO address ratio of sum / sum of ratios / price accumulator issue
|
// get the prices according to the reserves as of the last official interaction with the contract
|
||||||
|
MOCK_Decimal.Decimal memory priceToken0 = MOCK_Decimal.div(reserves.token0, reserves.token1);
|
||||||
|
MOCK_Decimal.Decimal memory priceToken1 = MOCK_Decimal.div(reserves.token1, reserves.token0);
|
||||||
|
|
||||||
// multiply previous reserves by elapsed blocks in an overflow-safe way
|
// multiply these prices by the number of elapsed blocks
|
||||||
TokenData memory remaindersMul;
|
MOCK_Decimal.Decimal memory priceToken0Accumulated = MOCK_Decimal.mul(priceToken0, blocksElapsed);
|
||||||
TokenData memory overflowsMul;
|
MOCK_Decimal.Decimal memory priceToken1Accumulated = MOCK_Decimal.mul(priceToken1, blocksElapsed);
|
||||||
(remaindersMul.token0, overflowsMul.token0) = reserves.token0.omul(blocksElapsed);
|
|
||||||
(remaindersMul.token1, overflowsMul.token1) = reserves.token1.omul(blocksElapsed);
|
|
||||||
|
|
||||||
// update cumulative reserves in an overflow-safe way
|
// add these incremental accumulated prices to the global accumulators
|
||||||
TokenData memory overflowsAdd;
|
accumulatedPriceToken0 = MOCK_Decimal.add(accumulatedPriceToken0, priceToken0Accumulated);
|
||||||
(reservesCumulative.token0, overflowsAdd.token0) = reservesCumulative.token0.oadd(remaindersMul.token0);
|
accumulatedPriceToken1 = MOCK_Decimal.add(accumulatedPriceToken1, priceToken1Accumulated);
|
||||||
(reservesCumulative.token1, overflowsAdd.token1) = reservesCumulative.token1.oadd(remaindersMul.token1);
|
|
||||||
|
|
||||||
// update cumulative reserves overflows
|
|
||||||
TokenData memory overflows = TokenData({
|
|
||||||
token0: overflowsMul.token0.add(overflowsAdd.token0),
|
|
||||||
token1: overflowsMul.token1.add(overflowsAdd.token1)
|
|
||||||
});
|
|
||||||
if (overflows.token0 > 0 || overflows.token1 > 0) {
|
|
||||||
reservesCumulativeOverflows = TokenData({
|
|
||||||
token0: reservesCumulativeOverflows.token0.add(overflows.token0),
|
|
||||||
token1: reservesCumulativeOverflows.token1.add(overflows.token1)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the last block number
|
// update the last block number
|
||||||
|
|||||||
20
contracts/libraries/MOCK_Decimal.sol
Normal file
20
contracts/libraries/MOCK_Decimal.sol
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
pragma solidity 0.5.12;
|
||||||
|
|
||||||
|
// mock fixed- or floating-point math
|
||||||
|
library MOCK_Decimal {
|
||||||
|
struct Decimal {
|
||||||
|
uint256 data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function div(uint128 numerator, uint128 denominator) internal pure returns (Decimal memory) {
|
||||||
|
return Decimal(numerator / denominator);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mul(Decimal memory a, uint128 b) internal pure returns (Decimal memory) {
|
||||||
|
return Decimal(a.data * b);
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(Decimal memory a, Decimal memory b) internal pure returns (Decimal memory) {
|
||||||
|
return Decimal(a.data + b.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,15 +10,4 @@ library SafeMath128 {
|
|||||||
function mul(uint128 x, uint128 y) internal pure returns (uint128 z) {
|
function mul(uint128 x, uint128 y) internal pure returns (uint128 z) {
|
||||||
require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
|
require(y == 0 || (z = x * y) / y == x, "ds-math-mul-overflow");
|
||||||
}
|
}
|
||||||
|
|
||||||
function oadd(uint128 w, uint128 x) internal pure returns (uint128 y, uint128 z) {
|
|
||||||
uint256 sum = uint256(w) + x;
|
|
||||||
z = uint128(sum / uint128(-1));
|
|
||||||
y = uint128(sum % uint128(-1));
|
|
||||||
}
|
|
||||||
function omul(uint128 w, uint128 x) internal pure returns (uint128 y, uint128 z) {
|
|
||||||
uint256 product = uint256(w) * x;
|
|
||||||
z = uint128(product / uint128(-1));
|
|
||||||
y = uint128(product % uint128(-1));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user