mock out price accumulator
This commit is contained in:
@ -4,6 +4,7 @@ import "./interfaces/IUniswapV2.sol";
|
||||
|
||||
import "./libraries/Math.sol";
|
||||
import "./libraries/SafeMath128.sol";
|
||||
import "./libraries/MOCK_Decimal.sol";
|
||||
|
||||
import "./token/ERC20.sol";
|
||||
import "./token/SafeTransfer.sol";
|
||||
@ -22,8 +23,9 @@ contract UniswapV2 is IUniswapV2, ERC20("Uniswap V2", "UNI-V2", 18, 0), SafeTran
|
||||
address public token1;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
function getReservesCumulative() external view returns (uint128, uint128, uint128, uint128) {
|
||||
function getAccumulatedPrices() external view returns (uint256, uint256) {
|
||||
require(blockNumberLast > 0, "UniswapV2: NOT_INITIALIZED");
|
||||
|
||||
TokenData memory reservesCumulativeNext;
|
||||
TokenData memory reservesCumulativeOverflowsNext;
|
||||
// replicate the logic in update
|
||||
if (block.number > blockNumberLast) {
|
||||
uint128 blocksElapsed = (block.number - blockNumberLast).downcast128();
|
||||
|
||||
TokenData memory remaindersMul;
|
||||
TokenData memory overflowsMul;
|
||||
(remaindersMul.token0, overflowsMul.token0) = reserves.token0.omul(blocksElapsed);
|
||||
(remaindersMul.token1, overflowsMul.token1) = reserves.token1.omul(blocksElapsed);
|
||||
// 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);
|
||||
|
||||
TokenData memory overflowsAdd;
|
||||
(reservesCumulativeNext.token0, overflowsAdd.token0) = reservesCumulative.token0.oadd(remaindersMul.token0);
|
||||
(reservesCumulativeNext.token1, overflowsAdd.token1) = reservesCumulative.token1.oadd(remaindersMul.token1);
|
||||
// multiply these prices by the number of elapsed blocks
|
||||
MOCK_Decimal.Decimal memory priceToken0Accumulated = MOCK_Decimal.mul(priceToken0, blocksElapsed);
|
||||
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))
|
||||
});
|
||||
// add the accumulated prices to the global accumulators
|
||||
return (
|
||||
MOCK_Decimal.add(accumulatedPriceToken0, priceToken0Accumulated).data,
|
||||
MOCK_Decimal.add(accumulatedPriceToken1, priceToken1Accumulated).data
|
||||
);
|
||||
} else {
|
||||
reservesCumulativeNext = reservesCumulative;
|
||||
reservesCumulativeOverflowsNext = reservesCumulativeOverflows;
|
||||
return (
|
||||
accumulatedPriceToken0.data,
|
||||
accumulatedPriceToken1.data
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
reservesCumulativeNext.token0,
|
||||
reservesCumulativeNext.token1,
|
||||
reservesCumulativeOverflowsNext.token0,
|
||||
reservesCumulativeOverflowsNext.token1
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
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
|
||||
TokenData memory remaindersMul;
|
||||
TokenData memory overflowsMul;
|
||||
(remaindersMul.token0, overflowsMul.token0) = reserves.token0.omul(blocksElapsed);
|
||||
(remaindersMul.token1, overflowsMul.token1) = reserves.token1.omul(blocksElapsed);
|
||||
// multiply these prices by the number of elapsed blocks
|
||||
MOCK_Decimal.Decimal memory priceToken0Accumulated = MOCK_Decimal.mul(priceToken0, blocksElapsed);
|
||||
MOCK_Decimal.Decimal memory priceToken1Accumulated = MOCK_Decimal.mul(priceToken1, blocksElapsed);
|
||||
|
||||
// update cumulative reserves in an overflow-safe way
|
||||
TokenData memory overflowsAdd;
|
||||
(reservesCumulative.token0, overflowsAdd.token0) = reservesCumulative.token0.oadd(remaindersMul.token0);
|
||||
(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)
|
||||
});
|
||||
}
|
||||
// add these incremental accumulated prices to the global accumulators
|
||||
accumulatedPriceToken0 = MOCK_Decimal.add(accumulatedPriceToken0, priceToken0Accumulated);
|
||||
accumulatedPriceToken1 = MOCK_Decimal.add(accumulatedPriceToken1, priceToken1Accumulated);
|
||||
}
|
||||
|
||||
// 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) {
|
||||
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