Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FXD-95 adding setPriceForBatch #281

Merged
merged 1 commit into from
Mar 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contracts/main/interfaces/ISetPrice.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ pragma solidity 0.8.17;

interface ISetPrice {
function setPrice(bytes32 _collateralPoolId) external;
function setPriceForBatch(bytes32[] calldata _collateralPoolIds) external;
}
27 changes: 20 additions & 7 deletions contracts/main/stablecoin-core/PriceOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ contract PriceOracle is CommonMath, PausableUpgradeable, IPriceOracle, ICagable,
uint256 _priceWithSafetyMargin // Price with safety margin [ray]
);

event LogSetPriceForBatch(bytes32[] _poolIds);

event LogSetStableCoinReferencePrice(address indexed _caller, uint256 _data);
event LogSetBookKeeper(address _newAddress);

Expand Down Expand Up @@ -95,13 +97,14 @@ contract PriceOracle is CommonMath, PausableUpgradeable, IPriceOracle, ICagable,
}

function setPrice(bytes32 _collateralPoolId) external override whenNotPaused isLive {
IPriceFeed _priceFeed = IPriceFeed(ICollateralPoolConfig(bookKeeper.collateralPoolConfig()).collateralPools(_collateralPoolId).priceFeed);
uint256 _liquidationRatio = ICollateralPoolConfig(bookKeeper.collateralPoolConfig()).getLiquidationRatio(_collateralPoolId);
(uint256 _rawPrice, bool _hasPrice) = _priceFeed.peekPrice();
uint256 _priceWithSafetyMargin = _hasPrice ? rdiv(rdiv(_rawPrice * (10 ** 9), stableCoinReferencePrice), _liquidationRatio) : 0;
address _collateralPoolConfig = address(bookKeeper.collateralPoolConfig());
ICollateralPoolConfig(_collateralPoolConfig).setPriceWithSafetyMargin(_collateralPoolId, _priceWithSafetyMargin);
emit LogSetPrice(_collateralPoolId, _rawPrice, _priceWithSafetyMargin);
_setPrice(_collateralPoolId);
}

function setPriceForBatch(bytes32[] calldata _collateralPoolIds) external override whenNotPaused isLive {
for (uint256 i = 0; i < _collateralPoolIds.length; i++) {
_setPrice(_collateralPoolIds[i]);
}
emit LogSetPriceForBatch(_collateralPoolIds);
}

/// @dev Cage function halts priceOracle contract for good.
Expand All @@ -122,4 +125,14 @@ contract PriceOracle is CommonMath, PausableUpgradeable, IPriceOracle, ICagable,
function unpause() external override onlyOwnerOrGov {
_unpause();
}

function _setPrice(bytes32 _collateralPoolId) internal {
IPriceFeed _priceFeed = IPriceFeed(ICollateralPoolConfig(bookKeeper.collateralPoolConfig()).collateralPools(_collateralPoolId).priceFeed);
uint256 _liquidationRatio = ICollateralPoolConfig(bookKeeper.collateralPoolConfig()).getLiquidationRatio(_collateralPoolId);
(uint256 _rawPrice, bool _hasPrice) = _priceFeed.peekPrice();
uint256 _priceWithSafetyMargin = _hasPrice ? rdiv(rdiv(_rawPrice * (10 ** 9), stableCoinReferencePrice), _liquidationRatio) : 0;
address _collateralPoolConfig = address(bookKeeper.collateralPoolConfig());
ICollateralPoolConfig(_collateralPoolConfig).setPriceWithSafetyMargin(_collateralPoolId, _priceWithSafetyMargin);
emit LogSetPrice(_collateralPoolId, _rawPrice, _priceWithSafetyMargin);
}
}
27 changes: 20 additions & 7 deletions contracts/tests/mocks/MockPriceOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ contract MockPriceOracle is CommonMath, PausableUpgradeable, IPriceOracle, ICaga
uint256 _priceWithSafetyMargin // Price with safety margin [ray]
);

event LogSetPriceForBatch(bytes32[] _poolIds);

event LogSetStableCoinReferencePrice(address indexed _caller, uint256 _data);
event LogSetBookKeeper(address _newAddress);

Expand Down Expand Up @@ -91,13 +93,14 @@ contract MockPriceOracle is CommonMath, PausableUpgradeable, IPriceOracle, ICaga
}

function setPrice(bytes32 _collateralPoolId) external override whenNotPaused isLive {
IPriceFeed _priceFeed = IPriceFeed(ICollateralPoolConfig(bookKeeper.collateralPoolConfig()).collateralPools(_collateralPoolId).priceFeed);
uint256 _liquidationRatio = ICollateralPoolConfig(bookKeeper.collateralPoolConfig()).getLiquidationRatio(_collateralPoolId);
(uint256 _rawPrice, bool _hasPrice) = _priceFeed.peekPrice();
uint256 _priceWithSafetyMargin = _hasPrice ? rdiv(rdiv(_rawPrice * (10 ** 9), stableCoinReferencePrice), _liquidationRatio) : 0;
address _collateralPoolConfig = address(bookKeeper.collateralPoolConfig());
ICollateralPoolConfig(_collateralPoolConfig).setPriceWithSafetyMargin(_collateralPoolId, _priceWithSafetyMargin);
emit LogSetPrice(_collateralPoolId, _rawPrice, _priceWithSafetyMargin);
_setPrice(_collateralPoolId);
}

