add randomSeed assss optional paramter to hint functions

This commit is contained in:
Edward Mulraney 2021-06-26 11:31:34 +01:00
parent 4df8b8bf56
commit b471eab625
2 changed files with 157 additions and 151 deletions

View File

@ -2,196 +2,198 @@ pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2; pragma experimental ABIEncoderV2;
interface TroveManagerLike { interface TroveManagerLike {
function getBorrowingRateWithDecay() external view returns (uint); function getBorrowingRateWithDecay() external view returns (uint);
function getTCR(uint _price) external view returns (uint); function getTCR(uint _price) external view returns (uint);
function getCurrentICR(address _borrower, 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 checkRecoveryMode(uint _price) external view returns (bool);
function getEntireDebtAndColl(address _borrower) external view returns ( function getEntireDebtAndColl(address _borrower) external view returns (
uint debt, uint debt,
uint coll, uint coll,
uint pendingLUSDDebtReward, uint pendingLUSDDebtReward,
uint pendingETHReward uint pendingETHReward
); );
} }
interface StabilityPoolLike { interface StabilityPoolLike {
function getCompoundedLUSDDeposit(address _depositor) external view returns (uint); function getCompoundedLUSDDeposit(address _depositor) external view returns (uint);
function getDepositorETHGain(address _depositor) external view returns (uint); function getDepositorETHGain(address _depositor) external view returns (uint);
function getDepositorLQTYGain(address _depositor) external view returns (uint); function getDepositorLQTYGain(address _depositor) external view returns (uint);
} }
interface StakingLike { interface StakingLike {
function stakes(address owner) external view returns (uint); function stakes(address owner) external view returns (uint);
function getPendingETHGain(address _user) external view returns (uint); function getPendingETHGain(address _user) external view returns (uint);
function getPendingLUSDGain(address _user) external view returns (uint); function getPendingLUSDGain(address _user) external view returns (uint);
} }
interface PoolLike { interface PoolLike {
function getETH() external view returns (uint); function getETH() external view returns (uint);
} }
interface HintHelpersLike { interface HintHelpersLike {
function computeNominalCR(uint _coll, uint _debt) external pure returns (uint); function computeNominalCR(uint _coll, uint _debt) external pure returns (uint);
function computeCR(uint _coll, uint _debt, uint _price) 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 ( function getApproxHint(uint _CR, uint _numTrials, uint _inputRandomSeed) external view returns (
address hintAddress, address hintAddress,
uint diff, uint diff,
uint latestRandomSeed uint latestRandomSeed
); );
function getRedemptionHints(uint _LUSDamount, uint _price, uint _maxIterations) external view returns ( function getRedemptionHints(uint _LUSDamount, uint _price, uint _maxIterations) external view returns (
address firstHint, address firstHint,
uint partialRedemptionHintNICR, uint partialRedemptionHintNICR,
uint truncatedLUSDamount uint truncatedLUSDamount
); );
} }
interface SortedTrovesLike { interface SortedTrovesLike {
function getSize() external view returns (uint256); function getSize() external view returns (uint256);
function findInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (address, address); function findInsertPosition(uint256 _ICR, address _prevId, address _nextId) external view returns (address, address);
} }
contract Math { contract Math {
/* DSMath add */ /* DSMath add */
function add(uint x, uint y) internal pure returns (uint z) { function add(uint x, uint y) internal pure returns (uint z) {
require((z = x + y) >= x, "math-not-safe"); 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 */ /* DSMath mul */
function sqrt(uint y) internal pure returns (uint z) { function mul(uint x, uint y) internal pure returns (uint z) {
if (y > 3) { require(y == 0 || (z = x * y) / y == x, "math-not-safe");
z = y; }
uint x = y / 2 + 1;
while (x < z) { /* Uniswap V2 sqrt */
z = x; function sqrt(uint y) internal pure returns (uint z) {
x = (y / x + x) / 2; if (y > 3) {
} z = y;
} else if (y != 0) { uint x = y / 2 + 1;
z = 1; while (x < z) {
} z = x;
} x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
} }
contract Helpers is Math { contract Helpers is Math {
TroveManagerLike internal constant troveManager = TroveManagerLike internal constant troveManager =
TroveManagerLike(0xA39739EF8b0231DbFA0DcdA07d7e29faAbCf4bb2); TroveManagerLike(0xA39739EF8b0231DbFA0DcdA07d7e29faAbCf4bb2);
StabilityPoolLike internal constant stabilityPool = StabilityPoolLike internal constant stabilityPool =
StabilityPoolLike(0x66017D22b0f8556afDd19FC67041899Eb65a21bb); StabilityPoolLike(0x66017D22b0f8556afDd19FC67041899Eb65a21bb);
StakingLike internal constant staking = StakingLike internal constant staking =
StakingLike(0x4f9Fbb3f1E99B56e0Fe2892e623Ed36A76Fc605d); StakingLike(0x4f9Fbb3f1E99B56e0Fe2892e623Ed36A76Fc605d);
PoolLike internal constant activePool = PoolLike internal constant activePool =
PoolLike(0xDf9Eb223bAFBE5c5271415C75aeCD68C21fE3D7F); PoolLike(0xDf9Eb223bAFBE5c5271415C75aeCD68C21fE3D7F);
PoolLike internal constant defaultPool = PoolLike internal constant defaultPool =
PoolLike(0x896a3F03176f05CFbb4f006BfCd8723F2B0D741C); PoolLike(0x896a3F03176f05CFbb4f006BfCd8723F2B0D741C);
HintHelpersLike internal constant hintHelpers = HintHelpersLike internal constant hintHelpers =
HintHelpersLike(0xE84251b93D9524E0d2e621Ba7dc7cb3579F997C0); HintHelpersLike(0xE84251b93D9524E0d2e621Ba7dc7cb3579F997C0);
SortedTrovesLike internal constant sortedTroves = SortedTrovesLike internal constant sortedTroves =
SortedTrovesLike(0x8FdD3fbFEb32b28fb73555518f8b361bCeA741A6); SortedTrovesLike(0x8FdD3fbFEb32b28fb73555518f8b361bCeA741A6);
struct Trove { struct Trove {
uint collateral; uint collateral;
uint debt; uint debt;
uint icr; uint icr;
} }
struct StabilityDeposit { struct StabilityDeposit {
uint deposit; uint deposit;
uint ethGain; uint ethGain;
uint lqtyGain; uint lqtyGain;
} }
struct Stake { struct Stake {
uint amount; uint amount;
uint ethGain; uint ethGain;
uint lusdGain; uint lusdGain;
} }
struct Position { struct Position {
Trove trove; Trove trove;
StabilityDeposit stability; StabilityDeposit stability;
Stake stake; Stake stake;
} }
struct System { struct System {
uint borrowFee; uint borrowFee;
uint ethTvl; uint ethTvl;
uint tcr; uint tcr;
bool isInRecoveryMode; bool isInRecoveryMode;
} }
} }
contract Resolver is Helpers { contract Resolver is Helpers {
function getTrove(address owner, uint oracleEthPrice) public view returns (Trove memory) { function getTrove(address owner, uint oracleEthPrice) public view returns (Trove memory) {
(uint debt, uint collateral, , ) = troveManager.getEntireDebtAndColl(owner); (uint debt, uint collateral, , ) = troveManager.getEntireDebtAndColl(owner);
uint icr = troveManager.getCurrentICR(owner, oracleEthPrice); uint icr = troveManager.getCurrentICR(owner, oracleEthPrice);
return Trove(collateral, debt, icr); return Trove(collateral, debt, icr);
} }
function getStabilityDeposit(address owner) public view returns (StabilityDeposit memory) { function getStabilityDeposit(address owner) public view returns (StabilityDeposit memory) {
uint deposit = stabilityPool.getCompoundedLUSDDeposit(owner); uint deposit = stabilityPool.getCompoundedLUSDDeposit(owner);
uint ethGain = stabilityPool.getDepositorETHGain(owner); uint ethGain = stabilityPool.getDepositorETHGain(owner);
uint lqtyGain = stabilityPool.getDepositorLQTYGain(owner); uint lqtyGain = stabilityPool.getDepositorLQTYGain(owner);
return StabilityDeposit(deposit, ethGain, lqtyGain); return StabilityDeposit(deposit, ethGain, lqtyGain);
} }
function getStake(address owner) public view returns (Stake memory) { function getStake(address owner) public view returns (Stake memory) {
uint amount = staking.stakes(owner); uint amount = staking.stakes(owner);
uint ethGain = staking.getPendingETHGain(owner); uint ethGain = staking.getPendingETHGain(owner);
uint lusdGain = staking.getPendingLUSDGain(owner); uint lusdGain = staking.getPendingLUSDGain(owner);
return Stake(amount, ethGain, lusdGain); return Stake(amount, ethGain, lusdGain);
} }
function getPosition(address owner, uint oracleEthPrice) external view returns (Position memory) { function getPosition(address owner, uint oracleEthPrice) external view returns (Position memory) {
Trove memory trove = getTrove(owner, oracleEthPrice); Trove memory trove = getTrove(owner, oracleEthPrice);
StabilityDeposit memory stability = getStabilityDeposit(owner); StabilityDeposit memory stability = getStabilityDeposit(owner);
Stake memory stake = getStake(owner); Stake memory stake = getStake(owner);
return Position(trove, stability, stake); return Position(trove, stability, stake);
} }
function getSystemState(uint oracleEthPrice) external view returns (System memory) { function getSystemState(uint oracleEthPrice) external view returns (System memory) {
uint borrowFee = troveManager.getBorrowingRateWithDecay(); uint borrowFee = troveManager.getBorrowingRateWithDecay();
uint ethTvl = add(activePool.getETH(), defaultPool.getETH()); uint ethTvl = add(activePool.getETH(), defaultPool.getETH());
uint tcr = troveManager.getTCR(oracleEthPrice); uint tcr = troveManager.getTCR(oracleEthPrice);
bool isInRecoveryMode = troveManager.checkRecoveryMode(oracleEthPrice); bool isInRecoveryMode = troveManager.checkRecoveryMode(oracleEthPrice);
return System(borrowFee, ethTvl, tcr, isInRecoveryMode); return System(borrowFee, ethTvl, tcr, isInRecoveryMode);
} }
function getTrovePositionHints(uint collateral, uint debt, uint searchIterations) external view returns ( function getTrovePositionHints(uint collateral, uint debt, uint searchIterations, uint randomSeed) external view returns (
address upperHint, address upperHint,
address lowerHint address lowerHint
) { ) {
// See: https://github.com/liquity/dev#supplying-hints-to-trove-operations // See: https://github.com/liquity/dev#supplying-hints-to-trove-operations
uint nominalCr = hintHelpers.computeNominalCR(collateral, debt); uint nominalCr = hintHelpers.computeNominalCR(collateral, debt);
searchIterations = searchIterations == 0 ? mul(10, sqrt(sortedTroves.getSize())) : searchIterations; searchIterations = searchIterations == 0 ? mul(10, sqrt(sortedTroves.getSize())) : searchIterations;
(address hintAddress, ,) = hintHelpers.getApproxHint(nominalCr, searchIterations, 3); randomSeed = randomSeed == 0 ? block.number : randomSeed;
return sortedTroves.findInsertPosition(nominalCr, hintAddress, hintAddress); (address hintAddress, ,) = hintHelpers.getApproxHint(nominalCr, searchIterations, randomSeed);
} return sortedTroves.findInsertPosition(nominalCr, hintAddress, hintAddress);
}
function getRedemptionPositionHints(uint amount, uint oracleEthPrice, uint searchIterations) external view returns ( function getRedemptionPositionHints(uint amount, uint oracleEthPrice, uint searchIterations, uint randomSeed) external view returns (
uint partialHintNicr, uint partialHintNicr,
address firstHint, address firstHint,
address upperHint, address upperHint,
address lowerHint address lowerHint
) { ) {
// See: https://github.com/liquity/dev#hints-for-redeemcollateral // See: https://github.com/liquity/dev#hints-for-redeemcollateral
(firstHint, partialHintNicr, ) = hintHelpers.getRedemptionHints(amount, oracleEthPrice, 0); (firstHint, partialHintNicr, ) = hintHelpers.getRedemptionHints(amount, oracleEthPrice, 0);
searchIterations = searchIterations == 0 ? mul(10, sqrt(sortedTroves.getSize())) : searchIterations; searchIterations = searchIterations == 0 ? mul(10, sqrt(sortedTroves.getSize())) : searchIterations;
(address hintAddress, ,) = hintHelpers.getApproxHint(partialHintNicr, searchIterations, 3); randomSeed = randomSeed == 0 ? block.number : randomSeed;
(upperHint, lowerHint) = sortedTroves.findInsertPosition(partialHintNicr, hintAddress, hintAddress); (address hintAddress, ,) = hintHelpers.getApproxHint(partialHintNicr, searchIterations, randomSeed);
} (upperHint, lowerHint) = sortedTroves.findInsertPosition(partialHintNicr, hintAddress, hintAddress);
}
} }
contract InstaLiquityResolver is Resolver { contract InstaLiquityResolver is Resolver {
string public constant name = "Liquity-Resolver-v1"; string public constant name = "Liquity-Resolver-v1";
} }

View File

@ -164,12 +164,14 @@ describe("InstaLiquityResolver", () => {
describe("getTrovePositionHints()", () => { describe("getTrovePositionHints()", () => {
it("returns the upper and lower address of Troves nearest to the given Trove", async () => { it("returns the upper and lower address of Troves nearest to the given Trove", async () => {
const collateral = hre.ethers.utils.parseEther("10"); 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 searchIterations = 10;
const randomSeed = 3;
const [upperHint, lowerHint] = await liquity.getTrovePositionHints( const [upperHint, lowerHint] = await liquity.getTrovePositionHints(
collateral, collateral,
debt, debt,
searchIterations searchIterations,
randomSeed
); );
expect(upperHint).eq(expectedTrovePositionHints.upperHint); expect(upperHint).eq(expectedTrovePositionHints.upperHint);
@ -182,6 +184,7 @@ describe("InstaLiquityResolver", () => {
const amount = hre.ethers.utils.parseUnits("10000", 18); // 10,000 LUSD const amount = hre.ethers.utils.parseUnits("10000", 18); // 10,000 LUSD
const oracleEthPrice = await liquityPriceOracle.callStatic.fetchPrice(); const oracleEthPrice = await liquityPriceOracle.callStatic.fetchPrice();
const searchIterations = 10; const searchIterations = 10;
const randomSeed = 3;
const [ const [
partialRedemptionHintNicr, partialRedemptionHintNicr,
firstHint, firstHint,
@ -190,7 +193,8 @@ describe("InstaLiquityResolver", () => {
] = await liquity.getRedemptionPositionHints( ] = await liquity.getRedemptionPositionHints(
amount, amount,
oracleEthPrice, oracleEthPrice,
searchIterations searchIterations,
randomSeed
); );
expect(partialRedemptionHintNicr).eq( expect(partialRedemptionHintNicr).eq(