编译器
0.8.17+commit.8df45f5f
文件 1 的 6:AuthNoOwner.sol
pragma solidity 0.8.17;
import {Authority} from "./Authority.sol";
contract AuthNoOwner {
event AuthorityUpdated(address indexed user, Authority indexed newAuthority);
Authority private _authority;
bool private _authorityInitialized;
modifier requiresAuth() virtual {
require(isAuthorized(msg.sender, msg.sig), "Auth: UNAUTHORIZED");
_;
}
function authority() public view returns (Authority) {
return _authority;
}
function authorityInitialized() public view returns (bool) {
return _authorityInitialized;
}
function isAuthorized(address user, bytes4 functionSig) internal view virtual returns (bool) {
Authority auth = _authority;
return (address(auth) != address(0) && auth.canCall(user, address(this), functionSig));
}
function _initializeAuthority(address newAuthority) internal {
require(address(_authority) == address(0), "Auth: authority is non-zero");
require(!_authorityInitialized, "Auth: authority already initialized");
_authority = Authority(newAuthority);
_authorityInitialized = true;
emit AuthorityUpdated(address(this), Authority(newAuthority));
}
}
文件 2 的 6:Authority.sol
pragma solidity 0.8.17;
interface Authority {
function canCall(address user, address target, bytes4 functionSig) external view returns (bool);
}
文件 3 的 6:EbtcFeed.sol
pragma solidity 0.8.17;
import "./Interfaces/IPriceFeed.sol";
import {IPriceFetcher} from "./Interfaces/IOracleCaller.sol";
import "./Dependencies/AuthNoOwner.sol";
contract EbtcFeed is IPriceFeed, AuthNoOwner {
string public constant NAME = "EbtcFeed";
uint256 public lastGoodPrice;
address public primaryOracle;
address public secondaryOracle;
uint256 constant INVALID_PRICE = 0;
address constant UNSET_ADDRESS = address(0);
uint256 constant GAS_LIMIT = 2_000_000;
event PrimaryOracleUpdated(address indexed _oldOracle, address indexed _newOracle);
event SecondaryOracleUpdated(address indexed _oldOracle, address indexed _newOracle);
constructor(address _authorityAddress, address _primaryOracle, address _secondaryOracle) {
_initializeAuthority(_authorityAddress);
uint256 firstPrice = IPriceFetcher(_primaryOracle).fetchPrice();
require(firstPrice != INVALID_PRICE, "EbtcFeed: Primary Oracle Must Work");
_storePrice(firstPrice);
primaryOracle = _primaryOracle;
if (_secondaryOracle != UNSET_ADDRESS) {
uint256 secondaryOraclePrice = IPriceFetcher(_secondaryOracle).fetchPrice();
if (secondaryOraclePrice != INVALID_PRICE) {
secondaryOracle = _secondaryOracle;
}
}
}
function setPrimaryOracle(address _newPrimary) external requiresAuth {
uint256 currentPrice = IPriceFetcher(_newPrimary).fetchPrice();
require(currentPrice != INVALID_PRICE, "EbtcFeed: Primary Oracle Must Work");
emit PrimaryOracleUpdated(primaryOracle, _newPrimary);
primaryOracle = _newPrimary;
}
function setSecondaryOracle(address _newSecondary) external requiresAuth {
if (_newSecondary != UNSET_ADDRESS) {
uint256 currentPrice = IPriceFetcher(_newSecondary).fetchPrice();
require(currentPrice != INVALID_PRICE, "EbtcFeed: Secondary Oracle Must Work");
}
emit SecondaryOracleUpdated(secondaryOracle, _newSecondary);
secondaryOracle = _newSecondary;
}
function fetchPrice() external override returns (uint256) {
uint256 primaryResponse = tinfoilCall(
primaryOracle,
abi.encodeCall(IPriceFetcher.fetchPrice, ())
);
if (primaryResponse != INVALID_PRICE) {
_storePrice(primaryResponse);
return primaryResponse;
}
if (secondaryOracle == UNSET_ADDRESS) {
return lastGoodPrice;
}
uint256 secondaryResponse = tinfoilCall(
secondaryOracle,
abi.encodeCall(IPriceFetcher.fetchPrice, ())
);
if (secondaryResponse != INVALID_PRICE) {
_storePrice(secondaryResponse);
return secondaryResponse;
}
return lastGoodPrice;
}
function _storePrice(uint256 _currentPrice) internal {
lastGoodPrice = _currentPrice;
emit LastGoodPriceUpdated(_currentPrice);
}
function tinfoilCall(address _target, bytes memory _calldata) public returns (uint256) {
uint256 gasLeft = gasleft();
uint256 cappedGas = gasLeft > GAS_LIMIT ? GAS_LIMIT : gasLeft;
(bool success, bytes memory res) = excessivelySafeCall(_target, cappedGas, 0, 32, _calldata);
if (success && res.length == 32) {
return abi.decode(res, (uint256));
}
return INVALID_PRICE;
}
function excessivelySafeCall(
address _target,
uint256 _gas,
uint256 _value,
uint16 _expectedLength,
bytes memory _calldata
) internal returns (bool, bytes memory) {
uint256 _receivedLength;
bool _success;
bytes memory _returnData = new bytes(_expectedLength);
assembly {
_success := call(
_gas,
_target,
_value,
add(_calldata, 0x20),
mload(_calldata),
0,
0
)
_receivedLength := returndatasize()
if eq(_receivedLength, _expectedLength) {
mstore(_returnData, _receivedLength)
returndatacopy(add(_returnData, 0x20), 0, _receivedLength)
}
}
return (_success, _returnData);
}
}
文件 4 的 6:IOracleCaller.sol
pragma solidity 0.8.17;
import "./IPool.sol";
interface IOracleCaller {
function getLatestPrice() external view returns (uint256);
}
interface IPriceFetcher {
function fetchPrice() external returns (uint256);
}
文件 5 的 6:IPool.sol
pragma solidity 0.8.17;
interface IPool {
event ETHBalanceUpdated(uint256 _newBalance);
event EBTCBalanceUpdated(uint256 _newBalance);
event CollSharesTransferred(address indexed _to, uint256 _amount);
function getSystemCollShares() external view returns (uint256);
function getSystemDebt() external view returns (uint256);
function increaseSystemDebt(uint256 _amount) external;
function decreaseSystemDebt(uint256 _amount) external;
}
文件 6 的 6:IPriceFeed.sol
pragma solidity 0.8.17;
interface IPriceFeed {
event LastGoodPriceUpdated(uint256 _lastGoodPrice);
event PriceFeedStatusChanged(Status newStatus);
event FallbackCallerChanged(
address indexed _oldFallbackCaller,
address indexed _newFallbackCaller
);
event UnhealthyFallbackCaller(address indexed _fallbackCaller, uint256 timestamp);
event CollateralFeedSourceUpdated(address indexed stEthFeed);
struct ChainlinkResponse {
uint80 roundEthBtcId;
uint80 roundStEthEthId;
uint256 answer;
uint256 timestampEthBtc;
uint256 timestampStEthEth;
bool success;
}
struct FallbackResponse {
uint256 answer;
uint256 timestamp;
bool success;
}
enum Status {
chainlinkWorking,
usingFallbackChainlinkUntrusted,
bothOraclesUntrusted,
usingFallbackChainlinkFrozen,
usingChainlinkFallbackUntrusted
}
function fetchPrice() external returns (uint256);
}
{
"compilationTarget": {
"contracts/EbtcFeed.sol": "EbtcFeed"
},
"evmVersion": "london",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"inputs":[{"internalType":"address","name":"_authorityAddress","type":"address"},{"internalType":"address","name":"_primaryOracle","type":"address"},{"internalType":"address","name":"_secondaryOracle","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"contract Authority","name":"newAuthority","type":"address"}],"name":"AuthorityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"stEthFeed","type":"address"}],"name":"CollateralFeedSourceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oldFallbackCaller","type":"address"},{"indexed":true,"internalType":"address","name":"_newFallbackCaller","type":"address"}],"name":"FallbackCallerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_lastGoodPrice","type":"uint256"}],"name":"LastGoodPriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IPriceFeed.Status","name":"newStatus","type":"uint8"}],"name":"PriceFeedStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oldOracle","type":"address"},{"indexed":true,"internalType":"address","name":"_newOracle","type":"address"}],"name":"PrimaryOracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_oldOracle","type":"address"},{"indexed":true,"internalType":"address","name":"_newOracle","type":"address"}],"name":"SecondaryOracleUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_fallbackCaller","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"UnhealthyFallbackCaller","type":"event"},{"inputs":[],"name":"NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authority","outputs":[{"internalType":"contract Authority","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"authorityInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"fetchPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lastGoodPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"primaryOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"secondaryOracle","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_newPrimary","type":"address"}],"name":"setPrimaryOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newSecondary","type":"address"}],"name":"setSecondaryOracle","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_target","type":"address"},{"internalType":"bytes","name":"_calldata","type":"bytes"}],"name":"tinfoilCall","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]