function setPriceForBatch(bytes32[] calldata _collateralPoolIds) external override whenNotPaused isLive {
for (uint256 i = 0; i < _collateralPoolIds.length; i++) {
_setPrice(_collateralPoolIds[i]);
}
emit LogSetPriceForBatch(_collateralPoolIds);
}

/// @dev Cage function halts priceOracle contract for good.
Expand All @@ -118,4 +121,14 @@ contract MockPriceOracle is CommonMath, PausableUpgradeable, IPriceOracle, ICaga
function unpause() external override onlyOwnerOrGov {
_unpause();
}

function _setPrice(bytes32 _collateralPoolId) internal {
IPriceFeed _priceFeed = IPriceFeed(ICollateralPoolConfig(bookKeeper.collateralPoolConfig()).collateralPools(_collateralPoolId).priceFeed);
uint256 _liquidationRatio = ICollateralPoolConfig(bookKeeper.collateralPoolConfig()).getLiquidationRatio(_collateralPoolId);
(uint256 _rawPrice, bool _hasPrice) = _priceFeed.peekPrice();
uint256 _priceWithSafetyMargin = _hasPrice ? rdiv(rdiv(_rawPrice * (10 ** 9), stableCoinReferencePrice), _liquidationRatio) : 0;
address _collateralPoolConfig = address(bookKeeper.collateralPoolConfig());
ICollateralPoolConfig(_collateralPoolConfig).setPriceWithSafetyMargin(_collateralPoolId, _priceWithSafetyMargin);
emit LogSetPrice(_collateralPoolId, _rawPrice, _priceWithSafetyMargin);
}
}
89 changes: 89 additions & 0 deletions scripts/tests/unit/stablecoin-core/PriceOracle.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,95 @@ describe("PriceOracle", () => {
})
})

describe("#setPriceBatch()", () => {
context("when price from price feed is 1", () => {
context("and price with safety margin is 0", () => {
it("should be success", async () => {
await mockedPriceFeed.mock.peekPrice.returns(formatBytes32BigNumber(One), false)
await mockedBookKeeper.mock.accessControlConfig.returns(mockedCollateralPoolConfig.address)

await mockedCollateralPoolConfig.mock.collateralPools.returns({
totalDebtShare: 0,
debtAccumulatedRate: WeiPerRay,
priceWithSafetyMargin: WeiPerRay,
debtCeiling: 0,
debtFloor: 0,
priceFeed: mockedPriceFeed.address,
liquidationRatio: WeiPerRay,
stabilityFeeRate: WeiPerRay,
lastAccumulationTime: 0,
adapter: AddressZero,
closeFactorBps: 5000,
liquidatorIncentiveBps: 10250,
treasuryFeesBps: 5000,
strategy: AddressZero,
positionDebtCeiling: WeiPerRad.mul(1000000)

})
await mockedBookKeeper.mock.collateralPoolConfig.returns(mockedCollateralPoolConfig.address)
await mockedCollateralPoolConfig.mock.setPriceWithSafetyMargin.withArgs(
formatBytes32String("WXDC"),
BigNumber.from("0")
).returns()
await mockedCollateralPoolConfig.mock.setPriceWithSafetyMargin.withArgs(
formatBytes32String("JEJU"),
BigNumber.from("0")
).returns()

await expect(priceOracle.setPriceForBatch([formatBytes32String("WXDC"), formatBytes32String("JEJU")]))
.to.emit(priceOracle, "LogSetPriceForBatch")
.withArgs([formatBytes32String("WXDC"), formatBytes32String("JEJU")])
})
})
})

context("when price from price feed is 7 * 10^11", () => {
context("and price with safety margin is 0", () => {
it("should be success", async () => {
await mockedBookKeeper.mock.collateralPoolConfig.returns(mockedCollateralPoolConfig.address)
await mockedBookKeeper.mock.accessControlConfig.returns(mockedAccessControlConfig.address)
await mockedAccessControlConfig.mock.hasRole.returns(true)

await mockedCollateralPoolConfig.mock.collateralPools.returns({
totalDebtShare: 0,
debtAccumulatedRate: WeiPerRay,
priceWithSafetyMargin: WeiPerRay,
debtCeiling: 0,
debtFloor: 0,
priceFeed: mockedPriceFeed.address,
liquidationRatio: 10 ** 10,
stabilityFeeRate: WeiPerRay,
lastAccumulationTime: 0,
adapter: AddressZero,
closeFactorBps: 5000,
liquidatorIncentiveBps: 10250,
treasuryFeesBps: 5000,
strategy: AddressZero,
positionDebtCeiling: WeiPerRad.mul(1000000)
})

await mockedPriceFeed.mock.peekPrice.returns(
formatBytes32BigNumber(BigNumber.from("700000000000")),
false,
)

await mockedCollateralPoolConfig.mock.setPriceWithSafetyMargin.withArgs(
formatBytes32String("WXDC"),
BigNumber.from("0")
).returns()
await mockedCollateralPoolConfig.mock.setPriceWithSafetyMargin.withArgs(
formatBytes32String("JEJU"),
BigNumber.from("0")
).returns()
await expect(priceOracle.setPriceForBatch([formatBytes32String("WXDC"), formatBytes32String("JEJU")]))
.to.emit(priceOracle, "LogSetPriceForBatch")
.withArgs([formatBytes32String("WXDC"), formatBytes32String("JEJU")])
})
})
})
})


describe("#setStableCoinReferencePrice", () => {
context("when the caller is not the owner", async () => {
it("should revert", async () => {
Expand Down
Loading