This repository has been archived by the owner on Mar 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
RootPriceOracle.sol
108 lines (87 loc) · 4.59 KB
/
RootPriceOracle.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2023 Tokemak Foundation. All rights reserved.
pragma solidity 0.8.17;
import { Errors } from "src/utils/Errors.sol";
import { SecurityBase } from "src/security/SecurityBase.sol";
import { ISystemRegistry } from "src/interfaces/ISystemRegistry.sol";
import { IPriceOracle } from "src/interfaces/oracles/IPriceOracle.sol";
import { IRootPriceOracle } from "src/interfaces/oracles/IRootPriceOracle.sol";
import { SystemComponent } from "src/SystemComponent.sol";
contract RootPriceOracle is SystemComponent, SecurityBase, IRootPriceOracle {
mapping(address => IPriceOracle) public tokenMappings;
event TokenRemoved(address token);
event TokenRegistered(address token, address oracle);
event TokenRegistrationReplaced(address token, address oldOracle, address newOracle);
error AlreadyRegistered(address token);
error MissingTokenOracle(address token);
error MappingDoesNotExist(address token);
error ReplaceOldMismatch(address token, address oldExpected, address oldActual);
error ReplaceAlreadyMatches(address token, address newOracle);
constructor(ISystemRegistry _systemRegistry)
SystemComponent(_systemRegistry)
SecurityBase(address(_systemRegistry.accessController()))
{ }
/// @notice Register a new token to oracle mapping
/// @dev May require additional registration in the oracle itself
/// @param token address of the token to register
/// @param oracle address of the oracle to use to lookup price
function registerMapping(address token, IPriceOracle oracle) external onlyOwner {
Errors.verifyNotZero(token, "token");
Errors.verifyNotZero(address(oracle), "oracle");
Errors.verifySystemsMatch(address(this), address(oracle));
// We want the operation of replacing a mapping to be an explicit
// call so we don't accidentally overwrite something
if (address(tokenMappings[token]) != address(0)) {
revert AlreadyRegistered(token);
}
tokenMappings[token] = oracle;
emit TokenRegistered(token, address(oracle));
}
/// @notice Replace an existing token -> oracle mapping
/// @dev Must exist, matching existing, and new != old value to successfully replace
/// @param token address of the token to register
/// @param oldOracle existing oracle address
/// @param newOracle new oracle address
function replaceMapping(address token, IPriceOracle oldOracle, IPriceOracle newOracle) external onlyOwner {
Errors.verifyNotZero(token, "token");
Errors.verifyNotZero(address(oldOracle), "oldOracle");
Errors.verifyNotZero(address(newOracle), "newOracle");
Errors.verifySystemsMatch(address(this), address(newOracle));
// We want to ensure you know what you're replacing so ensure
// you provide a matching old value
if (tokenMappings[token] != oldOracle) {
revert ReplaceOldMismatch(token, address(oldOracle), address(tokenMappings[token]));
}
// If the old and new values match we can assume you're not doing
// what you think you're doing so we just fail
if (oldOracle == newOracle) {
revert ReplaceAlreadyMatches(token, address(newOracle));
}
tokenMappings[token] = newOracle;
emit TokenRegistrationReplaced(token, address(oldOracle), address(newOracle));
}
/// @notice Remove a token to oracle mapping
/// @dev Must exist. Does not remove any additional configuration from the oracle itself
/// @param token address of the token that is registered
function removeMapping(address token) external onlyOwner {
Errors.verifyNotZero(token, "token");
// If you're trying to remove something that doesn't exist then
// some condition you're expecting isn't true. We revert so you can reevaluate
if (address(tokenMappings[token]) == address(0)) {
revert MappingDoesNotExist(token);
}
delete tokenMappings[token];
emit TokenRemoved(token);
}
/// @dev This and all price oracles are not view fn's so that we can perform the Curve reentrancy check
/// @inheritdoc IRootPriceOracle
function getPriceInEth(address token) external returns (uint256 price) {
// Skip the token address(0) check and just rely on the oracle lookup
// Emit token so we can figure out what was actually 0 later
IPriceOracle oracle = tokenMappings[token];
if (address(0) == address(oracle)) {
revert MissingTokenOracle(token);
}
price = oracle.getPriceInEth(token);
}
}