Skip to content
This repository has been archived by the owner on May 24, 2024. It is now read-only.

Commit

Permalink
Merge pull request #143 from euler-xyz/pToken-price
Browse files Browse the repository at this point in the history
pToken price decoding
  • Loading branch information
dglowinski authored Jul 13, 2022
2 parents 85abe8d + 5b647f8 commit 0fade57
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 15 deletions.
2 changes: 1 addition & 1 deletion addresses/euler-addresses-mainnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"exec": "0x155020C32cEb5E1BFdD6217c2E7906c92bcAC8c1",
"eToken": "0xEE385A1E2F0Bfe79D795a9AC680c4aB89033AbAB",
"dToken": "0xe374b7a44Dcd6b6eed4a6A845B6e162Ed52924e5",
"riskManager": "0x98D7A0b0c895f6C602fE2E6B3AA83EAFAbb92Ce6",
"riskManager": "0xB4d68bC247a1DEF6FB0B6d0F69906C5B75Afe2aD",
"irmDefault": "0x68004911694EC42f0c56B7144a6A5281fFDD38F7",
"irmClassMajor": "0xD75870dCbd1521E6CAd7566FbcA35D72e238572B",
"irmClassMega": "0x894c7499F240c0E0205c56d26A5D609C8408De2D",
Expand Down
2 changes: 1 addition & 1 deletion addresses/euler-addresses-ropsten.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"exec": "0x66aD957468eC68Cf88C505FC6166bC7D1c3E36b4",
"eToken": "0x1675e1da3c621af02102cde23d70ba7d49df94d2",
"dToken": "0x28849FeBDfa4267112c657985C991eaF876352A1",
"riskManager": "0x061651600e11C76BBb4C33315fabb3a194f36222",
"riskManager": "0x578C84b499DEb7e82C702042FA494F61e789731D",
"irmDefault": "0xd26285F0237EbD3316B555c6d5Ef32c6D1F66a3f",
"irmClassMega": "0xf6a0d1aeD7adB83028D164e1E28C26E627946f9d",
"swap": "0x4174b8CD7c08C53343994682ffD864ce959ea415"
Expand Down
27 changes: 14 additions & 13 deletions contracts/modules/RiskManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,11 +127,11 @@ contract RiskManager is IRiskManager, BaseLogic {
}


function decodeSqrtPriceX96(AssetCache memory assetCache, uint sqrtPriceX96) private view returns (uint price) {
if (uint160(assetCache.underlying) < uint160(referenceAsset)) {
price = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, uint(2**(96*2)) / 1e18) / assetCache.underlyingDecimalsScaler;
function decodeSqrtPriceX96(address underlying, uint underlyingDecimalsScaler, uint sqrtPriceX96) private view returns (uint price) {
if (uint160(underlying) < uint160(referenceAsset)) {
price = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, uint(2**(96*2)) / 1e18) / underlyingDecimalsScaler;
} else {
price = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, uint(2**(96*2)) / (1e18 * assetCache.underlyingDecimalsScaler));
price = FullMath.mulDiv(sqrtPriceX96, sqrtPriceX96, uint(2**(96*2)) / (1e18 * underlyingDecimalsScaler));
if (price == 0) return 1e36;
price = 1e36 / price;
}
Expand All @@ -140,7 +140,7 @@ contract RiskManager is IRiskManager, BaseLogic {
else if (price == 0) price = 1;
}

