From b471eab625fbdd54fde605df22ccd824918129ba Mon Sep 17 00:00:00 2001 From: Edward Mulraney Date: Sat, 26 Jun 2021 11:31:34 +0100 Subject: [PATCH] add randomSeed assss optional paramter to hint functions --- contracts/protocols/mainnet/liquity.sol | 298 ++++++++++++------------ test/liquity.js | 10 +- 2 files changed, 157 insertions(+), 151 deletions(-) diff --git a/contracts/protocols/mainnet/liquity.sol b/contracts/protocols/mainnet/liquity.sol index 5e3907e..04c5ee5 100644 --- a/contracts/protocols/mainnet/liquity.sol +++ b/contracts/protocols/mainnet/liquity.sol @@ -2,196 +2,198 @@ pragma solidity ^0.6.0; pragma experimental ABIEncoderV2; interface TroveManagerLike { - function getBorrowingRateWithDecay() external view returns (uint); - function getTCR(uint _price) external view returns (uint); - function getCurrentICR(address _borrower, uint _price) external view returns (uint); - function checkRecoveryMode(uint _price) external view returns (bool); - function getEntireDebtAndColl(address _borrower) external view returns ( - uint debt, - uint coll, - uint pendingLUSDDebtReward, - uint pendingETHReward - ); + function getBorrowingRateWithDecay() external view returns (uint); + function getTCR(uint _price) external view returns (uint); + function getCurrentICR(address _borrower, uint _price) external view returns (uint); + function checkRecoveryMode(uint _price) external view returns (bool); + function getEntireDebtAndColl(address _borrower) external view returns ( + uint debt, + uint coll, + uint pendingLUSDDebtReward, + uint pendingETHReward + ); } interface StabilityPoolLike { - function getCompoundedLUSDDeposit(address _depositor) external view returns (uint); - function getDepositorETHGain(address _depositor) external view returns (uint); - function getDepositorLQTYGain(address _depositor) external view returns (uint); + function getCompoundedLUSDDeposit(address _depositor) external view returns (uint); + function getDepositorETHGain(address _depositor) external view returns (uint); + function getDepositorLQTYGain(address _depositor) external view returns (uint); } interface StakingLike { - function stakes(address owner) external view returns (uint); - function getPendingETHGain(address _user) external view returns (uint); - function getPendingLUSDGain(address _user) external view returns (uint); + function stakes(address owner) external view returns (uint); + function getPendingETHGain(address _user) external view returns (uint); + function getPendingLUSDGain(address _user) external view returns (uint); } interface PoolLike { - function getETH() external view returns (uint); + function getETH() external view returns (uint); } interface HintHelpersLike { - function computeNominalCR(uint _coll, uint _debt) external pure returns (uint); - function computeCR(uint _coll, uint _debt, uint _price) external pure returns (uint); - function getApproxHint(uint _CR, uint _numTrials, uint _inputRandomSeed) external view returns ( - address hintAddress, - uint diff, - uint latestRandomSeed - ); - function getRedemptionHints(uint _LUSDamount, uint _price, uint _maxIterations) external view returns ( - address firstHint, - uint partialRedemptionHintNICR, - uint truncatedLUSDamount - ); + function computeNominalCR(uint _coll, uint _debt) external pure returns (uint); + function computeCR(uint _coll, uint _debt, uint _price) external pure returns (uint); + function getApproxHint(uint _CR, uint _numTrials, uint _inputRandomSeed) external view returns ( + address hintAddress, + uint diff, + uint latestRandomSeed + ); + function getRedemptionHints(uint _LUSDamount, uint _price, uint _maxIterations) external view returns ( + address firstHint, + uint partialRedemptionHintNICR, + uint truncatedLUSDamount + ); } interface SortedTrovesLike { - function getSize() external view returns (uint256); - function findInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (address, address); + function getSize() external view returns (uint256); + function findInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (address, address); } contract Math { - /* DSMath add */ - function add(uint x, uint y) internal pure returns (uint z) { - require((z = x + y) >= x, "math-not-safe"); - } - - /* DSMath mul */ - function mul(uint x, uint y) internal pure returns (uint z) { - require(y == 0 || (z = x * y) / y == x, "math-not-safe"); + /* DSMath add */ + function add(uint x, uint y) internal pure returns (uint z) { + require((z = x + y) >= x, "math-not-safe"); } + + /* DSMath mul */ + function mul(uint x, uint y) internal pure returns (uint z) { + require(y == 0 || (z = x * y) / y == x, "math-not-safe"); + } - /* Uniswap V2 sqrt */ - function sqrt(uint y) internal pure returns (uint z) { - if (y > 3) { - z = y; - uint x = y / 2 + 1; - while (x < z) { - z = x; - x = (y / x + x) / 2; - } - } else if (y != 0) { - z = 1; - } - } + /* Uniswap V2 sqrt */ + function sqrt(uint y) internal pure returns (uint z) { + if (y > 3) { + z = y; + uint x = y / 2 + 1; + while (x < z) { + z = x; + x = (y / x + x) / 2; + } + } else if (y != 0) { + z = 1; + } + } } contract Helpers is Math { - TroveManagerLike internal constant troveManager = - TroveManagerLike(0xA39739EF8b0231DbFA0DcdA07d7e29faAbCf4bb2); + TroveManagerLike internal constant troveManager = + TroveManagerLike(0xA39739EF8b0231DbFA0DcdA07d7e29faAbCf4bb2); - StabilityPoolLike internal constant stabilityPool = - StabilityPoolLike(0x66017D22b0f8556afDd19FC67041899Eb65a21bb); + StabilityPoolLike internal constant stabilityPool = + StabilityPoolLike(0x66017D22b0f8556afDd19FC67041899Eb65a21bb); - StakingLike internal constant staking = - StakingLike(0x4f9Fbb3f1E99B56e0Fe2892e623Ed36A76Fc605d); + StakingLike internal constant staking = + StakingLike(0x4f9Fbb3f1E99B56e0Fe2892e623Ed36A76Fc605d); - PoolLike internal constant activePool = - PoolLike(0xDf9Eb223bAFBE5c5271415C75aeCD68C21fE3D7F); - - PoolLike internal constant defaultPool = - PoolLike(0x896a3F03176f05CFbb4f006BfCd8723F2B0D741C); + PoolLike internal constant activePool = + PoolLike(0xDf9Eb223bAFBE5c5271415C75aeCD68C21fE3D7F); + + PoolLike internal constant defaultPool = + PoolLike(0x896a3F03176f05CFbb4f006BfCd8723F2B0D741C); - HintHelpersLike internal constant hintHelpers = - HintHelpersLike(0xE84251b93D9524E0d2e621Ba7dc7cb3579F997C0); - - SortedTrovesLike internal constant sortedTroves = - SortedTrovesLike(0x8FdD3fbFEb32b28fb73555518f8b361bCeA741A6); - - struct Trove { - uint collateral; - uint debt; - uint icr; - } + HintHelpersLike internal constant hintHelpers = + HintHelpersLike(0xE84251b93D9524E0d2e621Ba7dc7cb3579F997C0); + + SortedTrovesLike internal constant sortedTroves = + SortedTrovesLike(0x8FdD3fbFEb32b28fb73555518f8b361bCeA741A6); + + struct Trove { + uint collateral; + uint debt; + uint icr; + } - struct StabilityDeposit { - uint deposit; - uint ethGain; - uint lqtyGain; - } + struct StabilityDeposit { + uint deposit; + uint ethGain; + uint lqtyGain; + } - struct Stake { - uint amount; - uint ethGain; - uint lusdGain; - } + struct Stake { + uint amount; + uint ethGain; + uint lusdGain; + } - struct Position { - Trove trove; - StabilityDeposit stability; - Stake stake; - } + struct Position { + Trove trove; + StabilityDeposit stability; + Stake stake; + } - struct System { - uint borrowFee; - uint ethTvl; - uint tcr; - bool isInRecoveryMode; - } + struct System { + uint borrowFee; + uint ethTvl; + uint tcr; + bool isInRecoveryMode; + } } contract Resolver is Helpers { - function getTrove(address owner, uint oracleEthPrice) public view returns (Trove memory) { - (uint debt, uint collateral, , ) = troveManager.getEntireDebtAndColl(owner); - uint icr = troveManager.getCurrentICR(owner, oracleEthPrice); - return Trove(collateral, debt, icr); - } + function getTrove(address owner, uint oracleEthPrice) public view returns (Trove memory) { + (uint debt, uint collateral, , ) = troveManager.getEntireDebtAndColl(owner); + uint icr = troveManager.getCurrentICR(owner, oracleEthPrice); + return Trove(collateral, debt, icr); + } - function getStabilityDeposit(address owner) public view returns (StabilityDeposit memory) { - uint deposit = stabilityPool.getCompoundedLUSDDeposit(owner); - uint ethGain = stabilityPool.getDepositorETHGain(owner); - uint lqtyGain = stabilityPool.getDepositorLQTYGain(owner); - return StabilityDeposit(deposit, ethGain, lqtyGain); - } + function getStabilityDeposit(address owner) public view returns (StabilityDeposit memory) { + uint deposit = stabilityPool.getCompoundedLUSDDeposit(owner); + uint ethGain = stabilityPool.getDepositorETHGain(owner); + uint lqtyGain = stabilityPool.getDepositorLQTYGain(owner); + return StabilityDeposit(deposit, ethGain, lqtyGain); + } - function getStake(address owner) public view returns (Stake memory) { - uint amount = staking.stakes(owner); - uint ethGain = staking.getPendingETHGain(owner); - uint lusdGain = staking.getPendingLUSDGain(owner); - return Stake(amount, ethGain, lusdGain); - } + function getStake(address owner) public view returns (Stake memory) { + uint amount = staking.stakes(owner); + uint ethGain = staking.getPendingETHGain(owner); + uint lusdGain = staking.getPendingLUSDGain(owner); + return Stake(amount, ethGain, lusdGain); + } - function getPosition(address owner, uint oracleEthPrice) external view returns (Position memory) { - Trove memory trove = getTrove(owner, oracleEthPrice); - StabilityDeposit memory stability = getStabilityDeposit(owner); - Stake memory stake = getStake(owner); - return Position(trove, stability, stake); - } + function getPosition(address owner, uint oracleEthPrice) external view returns (Position memory) { + Trove memory trove = getTrove(owner, oracleEthPrice); + StabilityDeposit memory stability = getStabilityDeposit(owner); + Stake memory stake = getStake(owner); + return Position(trove, stability, stake); + } - function getSystemState(uint oracleEthPrice) external view returns (System memory) { - uint borrowFee = troveManager.getBorrowingRateWithDecay(); - uint ethTvl = add(activePool.getETH(), defaultPool.getETH()); - uint tcr = troveManager.getTCR(oracleEthPrice); - bool isInRecoveryMode = troveManager.checkRecoveryMode(oracleEthPrice); - return System(borrowFee, ethTvl, tcr, isInRecoveryMode); - } + function getSystemState(uint oracleEthPrice) external view returns (System memory) { + uint borrowFee = troveManager.getBorrowingRateWithDecay(); + uint ethTvl = add(activePool.getETH(), defaultPool.getETH()); + uint tcr = troveManager.getTCR(oracleEthPrice); + bool isInRecoveryMode = troveManager.checkRecoveryMode(oracleEthPrice); + return System(borrowFee, ethTvl, tcr, isInRecoveryMode); + } - function getTrovePositionHints(uint collateral, uint debt, uint searchIterations) external view returns ( - address upperHint, - address lowerHint - ) { - // See: https://github.com/liquity/dev#supplying-hints-to-trove-operations - uint nominalCr = hintHelpers.computeNominalCR(collateral, debt); - searchIterations = searchIterations == 0 ? mul(10, sqrt(sortedTroves.getSize())) : searchIterations; - (address hintAddress, ,) = hintHelpers.getApproxHint(nominalCr, searchIterations, 3); - return sortedTroves.findInsertPosition(nominalCr, hintAddress, hintAddress); - } + function getTrovePositionHints(uint collateral, uint debt, uint searchIterations, uint randomSeed) external view returns ( + address upperHint, + address lowerHint + ) { + // See: https://github.com/liquity/dev#supplying-hints-to-trove-operations + uint nominalCr = hintHelpers.computeNominalCR(collateral, debt); + searchIterations = searchIterations == 0 ? mul(10, sqrt(sortedTroves.getSize())) : searchIterations; + randomSeed = randomSeed == 0 ? block.number : randomSeed; + (address hintAddress, ,) = hintHelpers.getApproxHint(nominalCr, searchIterations, randomSeed); + return sortedTroves.findInsertPosition(nominalCr, hintAddress, hintAddress); + } - function getRedemptionPositionHints(uint amount, uint oracleEthPrice, uint searchIterations) external view returns ( - uint partialHintNicr, - address firstHint, - address upperHint, - address lowerHint - ) { - // See: https://github.com/liquity/dev#hints-for-redeemcollateral - (firstHint, partialHintNicr, ) = hintHelpers.getRedemptionHints(amount, oracleEthPrice, 0); - searchIterations = searchIterations == 0 ? mul(10, sqrt(sortedTroves.getSize())) : searchIterations; - (address hintAddress, ,) = hintHelpers.getApproxHint(partialHintNicr, searchIterations, 3); - (upperHint, lowerHint) = sortedTroves.findInsertPosition(partialHintNicr, hintAddress, hintAddress); - } + function getRedemptionPositionHints(uint amount, uint oracleEthPrice, uint searchIterations, uint randomSeed) external view returns ( + uint partialHintNicr, + address firstHint, + address upperHint, + address lowerHint + ) { + // See: https://github.com/liquity/dev#hints-for-redeemcollateral + (firstHint, partialHintNicr, ) = hintHelpers.getRedemptionHints(amount, oracleEthPrice, 0); + searchIterations = searchIterations == 0 ? mul(10, sqrt(sortedTroves.getSize())) : searchIterations; + randomSeed = randomSeed == 0 ? block.number : randomSeed; + (address hintAddress, ,) = hintHelpers.getApproxHint(partialHintNicr, searchIterations, randomSeed); + (upperHint, lowerHint) = sortedTroves.findInsertPosition(partialHintNicr, hintAddress, hintAddress); + } } contract InstaLiquityResolver is Resolver { - string public constant name = "Liquity-Resolver-v1"; + string public constant name = "Liquity-Resolver-v1"; } diff --git a/test/liquity.js b/test/liquity.js index 59efbcc..b11b790 100644 --- a/test/liquity.js +++ b/test/liquity.js @@ -164,12 +164,14 @@ describe("InstaLiquityResolver", () => { describe("getTrovePositionHints()", () => { it("returns the upper and lower address of Troves nearest to the given Trove", async () => { const collateral = hre.ethers.utils.parseEther("10"); - const debt = hre.ethers.utils.parseUnits("5000", 18); + const debt = hre.ethers.utils.parseUnits("5000", 18); // 5,000 LUSD const searchIterations = 10; + const randomSeed = 3; const [upperHint, lowerHint] = await liquity.getTrovePositionHints( collateral, debt, - searchIterations + searchIterations, + randomSeed ); expect(upperHint).eq(expectedTrovePositionHints.upperHint); @@ -182,6 +184,7 @@ describe("InstaLiquityResolver", () => { const amount = hre.ethers.utils.parseUnits("10000", 18); // 10,000 LUSD const oracleEthPrice = await liquityPriceOracle.callStatic.fetchPrice(); const searchIterations = 10; + const randomSeed = 3; const [ partialRedemptionHintNicr, firstHint, @@ -190,7 +193,8 @@ describe("InstaLiquityResolver", () => { ] = await liquity.getRedemptionPositionHints( amount, oracleEthPrice, - searchIterations + searchIterations, + randomSeed ); expect(partialRedemptionHintNicr).eq(