文件 1 的 4:Context.sol
pragma solidity >=0.6.0 <0.8.0;
abstract contract Context {
function _msgSender() internal view virtual returns (address payable) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes memory) {
this;
return msg.data;
}
}
文件 2 的 4:ExchangeRateFeeder.sol
pragma solidity >=0.6.0 <0.8.0;
import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
interface IExchangeRateFeeder {
event RateUpdated(
address indexed _operator,
address indexed _token,
uint256 _before,
uint256 _after,
uint256 _updateCount
);
enum Status {NEUTRAL, RUNNING, STOPPED}
struct Token {
Status status;
uint256 exchangeRate;
uint256 period;
uint256 weight;
uint256 lastUpdatedAt;
}
function exchangeRateOf(address _token, bool _simulate)
external
view
returns (uint256);
function update(address _token) external;
}
interface IExchangeRateFeederGov {
function addToken(
address _token,
uint256 _baseRate,
uint256 _period,
uint256 _weight
) external;
function startUpdate(address[] memory _tokens) external;
function stopUpdate(address[] memory _tokens) external;
}
contract ExchangeRateFeeder is IExchangeRateFeeder, Ownable {
using SafeMath for uint256;
mapping(address => Token) public tokens;
function addToken(
address _token,
uint256 _baseRate,
uint256 _period,
uint256 _weight
) public onlyOwner {
tokens[_token] = Token({
status: Status.NEUTRAL,
exchangeRate: _baseRate,
period: _period,
weight: _weight,
lastUpdatedAt: block.timestamp
});
}
function startUpdate(address[] memory _tokens) public onlyOwner {
for (uint256 i = 0; i < _tokens.length; i++) {
if (tokens[_tokens[i]].status == Status.RUNNING) {
update(_tokens[i]);
} else {
tokens[_tokens[i]].status = Status.RUNNING;
}
tokens[_tokens[i]].lastUpdatedAt = block.timestamp;
}
}
function stopUpdate(address[] memory _tokens) public onlyOwner {
for (uint256 i = 0; i < _tokens.length; i++) {
tokens[_tokens[i]].status = Status.STOPPED;
}
}
function exchangeRateOf(address _token, bool _simulate)
public
view
override
returns (uint256)
{
uint256 exchangeRate = tokens[_token].exchangeRate;
if (_simulate) {
Token memory token = tokens[_token];
uint256 elapsed = block.timestamp.sub(token.lastUpdatedAt);
uint256 updateCount = elapsed.div(token.period);
for (uint256 i = 0; i < updateCount; i++) {
exchangeRate = exchangeRate.mul(token.weight).div(1e18);
}
}
return exchangeRate;
}
function update(address _token) public override {
Token memory token = tokens[_token];
require(token.status == Status.RUNNING, "Feeder: invalid status");
uint256 elapsed = block.timestamp.sub(token.lastUpdatedAt);
if (elapsed < token.period) {
return;
}
uint256 updateCount = elapsed.div(token.period);
uint256 exchangeRateBefore = token.exchangeRate;
for (uint256 i = 0; i < updateCount; i++) {
token.exchangeRate = token.exchangeRate.mul(token.weight).div(1e18);
}
token.lastUpdatedAt = token.lastUpdatedAt.add(
updateCount.mul(token.period)
);
tokens[_token] = token;
emit RateUpdated(
msg.sender,
_token,
exchangeRateBefore,
token.exchangeRate,
updateCount
);
}
}
文件 3 的 4:Ownable.sol
pragma solidity >=0.6.0 <0.8.0;
import "../utils/Context.sol";
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
constructor () internal {
address msgSender = _msgSender();
_owner = msgSender;
emit OwnershipTransferred(address(0), msgSender);
}
function owner() public view virtual returns (address) {
return _owner;
}
modifier onlyOwner() {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
_;
}
function renounceOwnership() public virtual onlyOwner {
emit OwnershipTransferred(_owner, address(0));
_owner = address(0);
}
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
emit OwnershipTransferred(_owner, newOwner);
_owner = newOwner;
}
}
文件 4 的 4:SafeMath.sol
pragma solidity >=0.6.0 <0.8.0;
library SafeMath {
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b > a) return (false, 0);
return (true, a - b);
}
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a / b);
}
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
if (b == 0) return (false, 0);
return (true, a % b);
}
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
return a - b;
}
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
return a / b;
}
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: modulo by zero");
return a % b;
}
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b <= a, errorMessage);
return a - b;
}
function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a / b;
}
function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
require(b > 0, errorMessage);
return a % b;
}
}
{
"compilationTarget": {
"contracts/extensions/ExchangeRateFeeder.sol": "ExchangeRateFeeder"
},
"evmVersion": "istanbul",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 200
},
"remappings": []
}
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_operator","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_before","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_after","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_updateCount","type":"uint256"}],"name":"RateUpdated","type":"event"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_baseRate","type":"uint256"},{"internalType":"uint256","name":"_period","type":"uint256"},{"internalType":"uint256","name":"_weight","type":"uint256"}],"name":"addToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bool","name":"_simulate","type":"bool"}],"name":"exchangeRateOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"}],"name":"startUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"}],"name":"stopUpdate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokens","outputs":[{"internalType":"enum IExchangeRateFeeder.Status","name":"status","type":"uint8"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"},{"internalType":"uint256","name":"period","type":"uint256"},{"internalType":"uint256","name":"weight","type":"uint256"},{"internalType":"uint256","name":"lastUpdatedAt","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"update","outputs":[],"stateMutability":"nonpayable","type":"function"}]