Skip to content

Commit

Permalink
Merge pull request #145 from gildlab/2024-10-22-fallback
Browse files Browse the repository at this point in the history
include fallback in oracle v2
  • Loading branch information
thedavidmeister authored Oct 22, 2024
2 parents e45fb7a + ce869d5 commit af74439
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 36 deletions.
36 changes: 18 additions & 18 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,32 @@ ConfiscateSharesTest:testConfiscateShares(uint256,uint256,uint256,uint256,string
ConfiscateSharesTest:testConfiscateSharesOnZeroBalance(uint256,uint256,string,string,bytes,uint256,uint256) (runs: 2071, μ: 1197655, ~: 1198737)
ERC20PriceOracleReceiptVaultConstructionTest:testCheckConstructionEvent(uint256,string,string) (runs: 2071, μ: 480284, ~: 479761)
ERC20PriceOracleReceiptVaultConstructionTest:testCreatingSeveralVaults(uint256,uint256,string,string,string,string) (runs: 2071, μ: 914791, ~: 914405)
ERC20PriceOracleReceiptVaultDepositTest:testDepositBasic(uint256,string,uint256,uint256) (runs: 2070, μ: 569243, ~: 611059)
ERC20PriceOracleReceiptVaultDepositTest:testDepositSomeoneElse(uint256,uint256,string,uint256,uint256) (runs: 2070, μ: 594352, ~: 593119)
ERC20PriceOracleReceiptVaultDepositTest:testDepositWithIncorrectPrice(uint256,string,string,bytes,uint256,uint256) (runs: 2070, μ: 467188, ~: 466728)
ERC20PriceOracleReceiptVaultDepositTest:testDepositBasic(uint256,string,uint256,uint256) (runs: 2070, μ: 569241, ~: 611059)
ERC20PriceOracleReceiptVaultDepositTest:testDepositSomeoneElse(uint256,uint256,string,uint256,uint256) (runs: 2070, μ: 594349, ~: 593119)
ERC20PriceOracleReceiptVaultDepositTest:testDepositWithIncorrectPrice(uint256,string,string,bytes,uint256,uint256) (runs: 2070, μ: 467188, ~: 466725)
ERC20PriceOracleReceiptVaultDepositTest:testDepositWithZeroAssets(uint256,string,string,bytes,uint256) (runs: 2071, μ: 464983, ~: 465233)
ERC20PriceOracleReceiptVaultDepositTest:testDepositWithZeroReceiver(string,string,bytes,uint256,uint256) (runs: 2071, μ: 466283, ~: 466058)
ERC20PriceOracleReceiptVaultDepositTest:testMintBasic(uint256,string,uint256,uint256) (runs: 2070, μ: 564452, ~: 606304)
ERC20PriceOracleReceiptVaultDepositTest:testMintSomeoneElse(uint256,uint256,string,uint256,uint256) (runs: 2070, μ: 566380, ~: 565243)
ERC20PriceOracleReceiptVaultDepositTest:testMintWithMinPrice(uint256,string,string,uint256,uint256,uint256) (runs: 2064, μ: 466073, ~: 466503)
ERC20PriceOracleReceiptVaultDepositTest:testDepositWithZeroReceiver(string,string,bytes,uint256,uint256) (runs: 2071, μ: 466279, ~: 466058)
ERC20PriceOracleReceiptVaultDepositTest:testMintBasic(uint256,string,uint256,uint256) (runs: 2070, μ: 564455, ~: 606319)
ERC20PriceOracleReceiptVaultDepositTest:testMintSomeoneElse(uint256,uint256,string,uint256,uint256) (runs: 2070, μ: 566336, ~: 565243)
ERC20PriceOracleReceiptVaultDepositTest:testMintWithMinPrice(uint256,string,string,uint256,uint256,uint256) (runs: 2064, μ: 466047, ~: 466503)
ERC20PriceOracleReceiptVaultDepositTest:testMintWithZeroShares(uint256,string,uint256) (runs: 2071, μ: 464447, ~: 419528)
ERC20PriceOracleReceiptVaultDepositTest:testPreviewDepositReturnedShares(string,string,uint256,uint256) (runs: 2071, μ: 464897, ~: 465416)
ERC20PriceOracleReceiptVaultDepositTest:testPreviewMintReturnedAssets(string,string,uint256,uint256) (runs: 2071, μ: 465066, ~: 465500)
ERC20PriceOracleReceiptVaultRedeemTest:testPreviewRedeem(uint256,string,uint256,uint256) (runs: 2068, μ: 468030, ~: 509521)
ERC20PriceOracleReceiptVaultRedeemTest:testRedeemBasic(uint256,string,uint256,uint256,uint256) (runs: 2068, μ: 608039, ~: 649722)
ERC20PriceOracleReceiptVaultRedeemTest:testRedeemMoreThanBalance(uint256,string,uint256,uint256,uint256) (runs: 2070, μ: 593732, ~: 635427)
ERC20PriceOracleReceiptVaultRedeemTest:testRedeemRevertsOnZeroOwner(uint256,string,uint256,uint256,uint256) (runs: 2068, μ: 588196, ~: 629479)
ERC20PriceOracleReceiptVaultRedeemTest:testRedeemRevertsOnZeroReceiver(uint256,string,uint256,uint256,uint256) (runs: 2068, μ: 590608, ~: 631891)
ERC20PriceOracleReceiptVaultRedeemTest:testRedeemRevertsOnZeroShares(uint256,string,uint256,uint256) (runs: 2070, μ: 586876, ~: 628840)
ERC20PriceOracleReceiptVaultDepositTest:testPreviewDepositReturnedShares(string,string,uint256,uint256) (runs: 2071, μ: 464899, ~: 465416)
ERC20PriceOracleReceiptVaultDepositTest:testPreviewMintReturnedAssets(string,string,uint256,uint256) (runs: 2071, μ: 465068, ~: 465500)
ERC20PriceOracleReceiptVaultRedeemTest:testPreviewRedeem(uint256,string,uint256,uint256) (runs: 2068, μ: 468239, ~: 509803)
ERC20PriceOracleReceiptVaultRedeemTest:testRedeemBasic(uint256,string,uint256,uint256,uint256) (runs: 2068, μ: 607978, ~: 649722)
ERC20PriceOracleReceiptVaultRedeemTest:testRedeemMoreThanBalance(uint256,string,uint256,uint256,uint256) (runs: 2070, μ: 593735, ~: 635427)
ERC20PriceOracleReceiptVaultRedeemTest:testRedeemRevertsOnZeroOwner(uint256,string,uint256,uint256,uint256) (runs: 2068, μ: 588134, ~: 629479)
ERC20PriceOracleReceiptVaultRedeemTest:testRedeemRevertsOnZeroReceiver(uint256,string,uint256,uint256,uint256) (runs: 2068, μ: 590546, ~: 631891)
ERC20PriceOracleReceiptVaultRedeemTest:testRedeemRevertsOnZeroShares(uint256,string,uint256,uint256) (runs: 2070, μ: 586870, ~: 628840)
ERC20PriceOracleReceiptVaultWithdrawTest:testPreviewWithdraw(uint256,string,uint256,uint256) (runs: 2070, μ: 468223, ~: 510060)
ERC20PriceOracleReceiptVaultWithdrawTest:testWithdrawBasic(uint256,string,uint256,uint256) (runs: 2070, μ: 601723, ~: 588363)
ERC20PriceOracleReceiptVaultWithdrawTest:testWithdrawMoreThanAssets(uint256,string,uint256,uint256,uint256) (runs: 2070, μ: 592818, ~: 634821)
ERC20PriceOracleReceiptVaultWithdrawTest:testWithdrawRevertsOnZeroAssets(uint256,string,uint256,uint256) (runs: 2070, μ: 586898, ~: 628870)
ERC20PriceOracleReceiptVaultWithdrawTest:testWithdrawRevertsOnZeroOwner(uint256,string,uint256,uint256) (runs: 2070, μ: 585864, ~: 627837)
ERC20PriceOracleReceiptVaultWithdrawTest:testWithdrawRevertsOnZeroReceiver(uint256,string,uint256,uint256) (runs: 2070, μ: 588162, ~: 629946)
ERC20PriceOracleReceiptVaultreceiptVaultTest:testConvertToAssets(uint256,string,uint256,uint256) (runs: 2071, μ: 465101, ~: 507058)
ERC20PriceOracleReceiptVaultreceiptVaultTest:testConvertToAssetsDifferentCaller(uint256,uint256,string,uint256,uint256) (runs: 2071, μ: 466288, ~: 465063)
ERC20PriceOracleReceiptVaultreceiptVaultTest:testConvertToShares(uint256,string,uint256,uint256) (runs: 2071, μ: 468127, ~: 509961)
ERC20PriceOracleReceiptVaultreceiptVaultTest:testConvertToAssets(uint256,string,uint256,uint256) (runs: 2071, μ: 465102, ~: 507058)
ERC20PriceOracleReceiptVaultreceiptVaultTest:testConvertToAssetsDifferentCaller(uint256,uint256,string,uint256,uint256) (runs: 2071, μ: 466287, ~: 465063)
ERC20PriceOracleReceiptVaultreceiptVaultTest:testConvertToShares(uint256,string,uint256,uint256) (runs: 2071, μ: 468129, ~: 509961)
ERC20PriceOracleReceiptVaultreceiptVaultTest:testConvertToSharesDifferentCaller(uint256,uint256,string,uint256,uint256) (runs: 2071, μ: 472558, ~: 471487)
ERC20PriceOracleReceiptVaultreceiptVaultTest:testMaxDeposit(uint256,string) (runs: 2071, μ: 457348, ~: 456481)
ERC20PriceOracleReceiptVaultreceiptVaultTest:testMaxShares(uint256,string) (runs: 2071, μ: 457336, ~: 456469)
Expand Down
12 changes: 7 additions & 5 deletions script/Deploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import {
} from "src/concrete/vault/OffchainAssetReceiptVault.sol";
import {Receipt as ReceiptContract} from "src/concrete/receipt/Receipt.sol";
import {SceptreStakedFlrOracle} from "src/concrete/oracle/SceptreStakedFlrOracle.sol";
import {TwoPriceOracle, TwoPriceOracleConfig} from "src/concrete/oracle/TwoPriceOracle.sol";
import {TwoPriceOracleV2, TwoPriceOracleConfigV2} from "src/concrete/oracle/TwoPriceOracleV2.sol";
import {IStakedFlr} from "rain.flare/interface/IStakedFlr.sol";
import {FtsoV2LTSFeedOracle, FtsoV2LTSFeedOracleConfig} from "src/concrete/oracle/FtsoV2LTSFeedOracle.sol";
import {FLR_USD_FEED_ID} from "rain.flare/lib/lts/LibFtsoV2LTS.sol";
import {IPriceOracleV2} from "src/interface/IPriceOracleV2.sol";

bytes32 constant DEPLOYMENT_SUITE_IMPLEMENTATIONS = keccak256("implementations");
bytes32 constant DEPLOYMENT_SUITE_OWNABLE_ORACLE_VAULT = keccak256("ownable-oracle-vault");
Expand All @@ -45,7 +46,7 @@ contract Deploy is Script {

function deployStakedFlrPriceVault(uint256 deploymentKey) internal {
vm.startBroadcast(deploymentKey);
address ftsoV2LTSFeedOracle = address(
IPriceOracleV2 ftsoV2LTSFeedOracle = IPriceOracleV2(
new FtsoV2LTSFeedOracle(
FtsoV2LTSFeedOracleConfig({
feedId: FLR_USD_FEED_ID,
Expand All @@ -55,9 +56,10 @@ contract Deploy is Script {
)
);
address stakedFlr = vm.envAddress("SCEPTRE_STAKED_FLR_ADDRESS");
address stakedFlrOracle = address(new SceptreStakedFlrOracle(IStakedFlr(stakedFlr)));
address twoPriceOracle =
address(new TwoPriceOracle(TwoPriceOracleConfig({base: ftsoV2LTSFeedOracle, quote: stakedFlrOracle})));
IPriceOracleV2 stakedFlrOracle = IPriceOracleV2(new SceptreStakedFlrOracle(IStakedFlr(stakedFlr)));
IPriceOracleV2 twoPriceOracle = IPriceOracleV2(
new TwoPriceOracleV2(TwoPriceOracleConfigV2({base: ftsoV2LTSFeedOracle, quote: stakedFlrOracle}))
);

ICloneableFactoryV2(vm.envAddress("CLONE_FACTORY")).clone(
vm.envAddress("ERC20_PRICE_ORACLE_VAULT_IMPLEMENTATION"),
Expand Down
6 changes: 6 additions & 0 deletions src/concrete/oracle/FtsoV2LTSFeedOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,10 @@ contract FtsoV2LTSFeedOracle is IPriceOracleV2 {
Address.sendValue(payable(msg.sender), address(this).balance);
return val;
}

/// Need to accept refunds from the oracle.
fallback() external payable {}

/// Need to accept refunds from the oracle.
receive() external payable {}
}
6 changes: 6 additions & 0 deletions src/concrete/oracle/SceptreStakedFlrOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,10 @@ contract SceptreStakedFlrOracle is IPriceOracleV2 {
Address.sendValue(payable(msg.sender), address(this).balance);
return val;
}

/// Need to accept refunds from the oracle.
fallback() external payable {}

/// Need to accept refunds from the oracle.
receive() external payable {}
}
19 changes: 16 additions & 3 deletions src/concrete/oracle/TwoPriceOracleV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,16 @@ import {
LibFixedPointDecimalArithmeticOpenZeppelin,
Math
} from "rain.math.fixedpoint/lib/LibFixedPointDecimalArithmeticOpenZeppelin.sol";
import {TwoPriceOracleConfig} from "./TwoPriceOracle.sol";
import {Address} from "openzeppelin-contracts/contracts/utils/Address.sol";

/// Construction config for `TwoPriceOracle`.
/// @param base The base price of the merged pair, will be the numerator.
/// @param quote The quote price of the merged pair, will be the denominator.
struct TwoPriceOracleConfigV2 {
IPriceOracleV2 base;
IPriceOracleV2 quote;
}

/// @title TwoPriceOracle
/// Any time we have two price feeds that share a denominator we can derive the
/// price of the numerators by dividing the two ratios. We leverage the fixed
Expand All @@ -22,15 +29,15 @@ contract TwoPriceOracleV2 is IPriceOracleV2 {
using LibFixedPointDecimalArithmeticOpenZeppelin for uint256;

/// Emitted upon deployment and construction.
event Construction(address sender, TwoPriceOracleConfig config);
event Construction(address sender, TwoPriceOracleConfigV2 config);

/// As per `ConstructionConfig.base`.
IPriceOracleV2 public immutable base;
/// As per `ConstructionConfig.quote`.
IPriceOracleV2 public immutable quote;

/// @param config Config required to construct.
constructor(TwoPriceOracleConfig memory config) {
constructor(TwoPriceOracleConfigV2 memory config) {
base = IPriceOracleV2(config.base);
quote = IPriceOracleV2(config.quote);
emit Construction(msg.sender, config);
Expand All @@ -52,4 +59,10 @@ contract TwoPriceOracleV2 is IPriceOracleV2 {
Address.sendValue(payable(msg.sender), address(this).balance);
return val;
}

/// Need to accept refunds from the oracle.
fallback() external payable {}

/// Need to accept refunds from the oracle.
receive() external payable {}
}
4 changes: 2 additions & 2 deletions src/concrete/vault/ERC20PriceOracleReceiptVault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ import {IPriceOracleV2} from "../../interface/IPriceOracleV2.sol";
/// @param priceOracle as per `ERC20PriceOracleReceiptVaultConfig`.
/// @param vaultConfig config for the underlying `ReceiptVault`.
struct ERC20PriceOracleVaultConfig {
address priceOracle;
IPriceOracleV2 priceOracle;
VaultConfig vaultConfig;
}

/// @param priceOracle The price oracle that will be permanently bound to the
/// `ERC20PriceOracleVault` upon initialization.
/// @param receiptVaultConfig All config for the underlying receipt vault.
struct ERC20PriceOracleReceiptVaultConfig {
address priceOracle;
IPriceOracleV2 priceOracle;
ReceiptVaultConfig receiptVaultConfig;
}

Expand Down
6 changes: 6 additions & 0 deletions src/interface/IPriceOracleV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@ pragma solidity ^0.8.0;
interface IPriceOracleV2 {
/// Returns the current/latest price according to the oracle.
function price() external payable returns (uint256);

/// Need to accept refunds from the oracle.
fallback() external payable;

/// Need to accept refunds from the oracle.
receive() external payable;
}
10 changes: 6 additions & 4 deletions test/abstract/ERC20PriceOracleReceiptVaultTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ contract ERC20PriceOracleReceiptVaultTest is Test {
ERC20PriceOracleReceiptVault internal immutable iImplementation;
ReceiptContract internal immutable iReceiptImplementation;
IERC20 immutable iAsset;
address immutable iVaultOracle;
IPriceOracleV2 immutable iVaultOracle;

constructor() {
iFactory = new CloneFactory();
Expand All @@ -35,14 +35,16 @@ contract ERC20PriceOracleReceiptVaultTest is Test {
ReceiptVaultConstructionConfig({factory: iFactory, receiptImplementation: iReceiptImplementation})
);
iAsset = IERC20(address(uint160(uint256(keccak256("asset.test")))));
iVaultOracle = address(uint160(uint256(keccak256("vault.oracle"))));
iVaultOracle = IPriceOracleV2(payable(address(uint160(uint256(keccak256("vault.oracle"))))));
}

function setVaultOraclePrice(uint256 oraclePrice) internal {
vm.mockCall(iVaultOracle, abi.encodeWithSelector(IPriceOracleV2.price.selector), abi.encode(oraclePrice));
vm.mockCall(
address(iVaultOracle), abi.encodeWithSelector(IPriceOracleV2.price.selector), abi.encode(oraclePrice)
);
}

function createVault(address priceOracle, string memory name, string memory symbol)
function createVault(IPriceOracleV2 priceOracle, string memory name, string memory symbol)
internal
returns (ERC20PriceOracleReceiptVault)
{
Expand Down
3 changes: 2 additions & 1 deletion test/lib/LibERC20PriceOracleReceiptVaultCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ import {
ERC20PriceOracleVaultConfig
} from "src/concrete/vault/ERC20PriceOracleReceiptVault.sol";
import {VaultConfig} from "src/abstract/ReceiptVault.sol";
import {IPriceOracleV2} from "src/interface/IPriceOracleV2.sol";

library LibERC20PriceOracleReceiptVaultCreator {
/// Helper to create child erc20PriceOracleVault.
function createVault(
ICloneableFactoryV2 factory,
ERC20PriceOracleReceiptVault implementation,
address priceOracle,
IPriceOracleV2 priceOracle,
address asset,
string memory name,
string memory symbol
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ contract ERC20PriceOracleReceiptVaultConstructionTest is ERC20PriceOracleReceipt
// Ensure the fuzzed key is within the valid range for secp256
address alice = vm.addr((fuzzedKeyAlice % (SECP256K1_ORDER - 1)) + 1);

address vaultPriceOracle = address(uint160(uint256(keccak256("twoPriceOracle"))));
IPriceOracleV2 vaultPriceOracle =
IPriceOracleV2(payable(address(uint160(uint256(keccak256("twoPriceOracle"))))));
vm.startPrank(alice);

// Start recording logs
Expand All @@ -32,7 +33,7 @@ contract ERC20PriceOracleReceiptVaultConstructionTest is ERC20PriceOracleReceipt
// Note: To use vm.expectEmit receipt address is needed to be known.
// Find the OffchainAssetReceiptVaultInitialized event log
address msgSender = address(0);
address priceOracle = address(0);
IPriceOracleV2 priceOracle = IPriceOracleV2(payable(0));
address assetAddress = address(0);
string memory name = "";
string memory symbol = "";
Expand Down Expand Up @@ -60,7 +61,7 @@ contract ERC20PriceOracleReceiptVaultConstructionTest is ERC20PriceOracleReceipt
assertTrue(eventFound, "ERC20PriceOracleReceiptVaultInitialized event log not found");

assertEq(msgSender, address(iFactory));
assertEq(priceOracle, vaultPriceOracle);
assertEq(address(priceOracle), address(vaultPriceOracle));
assert(address(vault) != address(0));
assertEq(keccak256(bytes(vault.name())), keccak256(bytes(name)));
assertEq(keccak256(bytes(vault.symbol())), keccak256(bytes(symbol)));
Expand Down

0 comments on commit af74439

Please sign in to comment.