From 995340d956e257c2b36f5a31839d69000d68e8b6 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Tue, 25 Jun 2024 14:02:42 +0400 Subject: [PATCH 1/5] wip on sflr --- contracts/concrete/oracle/FlareFTSOOracle.sol | 12 ------- .../oracle/FtsoCurrentPriceUsdOracle.sol | 30 +++++++++++++++++ .../oracle/SceptreStakedFlrOracle.sol | 18 +++++++++++ .../oracle}/TwoPriceOracle.sol | 0 contracts/interface/sceptre/IStakedFlr.sol | 11 +++++++ foundry.toml | 3 +- script/Deploy.sol | 32 +++++++++++++++---- 7 files changed, 87 insertions(+), 19 deletions(-) delete mode 100644 contracts/concrete/oracle/FlareFTSOOracle.sol create mode 100644 contracts/concrete/oracle/FtsoCurrentPriceUsdOracle.sol create mode 100644 contracts/concrete/oracle/SceptreStakedFlrOracle.sol rename contracts/{oracle/price => concrete/oracle}/TwoPriceOracle.sol (100%) create mode 100644 contracts/interface/sceptre/IStakedFlr.sol diff --git a/contracts/concrete/oracle/FlareFTSOOracle.sol b/contracts/concrete/oracle/FlareFTSOOracle.sol deleted file mode 100644 index 4f0982cf..00000000 --- a/contracts/concrete/oracle/FlareFTSOOracle.sol +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-License-Identifier: CAL -pragma solidity =0.8.25; - -import {IPriceOracleV1} from "../../interface/IPriceOracleV1.sol"; -import {LibFtsoCurrentPriceUsd} from "rain.flare/src/lib/price/LibFtsoCurrentPriceUsd.sol"; - -contract FlareFTSOOracle is IPriceOracleV1 { - /// @inheritdoc IPriceOracleV1 - function price() external view override returns (uint256) { - return LibFtsoCurrentPriceUsd.ftsoCurrentPriceUsd("FLR", 300); - } -} diff --git a/contracts/concrete/oracle/FtsoCurrentPriceUsdOracle.sol b/contracts/concrete/oracle/FtsoCurrentPriceUsdOracle.sol new file mode 100644 index 00000000..1e7ecc89 --- /dev/null +++ b/contracts/concrete/oracle/FtsoCurrentPriceUsdOracle.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +import {IPriceOracleV1} from "../../interface/IPriceOracleV1.sol"; +import {LibFtsoCurrentPriceUsd} from "rain.flare/src/lib/price/LibFtsoCurrentPriceUsd.sol"; +import {LibIntOrAString, IntOrAString} from "rain.intorastring/lib/LibIntOrAString.sol"; + +struct FtsoCurrentPriceUsdOracleConfig { + string symbol; + uint256 staleAfter; +} + +contract FtsoCurrentPriceUsdOracle is IPriceOracleV1 { + event Construction(address sender, FtsoCurrentPriceUsdOracleConfig config); + + IntOrAString public immutable iSymbol; + uint256 public immutable iStaleAfter; + + constructor(FtsoCurrentPriceUsdOracleConfig memory config) { + iSymbol = LibIntOrAString.fromString2(config.symbol); + iStaleAfter = config.staleAfter; + + emit Construction(msg.sender, config); + } + + /// @inheritdoc IPriceOracleV1 + function price() external view override returns (uint256) { + return LibFtsoCurrentPriceUsd.ftsoCurrentPriceUsd(LibIntOrAString.toString(iSymbol), iStaleAfter); + } +} diff --git a/contracts/concrete/oracle/SceptreStakedFlrOracle.sol b/contracts/concrete/oracle/SceptreStakedFlrOracle.sol new file mode 100644 index 00000000..97cd1fce --- /dev/null +++ b/contracts/concrete/oracle/SceptreStakedFlrOracle.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: CAL +pragma solidity =0.8.25; + +import {IPriceOracleV1} from "../../interface/IPriceOracleV1.sol"; +import {IStakedFlr} from "../../interface/sceptre/IStakedFlr.sol"; + +contract SceptreStakedFlrOracle is IPriceOracleV1 { + IStakedFlr public immutable iStakedFlr; + + constructor(IStakedFlr stakedFlr) { + iStakedFlr = stakedFlr; + } + + /// @inheritdoc IPriceOracleV1 + function price() external view override returns (uint256) { + return iStakedFlr.getSharesByPooledFlr(1e18); + } +} diff --git a/contracts/oracle/price/TwoPriceOracle.sol b/contracts/concrete/oracle/TwoPriceOracle.sol similarity index 100% rename from contracts/oracle/price/TwoPriceOracle.sol rename to contracts/concrete/oracle/TwoPriceOracle.sol diff --git a/contracts/interface/sceptre/IStakedFlr.sol b/contracts/interface/sceptre/IStakedFlr.sol new file mode 100644 index 00000000..ae6fe20d --- /dev/null +++ b/contracts/interface/sceptre/IStakedFlr.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: CAL + +pragma solidity ^0.8.25; + +interface IStakedFlr { + function getSharesByPooledFlr(uint256 flrAmount) external view returns (uint256); + + function getPooledFlrByShares(uint256 shareAmount) external view returns (uint256); + + function submit() external payable returns (uint256); +} diff --git a/foundry.toml b/foundry.toml index 4da43b89..67f102c6 100644 --- a/foundry.toml +++ b/foundry.toml @@ -14,5 +14,6 @@ optimizer_runs = 100000 fuzz.runs = 2056 remappings = [ - "rain.factory/=lib/rain.factory/src/" + "rain.factory/=lib/rain.factory/src/", + "rain.intorastring/=lib/rain.interpreter/lib/rain.intorastring/src/", ] \ No newline at end of file diff --git a/script/Deploy.sol b/script/Deploy.sol index e67abc74..8d8dec12 100644 --- a/script/Deploy.sol +++ b/script/Deploy.sol @@ -9,16 +9,22 @@ import { } from "contracts/concrete/vault/ERC20PriceOracleReceiptVault.sol"; import {VaultConfig} from "contracts/abstract/ReceiptVault.sol"; import {ICloneableFactoryV2} from "rain.factory/interface/ICloneableFactoryV2.sol"; -import {FlareFTSOOracle} from "contracts/concrete/oracle/FlareFTSOOracle.sol"; +import { + FtsoCurrentPriceUsdOracle, + FtsoCurrentPriceUsdOracleConfig +} from "contracts/concrete/oracle/FtsoCurrentPriceUsdOracle.sol"; import { OffchainAssetReceiptVault, ReceiptVaultConstructionConfig } from "contracts/concrete/vault/OffchainAssetReceiptVault.sol"; import {Receipt as ReceiptContract} from "contracts/concrete/receipt/Receipt.sol"; +import {SceptreStakedFlrOracle} from "contracts/concrete/oracle/SceptreStakedFlrOracle.sol"; +import {TwoPriceOracle, TwoPriceOracleConfig} from "contracts/concrete/oracle/TwoPriceOracle.sol"; +import {IStakedFlr} from "contracts/interface/sceptre/IStakedFlr.sol"; bytes32 constant DEPLOYMENT_SUITE_IMPLEMENTATIONS = keccak256("implementations"); bytes32 constant DEPLOYMENT_SUITE_OWNABLE_ORACLE_VAULT = keccak256("ownable-oracle-vault"); -bytes32 constant DEPLOYMENT_SUITE_FLARE_FTSO_ORACLE_PRICE_VAULT = keccak256("flare-ftso-oracle-price-vault"); +bytes32 constant DEPLOYMENT_SUITE_STAKED_FLR_PRICE_VAULT = keccak256("sceptre-staked-flare-price-vault"); /// @title Deploy /// This is intended to be run on every commit by CI to a testnet such as mumbai, @@ -39,13 +45,27 @@ contract Deploy is Script { vm.stopBroadcast(); } - function deployFlareFTSOOraclePriceVault(uint256 deploymentKey) internal { + function deployStakedFlrPriceVault(uint256 deploymentKey) internal { vm.startBroadcast(deploymentKey); + address flareFTSOOracle = address( + new FtsoCurrentPriceUsdOracle( + FtsoCurrentPriceUsdOracleConfig({ + symbol: "FLR", + // 30 mins. + staleAfter: 1800 + }) + ) + ); + address stakedFlr = vm.envAddress("SCEPTRE_STAKED_FLR_ADDRESS"); + address stakedFlrOracle = address(new SceptreStakedFlrOracle(IStakedFlr(stakedFlr))); + address twoPriceOracle = + address(new TwoPriceOracle(TwoPriceOracleConfig({base: flareFTSOOracle, quote: stakedFlrOracle}))); + ICloneableFactoryV2(vm.envAddress("CLONE_FACTORY")).clone( vm.envAddress("ERC20_PRICE_ORACLE_VAULT_IMPLEMENTATION"), abi.encode( ERC20PriceOracleVaultConfig({ - priceOracle: address(new FlareFTSOOracle()), + priceOracle: twoPriceOracle, vaultConfig: VaultConfig({ asset: vm.envAddress("RECEIPT_VAULT_ASSET"), name: vm.envString("RECEIPT_VAULT_NAME"), @@ -90,8 +110,8 @@ contract Deploy is Script { if (suite == DEPLOYMENT_SUITE_IMPLEMENTATIONS) { deployImplementations(deployerPrivateKey); - } else if (suite == DEPLOYMENT_SUITE_FLARE_FTSO_ORACLE_PRICE_VAULT) { - deployFlareFTSOOraclePriceVault(deployerPrivateKey); + } else if (suite == DEPLOYMENT_SUITE_STAKED_FLR_PRICE_VAULT) { + deployStakedFlrPriceVault(deployerPrivateKey); } else { revert("Unknown deployment suite"); } From 3a894926df0cbbb8c8a3af39a130a2621f0ea0dd Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Tue, 25 Jun 2024 14:06:27 +0400 Subject: [PATCH 2/5] sceptre staked flr address --- .github/workflows/manual-sol-artifacts.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/manual-sol-artifacts.yaml b/.github/workflows/manual-sol-artifacts.yaml index c7cf8393..210bbb98 100644 --- a/.github/workflows/manual-sol-artifacts.yaml +++ b/.github/workflows/manual-sol-artifacts.yaml @@ -26,7 +26,7 @@ on: type: choice options: - ownable-oracle-vault - - flare-ftso-oracle-price-vault + - sceptre-staked-flare-price-vault - implementations receipt-vault-asset: @@ -82,6 +82,7 @@ jobs: RECEIPT_VAULT_SYMBOL: ${{ inputs.receipt-vault-symbol || '' }} OWNER_ADDRESS: ${{ inputs.owner || '' }} CLONE_FACTORY : ${{ vars[env.clone_factory_name] || '' }} + SCEPTRE_STAKED_FLR_ADDRESS: ${{ vars.SCEPTRE_STAKED_FLR_ADDRESS || '' }} ERC20_PRICE_ORACLE_VAULT_IMPLEMENTATION: ${{ vars[env.erc20_price_oracle_vault_implementation_name] || '' }} DEPLOY_BROADCAST: '1' DEPLOYMENT_KEY: ${{ secrets.CI_PRIVATE_KEY }} From 7aec12fe6625916e8423960a764b156950896490 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Tue, 25 Jun 2024 14:16:08 +0400 Subject: [PATCH 3/5] use staked flr as asset --- script/Deploy.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/Deploy.sol b/script/Deploy.sol index 8d8dec12..079fefbc 100644 --- a/script/Deploy.sol +++ b/script/Deploy.sol @@ -67,7 +67,7 @@ contract Deploy is Script { ERC20PriceOracleVaultConfig({ priceOracle: twoPriceOracle, vaultConfig: VaultConfig({ - asset: vm.envAddress("RECEIPT_VAULT_ASSET"), + asset: stakedFlr, name: vm.envString("RECEIPT_VAULT_NAME"), symbol: vm.envString("RECEIPT_VAULT_SYMBOL") }) From fe34fa70e9629b8334cae2aec45b1ce102478a0d Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Tue, 25 Jun 2024 14:34:05 +0400 Subject: [PATCH 4/5] fix slither --- slither.config.json | 2 +- {contracts/test => test/foundry/concrete}/ReadWriteTier.sol | 0 .../src/concrete/vault/OffchainAssetReceiptVault.roles.t.sol | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename {contracts/test => test/foundry/concrete}/ReadWriteTier.sol (100%) diff --git a/slither.config.json b/slither.config.json index f84294d2..c081d3af 100644 --- a/slither.config.json +++ b/slither.config.json @@ -1,4 +1,4 @@ { - "detectors_to_exclude": "solc-version,block-timestamp,unused-imports,different-pragma-directives-are-used", + "detectors_to_exclude": "solc-version,block-timestamp,unused-imports,different-pragma-directives-are-used,assembly-usage", "filter_paths": "lib/openzeppelin-contracts,lib/rain.tier.interface,test/,node_modules" } diff --git a/contracts/test/ReadWriteTier.sol b/test/foundry/concrete/ReadWriteTier.sol similarity index 100% rename from contracts/test/ReadWriteTier.sol rename to test/foundry/concrete/ReadWriteTier.sol diff --git a/test/foundry/src/concrete/vault/OffchainAssetReceiptVault.roles.t.sol b/test/foundry/src/concrete/vault/OffchainAssetReceiptVault.roles.t.sol index e639e13b..5ad7a80e 100644 --- a/test/foundry/src/concrete/vault/OffchainAssetReceiptVault.roles.t.sol +++ b/test/foundry/src/concrete/vault/OffchainAssetReceiptVault.roles.t.sol @@ -10,7 +10,7 @@ import { } from "contracts/concrete/vault/OffchainAssetReceiptVault.sol"; import {StringsUpgradeable} from "openzeppelin-contracts-upgradeable/contracts/utils/StringsUpgradeable.sol"; import {TestErc20} from "contracts/test/TestErc20.sol"; -import {ReadWriteTier} from "contracts/test/ReadWriteTier.sol"; +import {ReadWriteTier} from "../../../concrete/ReadWriteTier.sol"; contract RolesTest is OffchainAssetReceiptVaultTest { /// Test to checks Admin roles granted From 7b94145f989f381c4f2d0b621c3b8f9851d287d3 Mon Sep 17 00:00:00 2001 From: thedavidmeister Date: Thu, 19 Sep 2024 16:43:59 +0400 Subject: [PATCH 5/5] use upstream interface --- .../concrete/oracle/FtsoCurrentPriceUsdOracle.sol | 2 +- contracts/concrete/oracle/SceptreStakedFlrOracle.sol | 2 +- contracts/interface/sceptre/IStakedFlr.sol | 11 ----------- foundry.toml | 1 + lib/rain.flare | 2 +- script/Deploy.sol | 2 +- 6 files changed, 5 insertions(+), 15 deletions(-) delete mode 100644 contracts/interface/sceptre/IStakedFlr.sol diff --git a/contracts/concrete/oracle/FtsoCurrentPriceUsdOracle.sol b/contracts/concrete/oracle/FtsoCurrentPriceUsdOracle.sol index 1e7ecc89..8e4843a0 100644 --- a/contracts/concrete/oracle/FtsoCurrentPriceUsdOracle.sol +++ b/contracts/concrete/oracle/FtsoCurrentPriceUsdOracle.sol @@ -2,7 +2,7 @@ pragma solidity =0.8.25; import {IPriceOracleV1} from "../../interface/IPriceOracleV1.sol"; -import {LibFtsoCurrentPriceUsd} from "rain.flare/src/lib/price/LibFtsoCurrentPriceUsd.sol"; +import {LibFtsoCurrentPriceUsd} from "rain.flare/lib/price/LibFtsoCurrentPriceUsd.sol"; import {LibIntOrAString, IntOrAString} from "rain.intorastring/lib/LibIntOrAString.sol"; struct FtsoCurrentPriceUsdOracleConfig { diff --git a/contracts/concrete/oracle/SceptreStakedFlrOracle.sol b/contracts/concrete/oracle/SceptreStakedFlrOracle.sol index 97cd1fce..2069b856 100644 --- a/contracts/concrete/oracle/SceptreStakedFlrOracle.sol +++ b/contracts/concrete/oracle/SceptreStakedFlrOracle.sol @@ -2,7 +2,7 @@ pragma solidity =0.8.25; import {IPriceOracleV1} from "../../interface/IPriceOracleV1.sol"; -import {IStakedFlr} from "../../interface/sceptre/IStakedFlr.sol"; +import {IStakedFlr} from "rain.flare/interface/IStakedFlr.sol"; contract SceptreStakedFlrOracle is IPriceOracleV1 { IStakedFlr public immutable iStakedFlr; diff --git a/contracts/interface/sceptre/IStakedFlr.sol b/contracts/interface/sceptre/IStakedFlr.sol deleted file mode 100644 index ae6fe20d..00000000 --- a/contracts/interface/sceptre/IStakedFlr.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: CAL - -pragma solidity ^0.8.25; - -interface IStakedFlr { - function getSharesByPooledFlr(uint256 flrAmount) external view returns (uint256); - - function getPooledFlrByShares(uint256 shareAmount) external view returns (uint256); - - function submit() external payable returns (uint256); -} diff --git a/foundry.toml b/foundry.toml index 8f730d1f..4dfdf24b 100644 --- a/foundry.toml +++ b/foundry.toml @@ -17,4 +17,5 @@ remappings = [ "rain.factory/=lib/rain.factory/src/", "rain.intorastring/=lib/rain.interpreter/lib/rain.intorastring/src/", "forge-std/=lib/rain.interpreter/lib/forge-std/src/", + "rain.flare/=lib/rain.flare/src/", ] \ No newline at end of file diff --git a/lib/rain.flare b/lib/rain.flare index 48160f27..24e57b5c 160000 --- a/lib/rain.flare +++ b/lib/rain.flare @@ -1 +1 @@ -Subproject commit 48160f27bbf9a379d0414f63b66cf94205bd79d8 +Subproject commit 24e57b5cd2d8ea59b70089ba1ec8fefd19d12023 diff --git a/script/Deploy.sol b/script/Deploy.sol index f66a1345..746133d0 100644 --- a/script/Deploy.sol +++ b/script/Deploy.sol @@ -20,7 +20,7 @@ import { import {Receipt as ReceiptContract} from "contracts/concrete/receipt/Receipt.sol"; import {SceptreStakedFlrOracle} from "contracts/concrete/oracle/SceptreStakedFlrOracle.sol"; import {TwoPriceOracle, TwoPriceOracleConfig} from "contracts/concrete/oracle/TwoPriceOracle.sol"; -import {IStakedFlr} from "contracts/interface/sceptre/IStakedFlr.sol"; +import {IStakedFlr} from "rain.flare/interface/IStakedFlr.sol"; bytes32 constant DEPLOYMENT_SUITE_IMPLEMENTATIONS = keccak256("implementations"); bytes32 constant DEPLOYMENT_SUITE_OWNABLE_ORACLE_VAULT = keccak256("ownable-oracle-vault");