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

feat: oracles with firewalls on mint and burn #105

Merged
merged 54 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
66eb024
feat: oracles with firewalls on mint and burn
GuillaumeNervoXS Feb 27, 2024
55cb6d5
feat: oracles with target value as max
GuillaumeNervoXS Feb 27, 2024
e04c233
feat: fixed tests + test on mint and burn firewalls oracles
GuillaumeNervoXS Feb 28, 2024
9b7f422
test updateOracle
GuillaumeNervoXS Feb 29, 2024
120dd7d
feat: start testing deployment
GuillaumeNervoXS Mar 1, 2024
d29323a
feat: start scripts
GuillaumeNervoXS Mar 5, 2024
e2f708e
feat: mint and burn test done
GuillaumeNervoXS Mar 5, 2024
c383fb0
chore: try to fix linter issues
GuillaumeNervoXS Mar 5, 2024
feef55a
feat: testing done
GuillaumeNervoXS Mar 5, 2024
2f8fce5
format: prettier contracts
0xtekgrinder Mar 7, 2024
04ac2e1
chore : add scripts to ignored files in slither
0xtekgrinder Mar 7, 2024
dbe114a
chore: add uri env variables to ci tests
0xtekgrinder Mar 7, 2024
6afa900
fix: SwapTest and SavingsTest now compiles
0xtekgrinder Mar 10, 2024
bfa582e
fix part of the stack too deep when via-ir
GuillaumeNervoXS Mar 6, 2024
2742aa2
chore remap import from test
GuillaumeNervoXS Mar 6, 2024
ac8b2de
find which test files has compilation problem
GuillaumeNervoXS Mar 8, 2024
b83ff6b
fix all compilation tests except RedeemTest
GuillaumeNervoXS Mar 11, 2024
74b17b2
add back the RedeemTest
GuillaumeNervoXS Mar 11, 2024
4c6f8cf
fix redeem test compilation
GuillaumeNervoXS Mar 11, 2024
b0c9ee3
chore: setup repo inside ci
0xtekgrinder Mar 11, 2024
31b853d
chore: move setup repo action to actions subdirectory
0xtekgrinder Mar 11, 2024
54fb2dd
start burn protection for users
GuillaumeNervoXS Mar 13, 2024
41d56b5
fix firewall and user protection + tests
GuillaumeNervoXS Mar 13, 2024
218ef40
feat: add back burnRatio deviation user protection
GuillaumeNervoXS Mar 14, 2024
621d3c8
fix burnRatio protection
GuillaumeNervoXS Mar 14, 2024
93d4184
return ratio
GuillaumeNervoXS Mar 14, 2024
d509e5f
tests fixed
GuillaumeNervoXS Mar 20, 2024
cacd0fb
decimal issue
GuillaumeNervoXS Mar 20, 2024
159ed48
working tests
GuillaumeNervoXS Mar 21, 2024
f6be794
yarn prettier
GuillaumeNervoXS Mar 21, 2024
81c22ce
add bERNX + new target exposures
GuillaumeNervoXS Mar 21, 2024
df4f36e
testing after adding bERNX
GuillaumeNervoXS Mar 21, 2024
565cdaf
feat: change updateOracle to only trustedSeller only
GuillaumeNervoXS Mar 21, 2024
fb88360
add fork block number option
GuillaumeNervoXS Mar 22, 2024
d88e96d
change input to secret
GuillaumeNervoXS Mar 22, 2024
727afa6
revert prev change
GuillaumeNervoXS Mar 22, 2024
ba97362
add space
GuillaumeNervoXS Mar 22, 2024
3103458
fix: fix install
BaptistG Mar 22, 2024
0cdbe3c
update vscode settings
GuillaumeNervoXS Mar 22, 2024
6684097
reduce stack too deep
GuillaumeNervoXS Mar 22, 2024
5fa9919
fix burn test
GuillaumeNervoXS Mar 22, 2024
2c06fd8
revert deadline tests changes
GuillaumeNervoXS Mar 22, 2024
8623ccf
feat: USDA setup (#108)
sogipec Mar 25, 2024
7f4db42
Add a test on non arbitrage Mint->Burn
GuillaumeNervoXS Mar 27, 2024
60350fd
update post review
GuillaumeNervoXS Mar 27, 2024
cee97ae
removed checks on oracle update
GuillaumeNervoXS Mar 27, 2024
b75b0f0
compiling version
GuillaumeNervoXS Mar 27, 2024
e5052ff
fix tests
GuillaumeNervoXS Mar 27, 2024
b5489b0
fix all tests and deploy tests
GuillaumeNervoXS Mar 28, 2024
794b604
chore: review minor changes
GuillaumeNervoXS Mar 28, 2024
9235e72
update oracle hyperparameters
GuillaumeNervoXS Mar 28, 2024
e0f3824
remove test on no arbitrage --> impossible with the user protections
GuillaumeNervoXS Mar 28, 2024
ea38373
fix: invariant testing
GuillaumeNervoXS Mar 28, 2024
ea9f6f2
deployed update transmuter
GuillaumeNervoXS Mar 29, 2024
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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"editor.defaultFormatter": "JuanBlanco.solidity"
},
"editor.codeActionsOnSave": {
"source.fixAll": true
"source.fixAll": "explicit"
},
"workbench.colorCustomizations": {
"diffEditor.insertedTextBackground": "#00bb0044",
Expand Down
3 changes: 2 additions & 1 deletion contracts/interfaces/IGetters.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ interface IGetters {
OracleReadType oracleType,
OracleReadType targetType,
bytes memory oracleData,
bytes memory targetData
bytes memory targetData,
bytes memory hyperparameters
);

/// @notice Returns if the associated functionality is paused or not
Expand Down
10 changes: 10 additions & 0 deletions contracts/interfaces/IOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.5.0;

/// @title IOracle
/// @author Angle Labs, Inc.
interface IOracle {
/// @notice Update oracle data for a given `collateral`
function updateOracle(address collateral) external;
}
2 changes: 2 additions & 0 deletions contracts/interfaces/ITransmuter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { IDiamondCut } from "./IDiamondCut.sol";
import { IDiamondEtherscan } from "./IDiamondEtherscan.sol";
import { IDiamondLoupe } from "./IDiamondLoupe.sol";
import { IGetters } from "./IGetters.sol";
import { IOracle } from "./IOracle.sol";
import { IRedeemer } from "./IRedeemer.sol";
import { IRewardHandler } from "./IRewardHandler.sol";
import { ISettersGovernor, ISettersGuardian } from "./ISetters.sol";
Expand All @@ -51,6 +52,7 @@ interface ITransmuter is
IDiamondEtherscan,
IDiamondLoupe,
IGetters,
IOracle,
IRedeemer,
IRewardHandler,
ISettersGovernor,
Expand Down
3 changes: 3 additions & 0 deletions contracts/interfaces/ITransmuterOracle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ interface ITransmuterOracle {
/// @notice Reads the oracle value for asset to use in a burn transaction as well as the ratio
/// between the current price and the target price for the asset
function readBurn() external view returns (uint256 oracleValue, uint256 ratio);

/// @notice Reads the oracle value for asset
function read() external view returns (uint256);
}
83 changes: 42 additions & 41 deletions contracts/transmuter/Storage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ enum OracleReadType {
CBETH,
RETH,
SFRXETH,
PYTH
PYTH,
MAX
}

enum OracleQuoteType {
Expand All @@ -64,70 +65,70 @@ enum WhitelistType {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

struct Permit2Details {
address to; // Address that will receive the funds
uint256 nonce; // Nonce of the transaction
bytes signature; // Permit signature of the user
address to; // Address that will receive the funds
uint256 nonce; // Nonce of the transaction
bytes signature; // Permit signature of the user
}

struct FacetCut {
address facetAddress; // Facet contract address
FacetCutAction action; // Can be add, remove or replace
bytes4[] functionSelectors; // Ex. bytes4(keccak256("transfer(address,uint256)"))
address facetAddress; // Facet contract address
FacetCutAction action; // Can be add, remove or replace
bytes4[] functionSelectors; // Ex. bytes4(keccak256("transfer(address,uint256)"))
}

struct Facet {
address facetAddress; // Facet contract address
bytes4[] functionSelectors; // Ex. bytes4(keccak256("transfer(address,uint256)"))
address facetAddress; // Facet contract address
bytes4[] functionSelectors; // Ex. bytes4(keccak256("transfer(address,uint256)"))
}

struct FacetInfo {
address facetAddress; // Facet contract address
uint16 selectorPosition; // Position in the list of all selectors
address facetAddress; // Facet contract address
uint16 selectorPosition; // Position in the list of all selectors
}

struct DiamondStorage {
bytes4[] selectors; // List of all available selectors
mapping(bytes4 => FacetInfo) selectorInfo; // Selector to (address, position in list)
IAccessControlManager accessControlManager; // Contract handling access control
bytes4[] selectors; // List of all available selectors
mapping(bytes4 => FacetInfo) selectorInfo; // Selector to (address, position in list)
IAccessControlManager accessControlManager; // Contract handling access control
}

struct ImplementationStorage {
address implementation; // Dummy implementation address for Etherscan usability
address implementation; // Dummy implementation address for Etherscan usability
}

struct ManagerStorage {
IERC20[] subCollaterals; // Subtokens handled by the manager or strategies
bytes config; // Additional configuration data
IERC20[] subCollaterals; // Subtokens handled by the manager or strategies
bytes config; // Additional configuration data
}

struct Collateral {
uint8 isManaged; // If the collateral is managed through external strategies
uint8 isMintLive; // If minting from this asset is unpaused
uint8 isBurnLive; // If burning to this asset is unpaused
uint8 decimals; // IERC20Metadata(collateral).decimals()
uint8 onlyWhitelisted; // If only whitelisted addresses can burn or redeem for this token
uint216 normalizedStables; // Normalized amount of stablecoins issued from this collateral
uint64[] xFeeMint; // Increasing exposures in [0,BASE_9[
int64[] yFeeMint; // Mint fees at the exposures specified in `xFeeMint`
uint64[] xFeeBurn; // Decreasing exposures in ]0,BASE_9]
int64[] yFeeBurn; // Burn fees at the exposures specified in `xFeeBurn`
bytes oracleConfig; // Data about the oracle used for the collateral
bytes whitelistData; // For whitelisted collateral, data used to verify whitelists
ManagerStorage managerData; // For managed collateral, data used to handle the strategies
uint8 isManaged; // If the collateral is managed through external strategies
sogipec marked this conversation as resolved.
Show resolved Hide resolved
uint8 isMintLive; // If minting from this asset is unpaused
uint8 isBurnLive; // If burning to this asset is unpaused
uint8 decimals; // IERC20Metadata(collateral).decimals()
uint8 onlyWhitelisted; // If only whitelisted addresses can burn or redeem for this token
uint216 normalizedStables; // Normalized amount of stablecoins issued from this collateral
uint64[] xFeeMint; // Increasing exposures in [0,BASE_9[
int64[] yFeeMint; // Mint fees at the exposures specified in `xFeeMint`
uint64[] xFeeBurn; // Decreasing exposures in ]0,BASE_9]
int64[] yFeeBurn; // Burn fees at the exposures specified in `xFeeBurn`
bytes oracleConfig; // Data about the oracle used for the collateral
bytes whitelistData; // For whitelisted collateral, data used to verify whitelists
ManagerStorage managerData; // For managed collateral, data used to handle the strategies
}

struct TransmuterStorage {
IAgToken agToken; // agToken handled by the system
uint8 isRedemptionLive; // If redemption is unpaused
uint8 statusReentrant; // If call is reentrant or not
uint128 normalizedStables; // Normalized amount of stablecoins issued by the system
uint128 normalizer; // To reconcile `normalizedStables` values with the actual amount
address[] collateralList; // List of collateral assets supported by the system
uint64[] xRedemptionCurve; // Increasing collateral ratios > 0
int64[] yRedemptionCurve; // Value of the redemption fees at `xRedemptionCurve`
mapping(address => Collateral) collaterals; // Maps a collateral asset to its parameters
mapping(address => uint256) isTrusted; // If an address is trusted to update the normalizer value
IAgToken agToken; // agToken handled by the system
uint8 isRedemptionLive; // If redemption is unpaused
uint8 statusReentrant; // If call is reentrant or not
uint128 normalizedStables; // Normalized amount of stablecoins issued by the system
uint128 normalizer; // To reconcile `normalizedStables` values with the actual amount
address[] collateralList; // List of collateral assets supported by the system
uint64[] xRedemptionCurve; // Increasing collateral ratios > 0
int64[] yRedemptionCurve; // Value of the redemption fees at `xRedemptionCurve`
mapping(address => Collateral) collaterals; // Maps a collateral asset to its parameters
mapping(address => uint256) isTrusted; // If an address is trusted to update the normalizer value
mapping(address => uint256) isSellerTrusted; // If an address is trusted to sell accruing reward tokens
GuillaumeNervoXS marked this conversation as resolved.
Show resolved Hide resolved
mapping(WhitelistType => mapping(address => uint256)) isWhitelistedForType;
// Whether an address is whitelisted for a specific whitelist type
// Whether an address is whitelisted for a specific whitelist type
}
4 changes: 3 additions & 1 deletion contracts/transmuter/configs/FakeGnosis.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
address[] memory _collateralAddresses,
address[] memory _oracleAddresses
) external {
uint256 BPS = 1e14;

Check warning on line 31 in contracts/transmuter/configs/FakeGnosis.sol

View workflow job for this annotation

GitHub Actions / lint

Variable name must be in mixedCase
sogipec marked this conversation as resolved.
Show resolved Hide resolved
// Fee structure

uint64[] memory xMintFee = new uint64[](4);
Expand Down Expand Up @@ -85,7 +86,8 @@
Storage.OracleReadType.CHAINLINK_FEEDS,
Storage.OracleReadType.STABLE,
readData,
targetData
targetData,
abi.encode(uint128(0), uint128(50 * BPS))
);
collaterals[i] = CollateralSetupProd(
_collateralAddresses[i],
Expand Down
107 changes: 61 additions & 46 deletions contracts/transmuter/configs/Production.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@

/// @dev This contract is used only once to initialize the diamond proxy.
contract Production {
error WrongSetup();

function initialize(
IAccessControlManager _accessControlManager,
address _agToken,
address dummyImplementation
) external {
uint256 BPS = 1e14;

Check warning on line 16 in contracts/transmuter/configs/Production.sol

View workflow job for this annotation

GitHub Actions / lint

Variable name must be in mixedCase
address euroc = 0x1aBaEA1f7C830bD89Acc67eC4af516284b1bC33c;
address bc3m = 0x2F123cF3F37CE3328CC9B5b8415f9EC5109b45e7;
require(address(_accessControlManager) == 0x5bc6BEf80DA563EBf6Df6D6913513fa9A7ec89BE);

Check warning on line 19 in contracts/transmuter/configs/Production.sol

View workflow job for this annotation

GitHub Actions / lint

Use Custom Errors instead of require statements
require(address(_agToken) == 0x1a7e4e63778B4f12a199C062f3eFdD288afCBce8);

Check warning on line 20 in contracts/transmuter/configs/Production.sol

View workflow job for this annotation

GitHub Actions / lint

Use Custom Errors instead of require statements

// Check this docs for simulations:
// https://docs.google.com/spreadsheets/d/1UxS1m4sG8j2Lv02wONYJNkF4S7NDLv-5iyAzFAFTfXw/edit#gid=0
Expand Down Expand Up @@ -47,27 +50,31 @@
bytes memory oracleConfig;
{
// Pyth oracle for EUROC
bytes32[] memory feedIds = new bytes32[](2);
uint32[] memory stalePeriods = new uint32[](2);
uint8[] memory isMultiplied = new uint8[](2);
// pyth address
address pyth = 0x4305FB66699C3B2702D4d05CF36551390A4c69C6;
// EUROC/USD
feedIds[0] = 0x76fa85158bf14ede77087fe3ae472f66213f6ea2f5b411cb2de472794990fa5c;
// USD/EUR
feedIds[1] = 0xa995d00bb36a63cef7fd2c287dc105fc8f3d93779f062f09551b0af3e81ec30b;
stalePeriods[0] = 14 days;
stalePeriods[1] = 14 days;
isMultiplied[0] = 1;
isMultiplied[1] = 0;
OracleQuoteType quoteType = OracleQuoteType.UNIT;
bytes memory readData = abi.encode(pyth, feedIds, stalePeriods, isMultiplied, quoteType);
bytes memory readData;
{
bytes32[] memory feedIds = new bytes32[](2);
uint32[] memory stalePeriods = new uint32[](2);
uint8[] memory isMultiplied = new uint8[](2);
// pyth address
address pyth = 0x4305FB66699C3B2702D4d05CF36551390A4c69C6;
// EUROC/USD
feedIds[0] = 0x76fa85158bf14ede77087fe3ae472f66213f6ea2f5b411cb2de472794990fa5c;
// USD/EUR
feedIds[1] = 0xa995d00bb36a63cef7fd2c287dc105fc8f3d93779f062f09551b0af3e81ec30b;
stalePeriods[0] = 14 days;
stalePeriods[1] = 14 days;
isMultiplied[0] = 1;
isMultiplied[1] = 0;
OracleQuoteType quoteType = OracleQuoteType.UNIT;
readData = abi.encode(pyth, feedIds, stalePeriods, isMultiplied, quoteType);
}
bytes memory targetData;
oracleConfig = abi.encode(
Storage.OracleReadType.PYTH,
Storage.OracleReadType.STABLE,
readData,
targetData
targetData,
abi.encode(uint128(0), uint128(50 * BPS))
);
}
collaterals[0] = CollateralSetupProd(
Expand Down Expand Up @@ -102,41 +109,49 @@
yBurnFeeC3M[1] = int64(uint64((5 * BASE_9) / 1000));
yBurnFeeC3M[2] = int64(uint64(MAX_BURN_FEE));

AggregatorV3Interface[] memory circuitChainlink = new AggregatorV3Interface[](1);
uint32[] memory stalePeriods = new uint32[](1);
uint8[] memory circuitChainIsMultiplied = new uint8[](1);
uint8[] memory chainlinkDecimals = new uint8[](1);

// bC3M: Redstone as a current price (more accurate for redemptions), and Backed as a target

// Redstone C3M Oracle
circuitChainlink[0] = AggregatorV3Interface(0x6E27A25999B3C665E44D903B2139F5a4Be2B6C26);
stalePeriods[0] = 3 days;
circuitChainIsMultiplied[0] = 1;
chainlinkDecimals[0] = 8;
OracleQuoteType quoteType = OracleQuoteType.UNIT;
bytes memory readData = abi.encode(
circuitChainlink,
stalePeriods,
circuitChainIsMultiplied,
chainlinkDecimals,
quoteType
);
bytes memory readData;
{
AggregatorV3Interface[] memory circuitChainlink = new AggregatorV3Interface[](1);
uint32[] memory stalePeriods = new uint32[](1);
uint8[] memory circuitChainIsMultiplied = new uint8[](1);
uint8[] memory chainlinkDecimals = new uint8[](1);

// bC3M: Redstone as a current price (more accurate for redemptions), and Backed as a target

// Redstone C3M Oracle
circuitChainlink[0] = AggregatorV3Interface(0x6E27A25999B3C665E44D903B2139F5a4Be2B6C26);
stalePeriods[0] = 3 days;
circuitChainIsMultiplied[0] = 1;
chainlinkDecimals[0] = 8;
OracleQuoteType quoteType = OracleQuoteType.UNIT;
readData = abi.encode(
circuitChainlink,
stalePeriods,
circuitChainIsMultiplied,
chainlinkDecimals,
quoteType
);
}

// Backed C3M Oracle
circuitChainlink[0] = AggregatorV3Interface(0x83Ec02059F686E747392A22ddfED7833bA0d7cE3);
bytes memory targetData = abi.encode(
circuitChainlink,
stalePeriods,
circuitChainIsMultiplied,
chainlinkDecimals,
quoteType
);
bytes memory targetData;
{
uint256 initialValue;

{
(, int256 ratio, , , ) = AggregatorV3Interface(0x83Ec02059F686E747392A22ddfED7833bA0d7cE3)
.latestRoundData();
if (ratio <= 0) revert WrongSetup();
initialValue = (BASE_18 * uint256(ratio)) / 1e8;
}
targetData = abi.encode(initialValue, block.timestamp, 50 * BPS, 1 days);
}
bytes memory oracleConfig = abi.encode(
Storage.OracleReadType.CHAINLINK_FEEDS,
Storage.OracleReadType.CHAINLINK_FEEDS,
Storage.OracleReadType.MAX,
readData,
targetData
targetData,
abi.encode(uint128(20000 * BPS), uint128(100 * BPS))
);

collaterals[1] = CollateralSetupProd(
Expand Down
41 changes: 23 additions & 18 deletions contracts/transmuter/configs/ProductionUSD.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ contract ProductionUSD {
address _agToken,
address dummyImplementation
) external {
uint256 BPS = 1e14;
address usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
/*
require(address(_accessControlManager) == 0x5bc6BEf80DA563EBf6Df6D6913513fa9A7ec89BE);
Expand All @@ -35,30 +36,34 @@ contract ProductionUSD {

bytes memory oracleConfig;
{
AggregatorV3Interface[] memory circuitChainlink = new AggregatorV3Interface[](1);
uint32[] memory stalePeriods = new uint32[](1);
uint8[] memory circuitChainIsMultiplied = new uint8[](1);
uint8[] memory chainlinkDecimals = new uint8[](1);
bytes memory readData;
{
AggregatorV3Interface[] memory circuitChainlink = new AggregatorV3Interface[](1);
uint32[] memory stalePeriods = new uint32[](1);
uint8[] memory circuitChainIsMultiplied = new uint8[](1);
uint8[] memory chainlinkDecimals = new uint8[](1);

// Chainlink USDC/USD oracle
circuitChainlink[0] = AggregatorV3Interface(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6);
stalePeriods[0] = 1 days;
circuitChainIsMultiplied[0] = 1;
chainlinkDecimals[0] = 8;
OracleQuoteType quoteType = OracleQuoteType.UNIT;
bytes memory readData = abi.encode(
circuitChainlink,
stalePeriods,
circuitChainIsMultiplied,
chainlinkDecimals,
quoteType
);
// Chainlink USDC/USD oracle
circuitChainlink[0] = AggregatorV3Interface(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6);
stalePeriods[0] = 1 days;
circuitChainIsMultiplied[0] = 1;
chainlinkDecimals[0] = 8;
OracleQuoteType quoteType = OracleQuoteType.UNIT;
readData = abi.encode(
circuitChainlink,
stalePeriods,
circuitChainIsMultiplied,
chainlinkDecimals,
quoteType
);
}
bytes memory targetData;
oracleConfig = abi.encode(
Storage.OracleReadType.CHAINLINK_FEEDS,
Storage.OracleReadType.STABLE,
readData,
targetData
targetData,
abi.encode(uint128(0), uint128(50 * BPS))
);
}
collaterals[0] = CollateralSetupProd(
Expand Down
Loading
Loading