function callUniswapObserve(AssetCache memory assetCache, address pool, uint ago) private view returns (uint, uint) {
function callUniswapObserve(address underlying, uint underlyingDecimalsScaler, address pool, uint ago) private view returns (uint, uint) {
uint32[] memory secondsAgos = new uint32[](2);

secondsAgos[0] = uint32(ago);
Expand Down Expand Up @@ -181,7 +181,7 @@ contract RiskManager is IRiskManager, BaseLogic {

uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(tick);

return (decodeSqrtPriceX96(assetCache, sqrtPriceX96), ago);
return (decodeSqrtPriceX96(underlying, underlyingDecimalsScaler, sqrtPriceX96), ago);
}

function callChainlinkLatestAnswer(address chainlinkAggregator) private view returns (uint price) {
Expand All @@ -200,7 +200,7 @@ contract RiskManager is IRiskManager, BaseLogic {
if (price > 1e36) price = 1e36;
}

function resolvePricingConfig(AssetCache memory assetCache, AssetConfig memory config) private view returns (address underlying, uint16 pricingType, uint32 pricingParameters, uint24 twapWindow) {
function resolvePricingConfig(AssetCache memory assetCache, AssetConfig memory config) private view returns (address underlying, uint16 pricingType, uint32 pricingParameters, uint24 twapWindow, uint underlyingDecimalsScaler) {
if (assetCache.pricingType == PRICINGTYPE__FORWARDED) {
underlying = pTokenLookup[assetCache.underlying];

Expand All @@ -210,33 +210,35 @@ contract RiskManager is IRiskManager, BaseLogic {
AssetStorage storage newAssetStorage = eTokenLookup[newConfig.eTokenAddress];
pricingType = newAssetStorage.pricingType;
pricingParameters = newAssetStorage.pricingParameters;
underlyingDecimalsScaler = 10**(18 - newAssetStorage.underlyingDecimals);

require(pricingType != PRICINGTYPE__FORWARDED, "e/nested-price-forwarding");
} else {
underlying = assetCache.underlying;
pricingType = assetCache.pricingType;
pricingParameters = assetCache.pricingParameters;
twapWindow = config.twapWindow;
underlyingDecimalsScaler = assetCache.underlyingDecimalsScaler;
}
}

function getPriceInternal(AssetCache memory assetCache, AssetConfig memory config) public view FREEMEM returns (uint twap, uint twapPeriod) {
(address underlying, uint16 pricingType, uint32 pricingParameters, uint24 twapWindow) = resolvePricingConfig(assetCache, config);
(address underlying, uint16 pricingType, uint32 pricingParameters, uint24 twapWindow, uint underlyingDecimalsScaler) = resolvePricingConfig(assetCache, config);

if (pricingType == PRICINGTYPE__PEGGED) {
twap = 1e18;
twapPeriod = twapWindow;
} else if (pricingType == PRICINGTYPE__UNISWAP3_TWAP) {
address pool = computeUniswapPoolAddress(underlying, uint24(pricingParameters));
(twap, twapPeriod) = callUniswapObserve(assetCache, pool, twapWindow);
(twap, twapPeriod) = callUniswapObserve(underlying, underlyingDecimalsScaler, pool, twapWindow);
} else if (pricingType == PRICINGTYPE__CHAINLINK) {
twap = callChainlinkLatestAnswer(chainlinkPriceFeedLookup[underlying]);
twapPeriod = 0;

// if price invalid and uniswap fallback pool configured get the price from uniswap
if (twap == 0 && uint24(pricingParameters) != 0) {
address pool = computeUniswapPoolAddress(underlying, uint24(pricingParameters));
(twap, twapPeriod) = callUniswapObserve(assetCache, pool, twapWindow);
(twap, twapPeriod) = callUniswapObserve(underlying, underlyingDecimalsScaler, pool, twapWindow);
}

require(twap != 0, "e/unable-to-get-the-price");
Expand All @@ -263,15 +265,14 @@ contract RiskManager is IRiskManager, BaseLogic {

(twap, twapPeriod) = getPriceInternal(assetCache, config);

(address newUnderlying, uint16 pricingType, uint32 pricingParameters,) = resolvePricingConfig(assetCache, config);
(address newUnderlying, uint16 pricingType, uint32 pricingParameters, , uint underlyingDecimalsScaler) = resolvePricingConfig(assetCache, config);

if (pricingType == PRICINGTYPE__PEGGED) {
currPrice = 1e18;
} else if (pricingType == PRICINGTYPE__UNISWAP3_TWAP || pricingType == PRICINGTYPE__FORWARDED) {
AssetCache memory newAssetCache = loadAssetCacheRO(newUnderlying, assetStorage);
address pool = computeUniswapPoolAddress(newUnderlying, uint24(pricingParameters));
(uint160 sqrtPriceX96,,,,,,) = IUniswapV3Pool(pool).slot0();
currPrice = decodeSqrtPriceX96(newAssetCache, sqrtPriceX96);
currPrice = decodeSqrtPriceX96(newUnderlying, underlyingDecimalsScaler, sqrtPriceX96);
} else if (pricingType == PRICINGTYPE__CHAINLINK) {
currPrice = twap;
} else {
Expand Down
36 changes: 36 additions & 0 deletions test/pToken.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,42 @@ et.testSet({
})


.test({
desc: "price forwarding",
actions: ctx => [
() => { et.assert(ethers.BigNumber.from(ctx.contracts.tokens.TST.address).gt(ctx.contracts.tokens.WETH.address), 'TST/WETH pair is not inverted') },
{ action: 'updateUniswapPrice', pair: 'TST/WETH', price: '1.23', },
{ call: 'exec.getPrice', args: [ctx.contracts.tokens.TST.address], onResult: r => {
et.equals(r.twap, '1.23', '0.0001')
}},
{ call: 'exec.getPrice', args: [ctx.contracts.pTokens.pTST.address], onResult: r => {
et.equals(r.twap, '1.23', '0.0001')
}}
],
})


.test({
desc: "price forwarding 2",
actions: ctx => [
{ action: 'setAssetConfig', tok: 'TST6', config: { collateralFactor: 0.7, }, },
{ send: 'markets.activatePToken', args: [ctx.contracts.tokens.TST6.address], },
async () => {
et.assert(ethers.BigNumber.from(ctx.contracts.tokens.TST6.address).lt(ctx.contracts.tokens.WETH.address), 'TST6/WETH pair is inverted');
let pTokenAddr = await ctx.contracts.markets.underlyingToPToken(ctx.contracts.tokens.TST6.address);
ctx.contracts.pTokens['pTST6'] = await ethers.getContractAt('PToken', pTokenAddr);
},
{ action: 'updateUniswapPrice', pair: 'TST6/WETH', price: '1.23', },
{ call: 'exec.getPrice', args: [ctx.contracts.tokens.TST6.address], onResult: r => {
et.equals(r.twap, '1.23', '0.0001')
}},
{ call: 'exec.getPrice', args: [() => ctx.contracts.pTokens.pTST6.address], onResult: r => {
et.equals(r.twap, '1.23', '0.0001')
}}
],
})


.test({
desc: "activate already activated ptoken",
actions: ctx => [
Expand Down

0 comments on commit 0fade57

Please sign in to comment.