├── HBOToken └── contracts │ ├── ERC677Token.sol │ ├── HBOToken.sol │ ├── interfaces │ ├── ERC20.sol │ ├── ERC20Basic.sol │ ├── ERC677.sol │ └── ERC677Receiver.sol │ └── vendor │ ├── BasicToken.sol │ ├── SafeMathHBO.sol │ └── StandardToken.sol ├── README.md └── contracts ├── AccessControlledAggregator.sol ├── AggregatorFacade.sol ├── AggregatorProxy.sol ├── CheckedMath.sol ├── DeviationFlaggingValidator.sol ├── EACAggregatorProxy.sol ├── Flags.sol ├── FluxAggregator.sol ├── HashBridgeOracle.sol ├── HashBridgeOracleClient.sol ├── HashBridgeOracleTokenReceiver.sol ├── Median.sol ├── Migrations.sol ├── Oracle.sol ├── Owned.sol ├── PreCoordinator.sol ├── SafeMath128.sol ├── SafeMath32.sol ├── SafeMath64.sol ├── SignedSafeMath.sol ├── SimpleReadAccessController.sol ├── SimpleWriteAccessController.sol ├── VRF.sol ├── VRFConsumerBase.sol ├── VRFCoordinator.sol ├── VRFRequestIDBase.sol ├── dev └── BlockhashStore.sol ├── examples ├── OracleDemo.sol └── VRFD20.sol ├── interfaces ├── AccessControllerInterface.sol ├── AggregatorInterface.sol ├── AggregatorV2V3Interface.sol ├── AggregatorV3Interface.sol ├── AggregatorValidatorInterface.sol ├── BlockHashStoreInterface.sol ├── ENSInterface.sol ├── FlagsInterface.sol ├── HashBridgeOracleRequestInterface.sol ├── HashBridgeOracleTokenInterface.sol ├── OracleInterface.sol ├── PointerInterface.sol └── WithdrawalInterface.sol └── vendor ├── BufferHashBridgeOracle.sol ├── CBORHashBridgeOracle.sol ├── ENSResolver.sol ├── Ownable.sol └── SafeMathHashBridgeOracle.sol /HBOToken/contracts/ERC677Token.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import "./interfaces/ERC677.sol"; 5 | import "./interfaces/ERC677Receiver.sol"; 6 | 7 | 8 | contract ERC677Token is ERC677 { 9 | 10 | /** 11 | * @dev transfer token to a contract address with additional data if the recipient is a contact. 12 | * @param _to The address to transfer to. 13 | * @param _value The amount to be transferred. 14 | * @param _data The extra data to be passed to the receiving contract. 15 | */ 16 | function transferAndCall(address _to, uint _value, bytes _data) 17 | public 18 | returns (bool success) 19 | { 20 | super.transfer(_to, _value); 21 | Transfer(msg.sender, _to, _value, _data); 22 | if (isContract(_to)) { 23 | contractFallback(_to, _value, _data); 24 | } 25 | return true; 26 | } 27 | 28 | 29 | // PRIVATE 30 | 31 | function contractFallback(address _to, uint _value, bytes _data) 32 | private 33 | { 34 | ERC677Receiver receiver = ERC677Receiver(_to); 35 | receiver.onTokenTransfer(msg.sender, _value, _data); 36 | } 37 | 38 | function isContract(address _addr) 39 | private 40 | returns (bool hasCode) 41 | { 42 | uint length; 43 | assembly { length := extcodesize(_addr) } 44 | return length > 0; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /HBOToken/contracts/HBOToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import "./ERC677Token.sol"; 5 | import { StandardToken as HBOStandardToken } from "./vendor/StandardToken.sol"; 6 | 7 | 8 | contract HBOToken is HBOStandardToken, ERC677Token { 9 | 10 | uint public constant totalSupply = 10**27; 11 | string public constant name = "Hash Bridge Oracel"; 12 | uint8 public constant decimals = 18; 13 | string public constant symbol = "HBO"; 14 | 15 | function HBOToken(address holder) 16 | public 17 | { 18 | balances[holder] = totalSupply; 19 | } 20 | 21 | /** 22 | * @dev transfer token to a specified address with additional data if the recipient is a contract. 23 | * @param _to The address to transfer to. 24 | * @param _value The amount to be transferred. 25 | * @param _data The extra data to be passed to the receiving contract. 26 | */ 27 | function transferAndCall(address _to, uint _value, bytes _data) 28 | public 29 | validRecipient(_to) 30 | returns (bool success) 31 | { 32 | return super.transferAndCall(_to, _value, _data); 33 | } 34 | 35 | /** 36 | * @dev transfer token to a specified address. 37 | * @param _to The address to transfer to. 38 | * @param _value The amount to be transferred. 39 | */ 40 | function transfer(address _to, uint _value) 41 | public 42 | validRecipient(_to) 43 | returns (bool success) 44 | { 45 | return super.transfer(_to, _value); 46 | } 47 | 48 | /** 49 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 50 | * @param _spender The address which will spend the funds. 51 | * @param _value The amount of tokens to be spent. 52 | */ 53 | function approve(address _spender, uint256 _value) 54 | public 55 | validRecipient(_spender) 56 | returns (bool) 57 | { 58 | return super.approve(_spender, _value); 59 | } 60 | 61 | /** 62 | * @dev Transfer tokens from one address to another 63 | * @param _from address The address which you want to send tokens from 64 | * @param _to address The address which you want to transfer to 65 | * @param _value uint256 the amount of tokens to be transferred 66 | */ 67 | function transferFrom(address _from, address _to, uint256 _value) 68 | public 69 | validRecipient(_to) 70 | returns (bool) 71 | { 72 | return super.transferFrom(_from, _to, _value); 73 | } 74 | 75 | 76 | // MODIFIERS 77 | 78 | modifier validRecipient(address _recipient) { 79 | require(_recipient != address(0) && _recipient != address(this)); 80 | _; 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /HBOToken/contracts/interfaces/ERC20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import { ERC20Basic as HBOERC20Basic } from "./ERC20Basic.sol"; 5 | 6 | 7 | /** 8 | * @title ERC20 interface 9 | * @dev see https://github.com/ethereum/EIPs/issues/20 10 | */ 11 | contract ERC20 is HBOERC20Basic { 12 | function allowance(address owner, address spender) constant returns (uint256); 13 | function transferFrom(address from, address to, uint256 value) returns (bool); 14 | function approve(address spender, uint256 value) returns (bool); 15 | event Approval(address indexed owner, address indexed spender, uint256 value); 16 | } 17 | -------------------------------------------------------------------------------- /HBOToken/contracts/interfaces/ERC20Basic.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | /** 5 | * @title ERC20Basic 6 | * @dev Simpler version of ERC20 interface 7 | * @dev see https://github.com/ethereum/EIPs/issues/179 8 | */ 9 | contract ERC20Basic { 10 | uint256 public totalSupply; 11 | function balanceOf(address who) constant returns (uint256); 12 | function transfer(address to, uint256 value) returns (bool); 13 | event Transfer(address indexed from, address indexed to, uint256 value); 14 | } 15 | -------------------------------------------------------------------------------- /HBOToken/contracts/interfaces/ERC677.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | import { ERC20 as HBOERC20 } from "./ERC20.sol"; 4 | 5 | contract ERC677 is HBOERC20 { 6 | function transferAndCall(address to, uint value, bytes data) returns (bool success); 7 | 8 | event Transfer(address indexed from, address indexed to, uint value, bytes data); 9 | } 10 | -------------------------------------------------------------------------------- /HBOToken/contracts/interfaces/ERC677Receiver.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.8; 2 | 3 | 4 | contract ERC677Receiver { 5 | function onTokenTransfer(address _sender, uint _value, bytes _data); 6 | } 7 | -------------------------------------------------------------------------------- /HBOToken/contracts/vendor/BasicToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.24; 2 | 3 | 4 | import { ERC20Basic as HBOERC20Basic } from "../interfaces/ERC20Basic.sol"; 5 | import { SafeMathHBO as HBOSafeMath } from "./SafeMathHBO.sol"; 6 | 7 | 8 | /** 9 | * @title Basic token 10 | * @dev Basic version of StandardToken, with no allowances. 11 | */ 12 | contract BasicToken is HBOERC20Basic { 13 | using HBOSafeMath for uint256; 14 | 15 | mapping(address => uint256) balances; 16 | 17 | /** 18 | * @dev transfer token for a specified address 19 | * @param _to The address to transfer to. 20 | * @param _value The amount to be transferred. 21 | */ 22 | function transfer(address _to, uint256 _value) returns (bool) { 23 | balances[msg.sender] = balances[msg.sender].sub(_value); 24 | balances[_to] = balances[_to].add(_value); 25 | Transfer(msg.sender, _to, _value); 26 | return true; 27 | } 28 | 29 | /** 30 | * @dev Gets the balance of the specified address. 31 | * @param _owner The address to query the the balance of. 32 | * @return An uint256 representing the amount owned by the passed address. 33 | */ 34 | function balanceOf(address _owner) constant returns (uint256 balance) { 35 | return balances[_owner]; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /HBOToken/contracts/vendor/SafeMathHBO.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | /** 5 | * @title SafeMath 6 | * @dev Math operations with safety checks that throw on error 7 | */ 8 | library SafeMathHBO { 9 | 10 | /** 11 | * @dev Multiplies two numbers, throws on overflow. 12 | */ 13 | function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) { 14 | // Gas optimization: this is cheaper than asserting 'a' not being zero, but the 15 | // benefit is lost if 'b' is also tested. 16 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 17 | if (_a == 0) { 18 | return 0; 19 | } 20 | 21 | c = _a * _b; 22 | assert(c / _a == _b); 23 | return c; 24 | } 25 | 26 | /** 27 | * @dev Integer division of two numbers, truncating the quotient. 28 | */ 29 | function div(uint256 _a, uint256 _b) internal pure returns (uint256) { 30 | // assert(_b > 0); // Solidity automatically throws when dividing by 0 31 | // uint256 c = _a / _b; 32 | // assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold 33 | return _a / _b; 34 | } 35 | 36 | /** 37 | * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). 38 | */ 39 | function sub(uint256 _a, uint256 _b) internal pure returns (uint256) { 40 | assert(_b <= _a); 41 | return _a - _b; 42 | } 43 | 44 | /** 45 | * @dev Adds two numbers, throws on overflow. 46 | */ 47 | function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) { 48 | c = _a + _b; 49 | assert(c >= _a); 50 | return c; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /HBOToken/contracts/vendor/StandardToken.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.11; 2 | 3 | 4 | import { BasicToken as HBOBasicToken } from "./BasicToken.sol"; 5 | import { ERC20 as HBOERC20 } from "../interfaces/ERC20.sol"; 6 | 7 | 8 | /** 9 | * @title Standard ERC20 token 10 | * 11 | * @dev Implementation of the basic standard token. 12 | * @dev https://github.com/ethereum/EIPs/issues/20 13 | * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol 14 | */ 15 | contract StandardToken is HBOERC20, HBOBasicToken { 16 | 17 | mapping (address => mapping (address => uint256)) allowed; 18 | 19 | 20 | /** 21 | * @dev Transfer tokens from one address to another 22 | * @param _from address The address which you want to send tokens from 23 | * @param _to address The address which you want to transfer to 24 | * @param _value uint256 the amount of tokens to be transferred 25 | */ 26 | function transferFrom(address _from, address _to, uint256 _value) returns (bool) { 27 | var _allowance = allowed[_from][msg.sender]; 28 | 29 | // Check is not needed because sub(_allowance, _value) will already throw if this condition is not met 30 | // require (_value <= _allowance); 31 | 32 | balances[_from] = balances[_from].sub(_value); 33 | balances[_to] = balances[_to].add(_value); 34 | allowed[_from][msg.sender] = _allowance.sub(_value); 35 | Transfer(_from, _to, _value); 36 | return true; 37 | } 38 | 39 | /** 40 | * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. 41 | * @param _spender The address which will spend the funds. 42 | * @param _value The amount of tokens to be spent. 43 | */ 44 | function approve(address _spender, uint256 _value) returns (bool) { 45 | allowed[msg.sender][_spender] = _value; 46 | Approval(msg.sender, _spender, _value); 47 | return true; 48 | } 49 | 50 | /** 51 | * @dev Function to check the amount of tokens that an owner allowed to a spender. 52 | * @param _owner address The address which owns the funds. 53 | * @param _spender address The address which will spend the funds. 54 | * @return A uint256 specifying the amount of tokens still available for the spender. 55 | */ 56 | function allowance(address _owner, address _spender) constant returns (uint256 remaining) { 57 | return allowed[_owner][_spender]; 58 | } 59 | 60 | /* 61 | * approve should be called when allowed[_spender] == 0. To increment 62 | * allowed value is better to use this function to avoid 2 calls (and wait until 63 | * the first transaction is mined) 64 | * From MonolithDAO Token.sol 65 | */ 66 | function increaseApproval (address _spender, uint _addedValue) 67 | returns (bool success) { 68 | allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue); 69 | Approval(msg.sender, _spender, allowed[msg.sender][_spender]); 70 | return true; 71 | } 72 | 73 | function decreaseApproval (address _spender, uint _subtractedValue) 74 | returns (bool success) { 75 | uint oldValue = allowed[msg.sender][_spender]; 76 | if (_subtractedValue > oldValue) { 77 | allowed[msg.sender][_spender] = 0; 78 | } else { 79 | allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); 80 | } 81 | Approval(msg.sender, _spender, allowed[msg.sender][_spender]); 82 | return true; 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hboracle -------------------------------------------------------------------------------- /contracts/AccessControlledAggregator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | import "./FluxAggregator.sol"; 5 | import "./SimpleReadAccessController.sol"; 6 | 7 | /** 8 | * @title AccessControlled FluxAggregator contract 9 | * @notice This contract requires addresses to be added to a controller 10 | * in order to read the answers stored in the FluxAggregator contract 11 | */ 12 | contract AccessControlledAggregator is 13 | FluxAggregator, 14 | SimpleReadAccessController 15 | { 16 | /** 17 | * @notice set up the aggregator with initial configuration 18 | * @param _hbo The address of the HBO token 19 | * @param _paymentAmount The amount paid of HBO paid to each oracle per submission, in wei (units of 10⁻¹⁸ HBO) 20 | * @param _timeout is the number of seconds after the previous round that are 21 | * allowed to lapse before allowing an oracle to skip an unfinished round 22 | * @param _validator is an optional contract address for validating 23 | * external validation of answers 24 | * @param _minSubmissionValue is an immutable check for a lower bound of what 25 | * submission values are accepted from an oracle 26 | * @param _maxSubmissionValue is an immutable check for an upper bound of what 27 | * submission values are accepted from an oracle 28 | * @param _decimals represents the number of decimals to offset the answer by 29 | * @param _description a short description of what is being reported 30 | */ 31 | constructor( 32 | address _hbo, 33 | uint128 _paymentAmount, 34 | uint32 _timeout, 35 | address _validator, 36 | int256 _minSubmissionValue, 37 | int256 _maxSubmissionValue, 38 | uint8 _decimals, 39 | string memory _description 40 | ) 41 | public 42 | FluxAggregator( 43 | _hbo, 44 | _paymentAmount, 45 | _timeout, 46 | _validator, 47 | _minSubmissionValue, 48 | _maxSubmissionValue, 49 | _decimals, 50 | _description 51 | ) 52 | {} 53 | 54 | /** 55 | * @notice get data about a round. Consumers are encouraged to check 56 | * that they're receiving fresh data by inspecting the updatedAt and 57 | * answeredInRound return values. 58 | * @param _roundId the round ID to retrieve the round data for 59 | * @return roundId is the round ID for which data was retrieved 60 | * @return answer is the answer for the given round 61 | * @return startedAt is the timestamp when the round was started. This is 0 62 | * if the round hasn't been started yet. 63 | * @return updatedAt is the timestamp when the round last was updated (i.e. 64 | * answer was last computed) 65 | * @return answeredInRound is the round ID of the round in which the answer 66 | * was computed. answeredInRound may be smaller than roundId when the round 67 | * timed out. answerInRound is equal to roundId when the round didn't time out 68 | * and was completed regularly. 69 | * @dev overridden funcion to add the checkAccess() modifier 70 | * @dev Note that for in-progress rounds (i.e. rounds that haven't yet 71 | * received maxSubmissions) answer and updatedAt may change between queries. 72 | */ 73 | function getRoundData(uint80 _roundId) 74 | public 75 | view 76 | override 77 | checkAccess() 78 | returns ( 79 | uint80 roundId, 80 | int256 answer, 81 | uint256 startedAt, 82 | uint256 updatedAt, 83 | uint80 answeredInRound 84 | ) 85 | { 86 | return super.getRoundData(_roundId); 87 | } 88 | 89 | /** 90 | * @notice get data about the latest round. Consumers are encouraged to check 91 | * that they're receiving fresh data by inspecting the updatedAt and 92 | * answeredInRound return values. Consumers are encouraged to 93 | * use this more fully featured method over the "legacy" latestAnswer 94 | * functions. Consumers are encouraged to check that they're receiving fresh 95 | * data by inspecting the updatedAt and answeredInRound return values. 96 | * @return roundId is the round ID for which data was retrieved 97 | * @return answer is the answer for the given round 98 | * @return startedAt is the timestamp when the round was started. This is 0 99 | * if the round hasn't been started yet. 100 | * @return updatedAt is the timestamp when the round last was updated (i.e. 101 | * answer was last computed) 102 | * @return answeredInRound is the round ID of the round in which the answer 103 | * was computed. answeredInRound may be smaller than roundId when the round 104 | * timed out. answerInRound is equal to roundId when the round didn't time out 105 | * and was completed regularly. 106 | * @dev overridden funcion to add the checkAccess() modifier 107 | * @dev Note that for in-progress rounds (i.e. rounds that haven't yet 108 | * received maxSubmissions) answer and updatedAt may change between queries. 109 | */ 110 | function latestRoundData() 111 | public 112 | view 113 | override 114 | checkAccess() 115 | returns ( 116 | uint80 roundId, 117 | int256 answer, 118 | uint256 startedAt, 119 | uint256 updatedAt, 120 | uint80 answeredInRound 121 | ) 122 | { 123 | return super.latestRoundData(); 124 | } 125 | 126 | /** 127 | * @notice get the most recently reported answer 128 | * @dev overridden funcion to add the checkAccess() modifier 129 | * 130 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 131 | * answer has been reached, it will simply return 0. Either wait to point to 132 | * an already answered Aggregator or use the recommended latestRoundData 133 | * instead which includes better verification information. 134 | */ 135 | function latestAnswer() 136 | public 137 | view 138 | override 139 | checkAccess() 140 | returns (int256) 141 | { 142 | return super.latestAnswer(); 143 | } 144 | 145 | /** 146 | * @notice get the most recently reported round ID 147 | * @dev overridden funcion to add the checkAccess() modifier 148 | * 149 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 150 | * answer has been reached, it will simply return 0. Either wait to point to 151 | * an already answered Aggregator or use the recommended latestRoundData 152 | * instead which includes better verification information. 153 | */ 154 | function latestRound() 155 | public 156 | view 157 | override 158 | checkAccess() 159 | returns (uint256) 160 | { 161 | return super.latestRound(); 162 | } 163 | 164 | /** 165 | * @notice get the most recent updated at timestamp 166 | * @dev overridden funcion to add the checkAccess() modifier 167 | * 168 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 169 | * answer has been reached, it will simply return 0. Either wait to point to 170 | * an already answered Aggregator or use the recommended latestRoundData 171 | * instead which includes better verification information. 172 | */ 173 | function latestTimestamp() 174 | public 175 | view 176 | override 177 | checkAccess() 178 | returns (uint256) 179 | { 180 | return super.latestTimestamp(); 181 | } 182 | 183 | /** 184 | * @notice get past rounds answers 185 | * @dev overridden funcion to add the checkAccess() modifier 186 | * @param _roundId the round number to retrieve the answer for 187 | * 188 | * @dev #[deprecated] Use getRoundData instead. This does not error if no 189 | * answer has been reached, it will simply return 0. Either wait to point to 190 | * an already answered Aggregator or use the recommended getRoundData 191 | * instead which includes better verification information. 192 | */ 193 | function getAnswer(uint256 _roundId) 194 | public 195 | view 196 | override 197 | checkAccess() 198 | returns (int256) 199 | { 200 | return super.getAnswer(_roundId); 201 | } 202 | 203 | /** 204 | * @notice get timestamp when an answer was last updated 205 | * @dev overridden funcion to add the checkAccess() modifier 206 | * @param _roundId the round number to retrieve the updated timestamp for 207 | * 208 | * @dev #[deprecated] Use getRoundData instead. This does not error if no 209 | * answer has been reached, it will simply return 0. Either wait to point to 210 | * an already answered Aggregator or use the recommended getRoundData 211 | * instead which includes better verification information. 212 | */ 213 | function getTimestamp(uint256 _roundId) 214 | public 215 | view 216 | override 217 | checkAccess() 218 | returns (uint256) 219 | { 220 | return super.getTimestamp(_roundId); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /contracts/AggregatorFacade.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | import "./interfaces/AggregatorV2V3Interface.sol"; 5 | 6 | /** 7 | * @title A facade forAggregator versions to conform to the new v0.6 8 | * Aggregator V3 interface. 9 | */ 10 | contract AggregatorFacade is AggregatorV2V3Interface { 11 | AggregatorInterface public aggregator; 12 | uint8 public override decimals; 13 | string public override description; 14 | 15 | uint256 public constant override version = 2; 16 | 17 | // An error specific to the Aggregator V3 Interface, to prevent possible 18 | // confusion around accidentally reading unset values as reported values. 19 | string private constant V3_NO_DATA_ERROR = "No data present"; 20 | 21 | constructor( 22 | address _aggregator, 23 | uint8 _decimals, 24 | string memory _description 25 | ) public { 26 | aggregator = AggregatorInterface(_aggregator); 27 | decimals = _decimals; 28 | description = _description; 29 | } 30 | 31 | /** 32 | * @notice get the latest completed round where the answer was updated 33 | * @dev #[deprecated]. Use latestRoundData instead. This does not error if no 34 | * answer has been reached, it will simply return 0. Either wait to point to 35 | * an already answered Aggregator or use the recommended latestRoundData 36 | * instead which includes better verification information. 37 | */ 38 | function latestRound() external view virtual override returns (uint256) { 39 | return aggregator.latestRound(); 40 | } 41 | 42 | /** 43 | * @notice Reads the current answer from aggregator delegated to. 44 | * 45 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 46 | * answer has been reached, it will simply return 0. Either wait to point to 47 | * an already answered Aggregator or use the recommended latestRoundData 48 | * instead which includes better verification information. 49 | */ 50 | function latestAnswer() external view virtual override returns (int256) { 51 | return aggregator.latestAnswer(); 52 | } 53 | 54 | /** 55 | * @notice Reads the last updated height from aggregator delegated to. 56 | * 57 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 58 | * answer has been reached, it will simply return 0. Either wait to point to 59 | * an already answered Aggregator or use the recommended latestRoundData 60 | * instead which includes better verification information. 61 | */ 62 | function latestTimestamp() 63 | external 64 | view 65 | virtual 66 | override 67 | returns (uint256) 68 | { 69 | return aggregator.latestTimestamp(); 70 | } 71 | 72 | /** 73 | * @notice get data about the latest round. Consumers are encouraged to check 74 | * that they're receiving fresh data by inspecting the updatedAt value. 75 | * @return roundId is the round ID for which data was retrieved 76 | * @return answer is the answer for the given round 77 | * @return startedAt is always equal to updatedAt because the underlying 78 | * Aggregator contract does not expose this information. 79 | * @return updatedAt is the timestamp when the round last was updated (i.e. 80 | * answer was last computed) 81 | * @return answeredInRound is always equal to roundId because the underlying 82 | * Aggregator contract does not expose this information. 83 | * @dev Note that for rounds that haven't yet received responses from all 84 | * oracles, answer and updatedAt may change between queries. 85 | */ 86 | function latestRoundData() 87 | external 88 | view 89 | virtual 90 | override 91 | returns ( 92 | uint80 roundId, 93 | int256 answer, 94 | uint256 startedAt, 95 | uint256 updatedAt, 96 | uint80 answeredInRound 97 | ) 98 | { 99 | return _getRoundData(uint80(aggregator.latestRound())); 100 | } 101 | 102 | /** 103 | * @notice get past rounds answers 104 | * @param _roundId the answer number to retrieve the answer for 105 | * 106 | * @dev #[deprecated] Use getRoundData instead. This does not error if no 107 | * answer has been reached, it will simply return 0. Either wait to point to 108 | * an already answered Aggregator or use the recommended getRoundData 109 | * instead which includes better verification information. 110 | */ 111 | function getAnswer(uint256 _roundId) 112 | external 113 | view 114 | virtual 115 | override 116 | returns (int256) 117 | { 118 | return aggregator.getAnswer(_roundId); 119 | } 120 | 121 | /** 122 | * @notice get block timestamp when an answer was last updated 123 | * @param _roundId the answer number to retrieve the updated timestamp for 124 | * 125 | * @dev #[deprecated] Use getRoundData instead. This does not error if no 126 | * answer has been reached, it will simply return 0. Either wait to point to 127 | * an already answered Aggregator or use the recommended getRoundData 128 | * instead which includes better verification information. 129 | */ 130 | function getTimestamp(uint256 _roundId) 131 | external 132 | view 133 | virtual 134 | override 135 | returns (uint256) 136 | { 137 | return aggregator.getTimestamp(_roundId); 138 | } 139 | 140 | /** 141 | * @notice get data about a round. Consumers are encouraged to check 142 | * that they're receiving fresh data by inspecting the updatedAt value. 143 | * @param _roundId the round ID to retrieve the round data for 144 | * @return roundId is the round ID for which data was retrieved 145 | * @return answer is the answer for the given round 146 | * @return startedAt is always equal to updatedAt because the underlying 147 | * Aggregator contract does not expose this information. 148 | * @return updatedAt is the timestamp when the round last was updated (i.e. 149 | * answer was last computed) 150 | * @return answeredInRound is always equal to roundId because the underlying 151 | * Aggregator contract does not expose this information. 152 | * @dev Note that for rounds that haven't yet received responses from all 153 | * oracles, answer and updatedAt may change between queries. 154 | */ 155 | function getRoundData(uint80 _roundId) 156 | external 157 | view 158 | virtual 159 | override 160 | returns ( 161 | uint80 roundId, 162 | int256 answer, 163 | uint256 startedAt, 164 | uint256 updatedAt, 165 | uint80 answeredInRound 166 | ) 167 | { 168 | return _getRoundData(_roundId); 169 | } 170 | 171 | /* 172 | * Internal 173 | */ 174 | 175 | function _getRoundData(uint80 _roundId) 176 | internal 177 | view 178 | returns ( 179 | uint80 roundId, 180 | int256 answer, 181 | uint256 startedAt, 182 | uint256 updatedAt, 183 | uint80 answeredInRound 184 | ) 185 | { 186 | answer = aggregator.getAnswer(_roundId); 187 | updatedAt = uint64(aggregator.getTimestamp(_roundId)); 188 | 189 | require(updatedAt > 0, V3_NO_DATA_ERROR); 190 | 191 | return (_roundId, answer, updatedAt, updatedAt, _roundId); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /contracts/AggregatorProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | import "./Owned.sol"; 5 | import "./interfaces/AggregatorV2V3Interface.sol"; 6 | 7 | /** 8 | * @title A trusted proxy for updating where current answers are read from 9 | * @notice This contract provides a consistent address for the 10 | * CurrentAnwerInterface but delegates where it reads from to the owner, who is 11 | * trusted to update it. 12 | */ 13 | contract AggregatorProxy is AggregatorV2V3Interface, Owned { 14 | struct Phase { 15 | uint16 id; 16 | AggregatorV2V3Interface aggregator; 17 | } 18 | Phase private currentPhase; 19 | AggregatorV2V3Interface public proposedAggregator; 20 | mapping(uint16 => AggregatorV2V3Interface) public phaseAggregators; 21 | 22 | uint256 private constant PHASE_OFFSET = 64; 23 | uint256 private constant PHASE_SIZE = 16; 24 | uint256 private constant MAX_ID = 2**(PHASE_OFFSET + PHASE_SIZE) - 1; 25 | 26 | constructor(address _aggregator) public Owned() { 27 | setAggregator(_aggregator); 28 | } 29 | 30 | /** 31 | * @notice Reads the current answer from aggregator delegated to. 32 | * 33 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 34 | * answer has been reached, it will simply return 0. Either wait to point to 35 | * an already answered Aggregator or use the recommended latestRoundData 36 | * instead which includes better verification information. 37 | */ 38 | function latestAnswer() 39 | public 40 | view 41 | virtual 42 | override 43 | returns (int256 answer) 44 | { 45 | return currentPhase.aggregator.latestAnswer(); 46 | } 47 | 48 | /** 49 | * @notice Reads the last updated height from aggregator delegated to. 50 | * 51 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 52 | * answer has been reached, it will simply return 0. Either wait to point to 53 | * an already answered Aggregator or use the recommended latestRoundData 54 | * instead which includes better verification information. 55 | */ 56 | function latestTimestamp() 57 | public 58 | view 59 | virtual 60 | override 61 | returns (uint256 updatedAt) 62 | { 63 | return currentPhase.aggregator.latestTimestamp(); 64 | } 65 | 66 | /** 67 | * @notice get past rounds answers 68 | * @param _roundId the answer number to retrieve the answer for 69 | * 70 | * @dev #[deprecated] Use getRoundData instead. This does not error if no 71 | * answer has been reached, it will simply return 0. Either wait to point to 72 | * an already answered Aggregator or use the recommended getRoundData 73 | * instead which includes better verification information. 74 | */ 75 | function getAnswer(uint256 _roundId) 76 | public 77 | view 78 | virtual 79 | override 80 | returns (int256 answer) 81 | { 82 | if (_roundId > MAX_ID) return 0; 83 | 84 | (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); 85 | AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; 86 | if (address(aggregator) == address(0)) return 0; 87 | 88 | return aggregator.getAnswer(aggregatorRoundId); 89 | } 90 | 91 | /** 92 | * @notice get block timestamp when an answer was last updated 93 | * @param _roundId the answer number to retrieve the updated timestamp for 94 | * 95 | * @dev #[deprecated] Use getRoundData instead. This does not error if no 96 | * answer has been reached, it will simply return 0. Either wait to point to 97 | * an already answered Aggregator or use the recommended getRoundData 98 | * instead which includes better verification information. 99 | */ 100 | function getTimestamp(uint256 _roundId) 101 | public 102 | view 103 | virtual 104 | override 105 | returns (uint256 updatedAt) 106 | { 107 | if (_roundId > MAX_ID) return 0; 108 | 109 | (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); 110 | AggregatorV2V3Interface aggregator = phaseAggregators[phaseId]; 111 | if (address(aggregator) == address(0)) return 0; 112 | 113 | return aggregator.getTimestamp(aggregatorRoundId); 114 | } 115 | 116 | /** 117 | * @notice get the latest completed round where the answer was updated. This 118 | * ID includes the proxy's phase, to make sure round IDs increase even when 119 | * switching to a newly deployed aggregator. 120 | * 121 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 122 | * answer has been reached, it will simply return 0. Either wait to point to 123 | * an already answered Aggregator or use the recommended latestRoundData 124 | * instead which includes better verification information. 125 | */ 126 | function latestRound() 127 | public 128 | view 129 | virtual 130 | override 131 | returns (uint256 roundId) 132 | { 133 | Phase memory phase = currentPhase; // cache storage reads 134 | return addPhase(phase.id, uint64(phase.aggregator.latestRound())); 135 | } 136 | 137 | /** 138 | * @notice get data about a round. Consumers are encouraged to check 139 | * that they're receiving fresh data by inspecting the updatedAt and 140 | * answeredInRound return values. 141 | * Note that different underlying implementations of AggregatorV3Interface 142 | * have slightly different semantics for some of the return values. Consumers 143 | * should determine what implementations they expect to receive 144 | * data from and validate that they can properly handle return data from all 145 | * of them. 146 | * @param _roundId the requested round ID as presented through the proxy, this 147 | * is made up of the aggregator's round ID with the phase ID encoded in the 148 | * two highest order bytes 149 | * @return roundId is the round ID from the aggregator for which the data was 150 | * retrieved combined with an phase to ensure that round IDs get larger as 151 | * time moves forward. 152 | * @return answer is the answer for the given round 153 | * @return startedAt is the timestamp when the round was started. 154 | * (Only some AggregatorV3Interface implementations return meaningful values) 155 | * @return updatedAt is the timestamp when the round last was updated (i.e. 156 | * answer was last computed) 157 | * @return answeredInRound is the round ID of the round in which the answer 158 | * was computed. 159 | * (Only some AggregatorV3Interface implementations return meaningful values) 160 | * @dev Note that answer and updatedAt may change between queries. 161 | */ 162 | function getRoundData(uint80 _roundId) 163 | public 164 | view 165 | virtual 166 | override 167 | returns ( 168 | uint80 roundId, 169 | int256 answer, 170 | uint256 startedAt, 171 | uint256 updatedAt, 172 | uint80 answeredInRound 173 | ) 174 | { 175 | (uint16 phaseId, uint64 aggregatorRoundId) = parseIds(_roundId); 176 | 177 | ( 178 | roundId, 179 | answer, 180 | startedAt, 181 | updatedAt, 182 | answeredInRound 183 | ) = phaseAggregators[phaseId].getRoundData(aggregatorRoundId); 184 | 185 | return 186 | addPhaseIds( 187 | roundId, 188 | answer, 189 | startedAt, 190 | updatedAt, 191 | answeredInRound, 192 | phaseId 193 | ); 194 | } 195 | 196 | /** 197 | * @notice get data about the latest round. Consumers are encouraged to check 198 | * that they're receiving fresh data by inspecting the updatedAt and 199 | * answeredInRound return values. 200 | * Note that different underlying implementations of AggregatorV3Interface 201 | * have slightly different semantics for some of the return values. Consumers 202 | * should determine what implementations they expect to receive 203 | * data from and validate that they can properly handle return data from all 204 | * of them. 205 | * @return roundId is the round ID from the aggregator for which the data was 206 | * retrieved combined with an phase to ensure that round IDs get larger as 207 | * time moves forward. 208 | * @return answer is the answer for the given round 209 | * @return startedAt is the timestamp when the round was started. 210 | * (Only some AggregatorV3Interface implementations return meaningful values) 211 | * @return updatedAt is the timestamp when the round last was updated (i.e. 212 | * answer was last computed) 213 | * @return answeredInRound is the round ID of the round in which the answer 214 | * was computed. 215 | * (Only some AggregatorV3Interface implementations return meaningful values) 216 | * @dev Note that answer and updatedAt may change between queries. 217 | */ 218 | function latestRoundData() 219 | public 220 | view 221 | virtual 222 | override 223 | returns ( 224 | uint80 roundId, 225 | int256 answer, 226 | uint256 startedAt, 227 | uint256 updatedAt, 228 | uint80 answeredInRound 229 | ) 230 | { 231 | Phase memory current = currentPhase; // cache storage reads 232 | 233 | (roundId, answer, startedAt, updatedAt, answeredInRound) = current 234 | .aggregator 235 | .latestRoundData(); 236 | 237 | return 238 | addPhaseIds( 239 | roundId, 240 | answer, 241 | startedAt, 242 | updatedAt, 243 | answeredInRound, 244 | current.id 245 | ); 246 | } 247 | 248 | /** 249 | * @notice Used if an aggregator contract has been proposed. 250 | * @param _roundId the round ID to retrieve the round data for 251 | * @return roundId is the round ID for which data was retrieved 252 | * @return answer is the answer for the given round 253 | * @return startedAt is the timestamp when the round was started. 254 | * (Only some AggregatorV3Interface implementations return meaningful values) 255 | * @return updatedAt is the timestamp when the round last was updated (i.e. 256 | * answer was last computed) 257 | * @return answeredInRound is the round ID of the round in which the answer 258 | * was computed. 259 | */ 260 | function proposedGetRoundData(uint80 _roundId) 261 | public 262 | view 263 | virtual 264 | hasProposal() 265 | returns ( 266 | uint80 roundId, 267 | int256 answer, 268 | uint256 startedAt, 269 | uint256 updatedAt, 270 | uint80 answeredInRound 271 | ) 272 | { 273 | return proposedAggregator.getRoundData(_roundId); 274 | } 275 | 276 | /** 277 | * @notice Used if an aggregator contract has been proposed. 278 | * @return roundId is the round ID for which data was retrieved 279 | * @return answer is the answer for the given round 280 | * @return startedAt is the timestamp when the round was started. 281 | * (Only some AggregatorV3Interface implementations return meaningful values) 282 | * @return updatedAt is the timestamp when the round last was updated (i.e. 283 | * answer was last computed) 284 | * @return answeredInRound is the round ID of the round in which the answer 285 | * was computed. 286 | */ 287 | function proposedLatestRoundData() 288 | public 289 | view 290 | virtual 291 | hasProposal() 292 | returns ( 293 | uint80 roundId, 294 | int256 answer, 295 | uint256 startedAt, 296 | uint256 updatedAt, 297 | uint80 answeredInRound 298 | ) 299 | { 300 | return proposedAggregator.latestRoundData(); 301 | } 302 | 303 | /** 304 | * @notice returns the current phase's aggregator address. 305 | */ 306 | function aggregator() external view returns (address) { 307 | return address(currentPhase.aggregator); 308 | } 309 | 310 | /** 311 | * @notice returns the current phase's ID. 312 | */ 313 | function phaseId() external view returns (uint16) { 314 | return currentPhase.id; 315 | } 316 | 317 | /** 318 | * @notice represents the number of decimals the aggregator responses represent. 319 | */ 320 | function decimals() external view override returns (uint8) { 321 | return currentPhase.aggregator.decimals(); 322 | } 323 | 324 | /** 325 | * @notice the version number representing the type of aggregator the proxy 326 | * points to. 327 | */ 328 | function version() external view override returns (uint256) { 329 | return currentPhase.aggregator.version(); 330 | } 331 | 332 | /** 333 | * @notice returns the description of the aggregator the proxy points to. 334 | */ 335 | function description() external view override returns (string memory) { 336 | return currentPhase.aggregator.description(); 337 | } 338 | 339 | /** 340 | * @notice Allows the owner to propose a new address for the aggregator 341 | * @param _aggregator The new address for the aggregator contract 342 | */ 343 | function proposeAggregator(address _aggregator) external onlyOwner() { 344 | proposedAggregator = AggregatorV2V3Interface(_aggregator); 345 | } 346 | 347 | /** 348 | * @notice Allows the owner to confirm and change the address 349 | * to the proposed aggregator 350 | * @dev Reverts if the given address doesn't match what was previously 351 | * proposed 352 | * @param _aggregator The new address for the aggregator contract 353 | */ 354 | function confirmAggregator(address _aggregator) external onlyOwner() { 355 | require( 356 | _aggregator == address(proposedAggregator), 357 | "Invalid proposed aggregator" 358 | ); 359 | delete proposedAggregator; 360 | setAggregator(_aggregator); 361 | } 362 | 363 | /* 364 | * Internal 365 | */ 366 | 367 | function setAggregator(address _aggregator) internal { 368 | uint16 id = currentPhase.id + 1; 369 | currentPhase = Phase(id, AggregatorV2V3Interface(_aggregator)); 370 | phaseAggregators[id] = AggregatorV2V3Interface(_aggregator); 371 | } 372 | 373 | function addPhase(uint16 _phase, uint64 _originalId) 374 | internal 375 | pure 376 | returns (uint80) 377 | { 378 | return uint80((uint256(_phase) << PHASE_OFFSET) | _originalId); 379 | } 380 | 381 | function parseIds(uint256 _roundId) internal pure returns (uint16, uint64) { 382 | uint16 phaseId = uint16(_roundId >> PHASE_OFFSET); 383 | uint64 aggregatorRoundId = uint64(_roundId); 384 | 385 | return (phaseId, aggregatorRoundId); 386 | } 387 | 388 | function addPhaseIds( 389 | uint80 roundId, 390 | int256 answer, 391 | uint256 startedAt, 392 | uint256 updatedAt, 393 | uint80 answeredInRound, 394 | uint16 phaseId 395 | ) 396 | internal 397 | pure 398 | returns ( 399 | uint80, 400 | int256, 401 | uint256, 402 | uint256, 403 | uint80 404 | ) 405 | { 406 | return ( 407 | addPhase(phaseId, uint64(roundId)), 408 | answer, 409 | startedAt, 410 | updatedAt, 411 | addPhase(phaseId, uint64(answeredInRound)) 412 | ); 413 | } 414 | 415 | /* 416 | * Modifiers 417 | */ 418 | 419 | modifier hasProposal() { 420 | require( 421 | address(proposedAggregator) != address(0), 422 | "No proposed aggregator present" 423 | ); 424 | _; 425 | } 426 | } 427 | -------------------------------------------------------------------------------- /contracts/CheckedMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | // Adapted from https://github.com/OpenZeppelin/openzeppelin-contracts/blob/97894a140d2a698e5a0f913648a8f56d62277a70/contracts/math/SignedSafeMath.sol 3 | 4 | pragma solidity ^0.6.0; 5 | 6 | library CheckedMath { 7 | int256 internal constant INT256_MIN = -2**255; 8 | 9 | /** 10 | * @dev Subtracts two signed integers, returns false 2nd param on overflow. 11 | */ 12 | function add(int256 a, int256 b) 13 | internal 14 | pure 15 | returns (int256 result, bool ok) 16 | { 17 | int256 c = a + b; 18 | if ((b >= 0 && c < a) || (b < 0 && c >= a)) return (0, false); 19 | 20 | return (c, true); 21 | } 22 | 23 | /** 24 | * @dev Subtracts two signed integers, returns false 2nd param on overflow. 25 | */ 26 | function sub(int256 a, int256 b) 27 | internal 28 | pure 29 | returns (int256 result, bool ok) 30 | { 31 | int256 c = a - b; 32 | if ((b < 0 && c <= a) || (b >= 0 && c > a)) return (0, false); 33 | 34 | return (c, true); 35 | } 36 | 37 | /** 38 | * @dev Multiplies two signed integers, returns false 2nd param on overflow. 39 | */ 40 | function mul(int256 a, int256 b) 41 | internal 42 | pure 43 | returns (int256 result, bool ok) 44 | { 45 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 46 | // benefit is lost if 'b' is also tested. 47 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 48 | if (a == 0) return (0, true); 49 | if (a == -1 && b == INT256_MIN) return (0, false); 50 | 51 | int256 c = a * b; 52 | if (!(c / a == b)) return (0, false); 53 | 54 | return (c, true); 55 | } 56 | 57 | /** 58 | * @dev Divides two signed integers, returns false 2nd param on overflow. 59 | */ 60 | function div(int256 a, int256 b) 61 | internal 62 | pure 63 | returns (int256 result, bool ok) 64 | { 65 | if (b == 0) return (0, false); 66 | if (b == -1 && a == INT256_MIN) return (0, false); 67 | 68 | int256 c = a / b; 69 | 70 | return (c, true); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /contracts/DeviationFlaggingValidator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | import "./Owned.sol"; 5 | import "./CheckedMath.sol"; 6 | import "./interfaces/AggregatorValidatorInterface.sol"; 7 | import "./interfaces/FlagsInterface.sol"; 8 | 9 | /** 10 | * @title The Deviation Flagging Validator contract 11 | * @notice Checks the current value against the previous value, and makes sure 12 | * that it does not deviate outside of some relative range. If the deviation 13 | * threshold is passed then the validator raises a flag on the designated 14 | * flag contract. 15 | */ 16 | contract DeviationFlaggingValidator is Owned, AggregatorValidatorInterface { 17 | using CheckedMath for int256; 18 | 19 | uint32 public constant THRESHOLD_MULTIPLIER = 100000; 20 | 21 | uint32 public flaggingThreshold; 22 | FlagsInterface public flags; 23 | 24 | event FlaggingThresholdUpdated( 25 | uint24 indexed previous, 26 | uint24 indexed current 27 | ); 28 | event FlagsAddressUpdated( 29 | address indexed previous, 30 | address indexed current 31 | ); 32 | 33 | int256 private constant INT256_MIN = -2**255; 34 | 35 | /** 36 | * @notice sets up the validator with its threshold and flag address. 37 | * @param _flags sets the address of the flags contract 38 | * @param _flaggingThreshold sets the threshold that will trigger a flag to be 39 | * raised. Setting the value of 100,000 is equivalent to tolerating a 100% 40 | * change compared to the previous price. 41 | */ 42 | constructor(address _flags, uint24 _flaggingThreshold) public { 43 | setFlagsAddress(_flags); 44 | setFlaggingThreshold(_flaggingThreshold); 45 | } 46 | 47 | /** 48 | * @notice checks whether the parameters count as valid by comparing the 49 | * difference change to the flagging threshold. 50 | * @param _previousRoundId is ignored. 51 | * @param _previousAnswer is used as the median of the difference with the 52 | * current answer to determine if the deviation threshold has been exceeded. 53 | * @param _roundId is ignored. 54 | * @param _answer is the latest answer which is compared for a ratio of change 55 | * to make sure it has not execeeded the flagging threshold. 56 | */ 57 | function validate( 58 | uint256 _previousRoundId, 59 | int256 _previousAnswer, 60 | uint256 _roundId, 61 | int256 _answer 62 | ) external override returns (bool) { 63 | if (!isValid(_previousRoundId, _previousAnswer, _roundId, _answer)) { 64 | flags.raiseFlag(msg.sender); 65 | return false; 66 | } 67 | 68 | return true; 69 | } 70 | 71 | /** 72 | * @notice checks whether the parameters count as valid by comparing the 73 | * difference change to the flagging threshold and raises a flag on the 74 | * flagging contract if so. 75 | * @param _previousAnswer is used as the median of the difference with the 76 | * current answer to determine if the deviation threshold has been exceeded. 77 | * @param _answer is the current answer which is compared for a ratio of 78 | * change * to make sure it has not execeeded the flagging threshold. 79 | */ 80 | function isValid( 81 | uint256, 82 | int256 _previousAnswer, 83 | uint256, 84 | int256 _answer 85 | ) public view returns (bool) { 86 | if (_previousAnswer == 0) return true; 87 | 88 | (int256 change, bool changeOk) = _previousAnswer.sub(_answer); 89 | (int256 ratioNumerator, bool numOk) = change.mul(THRESHOLD_MULTIPLIER); 90 | (int256 ratio, bool ratioOk) = ratioNumerator.div(_previousAnswer); 91 | (uint256 absRatio, bool absOk) = abs(ratio); 92 | 93 | return 94 | changeOk && 95 | numOk && 96 | ratioOk && 97 | absOk && 98 | absRatio <= flaggingThreshold; 99 | } 100 | 101 | /** 102 | * @notice updates the flagging threshold 103 | * @param _flaggingThreshold sets the threshold that will trigger a flag to be 104 | * raised. Setting the value of 100,000 is equivalent to tolerating a 100% 105 | * change compared to the previous price. 106 | */ 107 | function setFlaggingThreshold(uint24 _flaggingThreshold) 108 | public 109 | onlyOwner() 110 | { 111 | uint24 previousFT = uint24(flaggingThreshold); 112 | 113 | if (previousFT != _flaggingThreshold) { 114 | flaggingThreshold = _flaggingThreshold; 115 | 116 | emit FlaggingThresholdUpdated(previousFT, _flaggingThreshold); 117 | } 118 | } 119 | 120 | /** 121 | * @notice updates the flagging contract address for raising flags 122 | * @param _flags sets the address of the flags contract 123 | */ 124 | function setFlagsAddress(address _flags) public onlyOwner() { 125 | address previous = address(flags); 126 | 127 | if (previous != _flags) { 128 | flags = FlagsInterface(_flags); 129 | 130 | emit FlagsAddressUpdated(previous, _flags); 131 | } 132 | } 133 | 134 | // PRIVATE 135 | 136 | function abs(int256 value) private pure returns (uint256, bool) { 137 | if (value >= 0) return (uint256(value), true); 138 | if (value == CheckedMath.INT256_MIN) return (0, false); 139 | return (uint256(value * -1), true); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /contracts/EACAggregatorProxy.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | import "./AggregatorProxy.sol"; 5 | import "./interfaces/AccessControllerInterface.sol"; 6 | 7 | /** 8 | * @title External Access Controlled Aggregator Proxy 9 | * @notice A trusted proxy for updating where current answers are read from 10 | * @notice This contract provides a consistent address for the 11 | * Aggregator and AggregatorV3Interface but delegates where it reads from to the owner, who is 12 | * trusted to update it. 13 | * @notice Only access enabled addresses are allowed to access getters for 14 | * aggregated answers and round information. 15 | */ 16 | contract EACAggregatorProxy is AggregatorProxy { 17 | AccessControllerInterface public accessController; 18 | 19 | constructor(address _aggregator, address _accessController) 20 | public 21 | AggregatorProxy(_aggregator) 22 | { 23 | setController(_accessController); 24 | } 25 | 26 | /** 27 | * @notice Allows the owner to update the accessController contract address. 28 | * @param _accessController The new address for the accessController contract 29 | */ 30 | function setController(address _accessController) public onlyOwner() { 31 | accessController = AccessControllerInterface(_accessController); 32 | } 33 | 34 | /** 35 | * @notice Reads the current answer from aggregator delegated to. 36 | * @dev overridden function to add the checkAccess() modifier 37 | * 38 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 39 | * answer has been reached, it will simply return 0. Either wait to point to 40 | * an already answered Aggregator or use the recommended latestRoundData 41 | * instead which includes better verification information. 42 | */ 43 | function latestAnswer() 44 | public 45 | view 46 | override 47 | checkAccess() 48 | returns (int256) 49 | { 50 | return super.latestAnswer(); 51 | } 52 | 53 | /** 54 | * @notice get the latest completed round where the answer was updated. This 55 | * ID includes the proxy's phase, to make sure round IDs increase even when 56 | * switching to a newly deployed aggregator. 57 | * 58 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 59 | * answer has been reached, it will simply return 0. Either wait to point to 60 | * an already answered Aggregator or use the recommended latestRoundData 61 | * instead which includes better verification information. 62 | */ 63 | function latestTimestamp() 64 | public 65 | view 66 | override 67 | checkAccess() 68 | returns (uint256) 69 | { 70 | return super.latestTimestamp(); 71 | } 72 | 73 | /** 74 | * @notice get past rounds answers 75 | * @param _roundId the answer number to retrieve the answer for 76 | * @dev overridden function to add the checkAccess() modifier 77 | * 78 | * @dev #[deprecated] Use getRoundData instead. This does not error if no 79 | * answer has been reached, it will simply return 0. Either wait to point to 80 | * an already answered Aggregator or use the recommended getRoundData 81 | * instead which includes better verification information. 82 | */ 83 | function getAnswer(uint256 _roundId) 84 | public 85 | view 86 | override 87 | checkAccess() 88 | returns (int256) 89 | { 90 | return super.getAnswer(_roundId); 91 | } 92 | 93 | /** 94 | * @notice get block timestamp when an answer was last updated 95 | * @param _roundId the answer number to retrieve the updated timestamp for 96 | * @dev overridden function to add the checkAccess() modifier 97 | * 98 | * @dev #[deprecated] Use getRoundData instead. This does not error if no 99 | * answer has been reached, it will simply return 0. Either wait to point to 100 | * an already answered Aggregator or use the recommended getRoundData 101 | * instead which includes better verification information. 102 | */ 103 | function getTimestamp(uint256 _roundId) 104 | public 105 | view 106 | override 107 | checkAccess() 108 | returns (uint256) 109 | { 110 | return super.getTimestamp(_roundId); 111 | } 112 | 113 | /** 114 | * @notice get the latest completed round where the answer was updated 115 | * @dev overridden function to add the checkAccess() modifier 116 | * 117 | * @dev #[deprecated] Use latestRoundData instead. This does not error if no 118 | * answer has been reached, it will simply return 0. Either wait to point to 119 | * an already answered Aggregator or use the recommended latestRoundData 120 | * instead which includes better verification information. 121 | */ 122 | function latestRound() 123 | public 124 | view 125 | override 126 | checkAccess() 127 | returns (uint256) 128 | { 129 | return super.latestRound(); 130 | } 131 | 132 | /** 133 | * @notice get data about a round. Consumers are encouraged to check 134 | * that they're receiving fresh data by inspecting the updatedAt and 135 | * answeredInRound return values. 136 | * Note that different underlying implementations of AggregatorV3Interface 137 | * have slightly different semantics for some of the return values. Consumers 138 | * should determine what implementations they expect to receive 139 | * data from and validate that they can properly handle return data from all 140 | * of them. 141 | * @param _roundId the round ID to retrieve the round data for 142 | * @return roundId is the round ID from the aggregator for which the data was 143 | * retrieved combined with a phase to ensure that round IDs get larger as 144 | * time moves forward. 145 | * @return answer is the answer for the given round 146 | * @return startedAt is the timestamp when the round was started. 147 | * (Only some AggregatorV3Interface implementations return meaningful values) 148 | * @return updatedAt is the timestamp when the round last was updated (i.e. 149 | * answer was last computed) 150 | * @return answeredInRound is the round ID of the round in which the answer 151 | * was computed. 152 | * (Only some AggregatorV3Interface implementations return meaningful values) 153 | * @dev Note that answer and updatedAt may change between queries. 154 | */ 155 | function getRoundData(uint80 _roundId) 156 | public 157 | view 158 | override 159 | checkAccess() 160 | returns ( 161 | uint80 roundId, 162 | int256 answer, 163 | uint256 startedAt, 164 | uint256 updatedAt, 165 | uint80 answeredInRound 166 | ) 167 | { 168 | return super.getRoundData(_roundId); 169 | } 170 | 171 | /** 172 | * @notice get data about the latest round. Consumers are encouraged to check 173 | * that they're receiving fresh data by inspecting the updatedAt and 174 | * answeredInRound return values. 175 | * Note that different underlying implementations of AggregatorV3Interface 176 | * have slightly different semantics for some of the return values. Consumers 177 | * should determine what implementations they expect to receive 178 | * data from and validate that they can properly handle return data from all 179 | * of them. 180 | * @return roundId is the round ID from the aggregator for which the data was 181 | * retrieved combined with a phase to ensure that round IDs get larger as 182 | * time moves forward. 183 | * @return answer is the answer for the given round 184 | * @return startedAt is the timestamp when the round was started. 185 | * (Only some AggregatorV3Interface implementations return meaningful values) 186 | * @return updatedAt is the timestamp when the round last was updated (i.e. 187 | * answer was last computed) 188 | * @return answeredInRound is the round ID of the round in which the answer 189 | * was computed. 190 | * (Only some AggregatorV3Interface implementations return meaningful values) 191 | * @dev Note that answer and updatedAt may change between queries. 192 | */ 193 | function latestRoundData() 194 | public 195 | view 196 | override 197 | checkAccess() 198 | returns ( 199 | uint80 roundId, 200 | int256 answer, 201 | uint256 startedAt, 202 | uint256 updatedAt, 203 | uint80 answeredInRound 204 | ) 205 | { 206 | return super.latestRoundData(); 207 | } 208 | 209 | /** 210 | * @notice Used if an aggregator contract has been proposed. 211 | * @param _roundId the round ID to retrieve the round data for 212 | * @return roundId is the round ID for which data was retrieved 213 | * @return answer is the answer for the given round 214 | * @return startedAt is the timestamp when the round was started. 215 | * (Only some AggregatorV3Interface implementations return meaningful values) 216 | * @return updatedAt is the timestamp when the round last was updated (i.e. 217 | * answer was last computed) 218 | * @return answeredInRound is the round ID of the round in which the answer 219 | * was computed. 220 | */ 221 | function proposedGetRoundData(uint80 _roundId) 222 | public 223 | view 224 | override 225 | checkAccess() 226 | hasProposal() 227 | returns ( 228 | uint80 roundId, 229 | int256 answer, 230 | uint256 startedAt, 231 | uint256 updatedAt, 232 | uint80 answeredInRound 233 | ) 234 | { 235 | return super.proposedGetRoundData(_roundId); 236 | } 237 | 238 | /** 239 | * @notice Used if an aggregator contract has been proposed. 240 | * @return roundId is the round ID for which data was retrieved 241 | * @return answer is the answer for the given round 242 | * @return startedAt is the timestamp when the round was started. 243 | * (Only some AggregatorV3Interface implementations return meaningful values) 244 | * @return updatedAt is the timestamp when the round last was updated (i.e. 245 | * answer was last computed) 246 | * @return answeredInRound is the round ID of the round in which the answer 247 | * was computed. 248 | */ 249 | function proposedLatestRoundData() 250 | public 251 | view 252 | override 253 | checkAccess() 254 | hasProposal() 255 | returns ( 256 | uint80 roundId, 257 | int256 answer, 258 | uint256 startedAt, 259 | uint256 updatedAt, 260 | uint80 answeredInRound 261 | ) 262 | { 263 | return super.proposedLatestRoundData(); 264 | } 265 | 266 | /** 267 | * @dev reverts if the caller does not have access by the accessController 268 | * contract or is the contract itself. 269 | */ 270 | modifier checkAccess() { 271 | AccessControllerInterface ac = accessController; 272 | require( 273 | address(ac) == address(0) || ac.hasAccess(msg.sender, msg.data), 274 | "No access" 275 | ); 276 | _; 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /contracts/Flags.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | import "./SimpleReadAccessController.sol"; 5 | import "./interfaces/AccessControllerInterface.sol"; 6 | import "./interfaces/FlagsInterface.sol"; 7 | 8 | /** 9 | * @title The Flags contract 10 | * @notice Allows flags to signal to any reader on the access control list. 11 | * The owner can set flags, or designate other addresses to set flags. The 12 | * owner must turn the flags off, other setters cannot. An expected pattern is 13 | * to allow addresses to raise flags on themselves, so if you are subscribing to 14 | * FlagOn events you should filter for addresses you care about. 15 | */ 16 | contract Flags is FlagsInterface, SimpleReadAccessController { 17 | AccessControllerInterface public raisingAccessController; 18 | 19 | mapping(address => bool) private flags; 20 | 21 | event FlagRaised(address indexed subject); 22 | event FlagLowered(address indexed subject); 23 | event RaisingAccessControllerUpdated( 24 | address indexed previous, 25 | address indexed current 26 | ); 27 | 28 | /** 29 | * @param racAddress address for the raising access controller. 30 | */ 31 | constructor(address racAddress) public { 32 | setRaisingAccessController(racAddress); 33 | } 34 | 35 | /** 36 | * @notice read the warning flag status of a contract address. 37 | * @param subject The contract address being checked for a flag. 38 | * @return A true value indicates that a flag was raised and a 39 | * false value indicates that no flag was raised. 40 | */ 41 | function getFlag(address subject) 42 | external 43 | view 44 | override 45 | checkAccess() 46 | returns (bool) 47 | { 48 | return flags[subject]; 49 | } 50 | 51 | /** 52 | * @notice read the warning flag status of a contract address. 53 | * @param subjects An array of addresses being checked for a flag. 54 | * @return An array of bools where a true value for any flag indicates that 55 | * a flag was raised and a false value indicates that no flag was raised. 56 | */ 57 | function getFlags(address[] calldata subjects) 58 | external 59 | view 60 | override 61 | checkAccess() 62 | returns (bool[] memory) 63 | { 64 | bool[] memory responses = new bool[](subjects.length); 65 | for (uint256 i = 0; i < subjects.length; i++) { 66 | responses[i] = flags[subjects[i]]; 67 | } 68 | return responses; 69 | } 70 | 71 | /** 72 | * @notice enable the warning flag for an address. 73 | * Access is controlled by raisingAccessController, except for owner 74 | * who always has access. 75 | * @param subject The contract address whose flag is being raised 76 | */ 77 | function raiseFlag(address subject) external override { 78 | require(allowedToRaiseFlags(), "Not allowed to raise flags"); 79 | 80 | tryToRaiseFlag(subject); 81 | } 82 | 83 | /** 84 | * @notice enable the warning flags for multiple addresses. 85 | * Access is controlled by raisingAccessController, except for owner 86 | * who always has access. 87 | * @param subjects List of the contract addresses whose flag is being raised 88 | */ 89 | function raiseFlags(address[] calldata subjects) external override { 90 | require(allowedToRaiseFlags(), "Not allowed to raise flags"); 91 | 92 | for (uint256 i = 0; i < subjects.length; i++) { 93 | tryToRaiseFlag(subjects[i]); 94 | } 95 | } 96 | 97 | /** 98 | * @notice allows owner to disable the warning flags for multiple addresses. 99 | * @param subjects List of the contract addresses whose flag is being lowered 100 | */ 101 | function lowerFlags(address[] calldata subjects) 102 | external 103 | override 104 | onlyOwner() 105 | { 106 | for (uint256 i = 0; i < subjects.length; i++) { 107 | address subject = subjects[i]; 108 | 109 | if (flags[subject]) { 110 | flags[subject] = false; 111 | emit FlagLowered(subject); 112 | } 113 | } 114 | } 115 | 116 | /** 117 | * @notice allows owner to change the access controller for raising flags. 118 | * @param racAddress new address for the raising access controller. 119 | */ 120 | function setRaisingAccessController(address racAddress) 121 | public 122 | override 123 | onlyOwner() 124 | { 125 | address previous = address(raisingAccessController); 126 | 127 | if (previous != racAddress) { 128 | raisingAccessController = AccessControllerInterface(racAddress); 129 | 130 | emit RaisingAccessControllerUpdated(previous, racAddress); 131 | } 132 | } 133 | 134 | // PRIVATE 135 | 136 | function allowedToRaiseFlags() private view returns (bool) { 137 | return 138 | msg.sender == owner || 139 | raisingAccessController.hasAccess(msg.sender, msg.data); 140 | } 141 | 142 | function tryToRaiseFlag(address subject) private { 143 | if (!flags[subject]) { 144 | flags[subject] = true; 145 | emit FlagRaised(subject); 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /contracts/HashBridgeOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import {CBORHashBridgeOracle} from "./vendor/CBORHashBridgeOracle.sol"; 5 | import {BufferHashBridgeOracle} from "./vendor/BufferHashBridgeOracle.sol"; 6 | 7 | /** 8 | * @title Library for common HashBridgeOracle functions 9 | * @dev Uses imported CBOR library for encoding to buffer 10 | */ 11 | library HashBridgeOracle { 12 | uint256 internal constant defaultBufferSize = 256; // solhint-disable-line const-name-snakecase 13 | 14 | using CBORHashBridgeOracle for BufferHashBridgeOracle.buffer; 15 | 16 | struct Request { 17 | bytes32 id; 18 | address callbackAddress; 19 | bytes4 callbackFunctionId; 20 | uint256 nonce; 21 | BufferHashBridgeOracle.buffer buf; 22 | } 23 | 24 | /** 25 | * @notice Initializes a HashBridgeOracle request 26 | * @dev Sets the ID, callback address, and callback function signature on the request 27 | * @param self The uninitialized request 28 | * @param _id The Job Specification ID 29 | * @param _callbackAddress The callback address 30 | * @param _callbackFunction The callback function signature 31 | * @return The initialized request 32 | */ 33 | function initialize( 34 | Request memory self, 35 | bytes32 _id, 36 | address _callbackAddress, 37 | bytes4 _callbackFunction 38 | ) internal pure returns (HashBridgeOracle.Request memory) { 39 | BufferHashBridgeOracle.init(self.buf, defaultBufferSize); 40 | self.id = _id; 41 | self.callbackAddress = _callbackAddress; 42 | self.callbackFunctionId = _callbackFunction; 43 | return self; 44 | } 45 | 46 | /** 47 | * @notice Sets the data for the buffer without encoding CBOR on-chain 48 | * @dev CBOR can be closed with curly-brackets {} or they can be left off 49 | * @param self The initialized request 50 | * @param _data The CBOR data 51 | */ 52 | function setBuffer(Request memory self, bytes memory _data) internal pure { 53 | BufferHashBridgeOracle.init(self.buf, _data.length); 54 | BufferHashBridgeOracle.append(self.buf, _data); 55 | } 56 | 57 | /** 58 | * @notice Adds a string value to the request with a given key name 59 | * @param self The initialized request 60 | * @param _key The name of the key 61 | * @param _value The string value to add 62 | */ 63 | function add( 64 | Request memory self, 65 | string memory _key, 66 | string memory _value 67 | ) internal pure { 68 | self.buf.encodeString(_key); 69 | self.buf.encodeString(_value); 70 | } 71 | 72 | /** 73 | * @notice Adds a bytes value to the request with a given key name 74 | * @param self The initialized request 75 | * @param _key The name of the key 76 | * @param _value The bytes value to add 77 | */ 78 | function addBytes( 79 | Request memory self, 80 | string memory _key, 81 | bytes memory _value 82 | ) internal pure { 83 | self.buf.encodeString(_key); 84 | self.buf.encodeBytes(_value); 85 | } 86 | 87 | /** 88 | * @notice Adds a int256 value to the request with a given key name 89 | * @param self The initialized request 90 | * @param _key The name of the key 91 | * @param _value The int256 value to add 92 | */ 93 | function addInt( 94 | Request memory self, 95 | string memory _key, 96 | int256 _value 97 | ) internal pure { 98 | self.buf.encodeString(_key); 99 | self.buf.encodeInt(_value); 100 | } 101 | 102 | /** 103 | * @notice Adds a uint256 value to the request with a given key name 104 | * @param self The initialized request 105 | * @param _key The name of the key 106 | * @param _value The uint256 value to add 107 | */ 108 | function addUint( 109 | Request memory self, 110 | string memory _key, 111 | uint256 _value 112 | ) internal pure { 113 | self.buf.encodeString(_key); 114 | self.buf.encodeUInt(_value); 115 | } 116 | 117 | /** 118 | * @notice Adds an array of strings to the request with a given key name 119 | * @param self The initialized request 120 | * @param _key The name of the key 121 | * @param _values The array of string values to add 122 | */ 123 | function addStringArray( 124 | Request memory self, 125 | string memory _key, 126 | string[] memory _values 127 | ) internal pure { 128 | self.buf.encodeString(_key); 129 | self.buf.startArray(); 130 | for (uint256 i = 0; i < _values.length; i++) { 131 | self.buf.encodeString(_values[i]); 132 | } 133 | self.buf.endSequence(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /contracts/HashBridgeOracleClient.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "./HashBridgeOracle.sol"; 5 | import "./interfaces/ENSInterface.sol"; 6 | import "./interfaces/HashBridgeOracleTokenInterface.sol"; 7 | import "./interfaces/HashBridgeOracleRequestInterface.sol"; 8 | import "./interfaces/PointerInterface.sol"; 9 | import { 10 | ENSResolver as ENSResolver_HashBridgeOracle 11 | } from "./vendor/ENSResolver.sol"; 12 | 13 | /** 14 | * @title The HashBridgeOracleClient contract 15 | * @notice Contract writers can inherit this contract in order to create requests for the 16 | * HashBridgeOracle network 17 | */ 18 | contract HashBridgeOracleClient { 19 | using HashBridgeOracle for HashBridgeOracle.Request; 20 | 21 | uint256 internal constant HBO = 10**18; 22 | uint256 private constant AMOUNT_OVERRIDE = 0; 23 | address private constant SENDER_OVERRIDE = address(0); 24 | uint256 private constant ARGS_VERSION = 1; 25 | bytes32 private constant ENS_TOKEN_SUBNAME = keccak256("hbo"); 26 | bytes32 private constant ENS_ORACLE_SUBNAME = keccak256("oracle"); 27 | address private constant HBO_TOKEN_POINTER = 28 | 0xC89bD4E1632D3A43CB03AAAd5262cbe4038Bc571; 29 | 30 | ENSInterface private ens; 31 | bytes32 private ensNode; 32 | HashBridgeOracleTokenInterface private hbo; 33 | HashBridgeOracleRequestInterface private oracle; 34 | uint256 private requestCount = 1; 35 | mapping(bytes32 => address) private pendingRequests; 36 | 37 | event HashBridgeOracleRequested(bytes32 indexed id); 38 | event HashBridgeOracleFulfilled(bytes32 indexed id); 39 | event HashBridgeOracleCancelled(bytes32 indexed id); 40 | 41 | /** 42 | * @notice Creates a request that can hold additional parameters 43 | * @param _specId The Job Specification ID that the request will be created for 44 | * @param _callbackAddress The callback address that the response will be sent to 45 | * @param _callbackFunctionSignature The callback function signature to use for the callback address 46 | * @return A HashBridgeOracle Request struct in memory 47 | */ 48 | function buildHashBridgeOracleRequest( 49 | bytes32 _specId, 50 | address _callbackAddress, 51 | bytes4 _callbackFunctionSignature 52 | ) internal pure returns (HashBridgeOracle.Request memory) { 53 | HashBridgeOracle.Request memory req; 54 | return 55 | req.initialize( 56 | _specId, 57 | _callbackAddress, 58 | _callbackFunctionSignature 59 | ); 60 | } 61 | 62 | /** 63 | * @notice Creates a HashBridgeOracle request to the stored oracle address 64 | * @dev Calls `hashBridgeOracleRequestTo` with the stored oracle address 65 | * @param _req The initialized HashBridgeOracle Request 66 | * @param _payment The amount of HBO to send for the request 67 | * @return requestId The request ID 68 | */ 69 | function sendHashBridgeOracleRequest( 70 | HashBridgeOracle.Request memory _req, 71 | uint256 _payment 72 | ) internal returns (bytes32) { 73 | return sendHashBridgeOracleRequestTo(address(oracle), _req, _payment); 74 | } 75 | 76 | /** 77 | * @notice Creates a HashBridgeOracle request to the specified oracle address 78 | * @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to 79 | * send HBO which creates a request on the target oracle contract. 80 | * Emits HashBridgeOracleRequested event. 81 | * @param _oracle The address of the oracle for the request 82 | * @param _req The initialized HashBridgeOracle Request 83 | * @param _payment The amount of HBO to send for the request 84 | * @return requestId The request ID 85 | */ 86 | function sendHashBridgeOracleRequestTo( 87 | address _oracle, 88 | HashBridgeOracle.Request memory _req, 89 | uint256 _payment 90 | ) internal returns (bytes32 requestId) { 91 | requestId = keccak256(abi.encodePacked(this, requestCount)); 92 | _req.nonce = requestCount; 93 | pendingRequests[requestId] = _oracle; 94 | emit HashBridgeOracleRequested(requestId); 95 | require( 96 | hbo.transferAndCall(_oracle, _payment, encodeRequest(_req)), 97 | "unable to transferAndCall to oracle" 98 | ); 99 | requestCount += 1; 100 | 101 | return requestId; 102 | } 103 | 104 | /** 105 | * @notice Allows a request to be cancelled if it has not been fulfilled 106 | * @dev Requires keeping track of the expiration value emitted from the oracle contract. 107 | * Deletes the request from the `pendingRequests` mapping. 108 | * Emits HashBridgeOracleCancelled event. 109 | * @param _requestId The request ID 110 | * @param _payment The amount of HBO sent for the request 111 | * @param _callbackFunc The callback function specified for the request 112 | * @param _expiration The time of the expiration for the request 113 | */ 114 | function cancelHashBridgeOracleRequest( 115 | bytes32 _requestId, 116 | uint256 _payment, 117 | bytes4 _callbackFunc, 118 | uint256 _expiration 119 | ) internal { 120 | HashBridgeOracleRequestInterface requested = 121 | HashBridgeOracleRequestInterface(pendingRequests[_requestId]); 122 | delete pendingRequests[_requestId]; 123 | emit HashBridgeOracleCancelled(_requestId); 124 | requested.cancelOracleRequest( 125 | _requestId, 126 | _payment, 127 | _callbackFunc, 128 | _expiration 129 | ); 130 | } 131 | 132 | /** 133 | * @notice Sets the stored oracle address 134 | * @param _oracle The address of the oracle contract 135 | */ 136 | function setHashBridgeOracleOracle(address _oracle) internal { 137 | oracle = HashBridgeOracleRequestInterface(_oracle); 138 | } 139 | 140 | /** 141 | * @notice Sets the HBO token address 142 | * @param _hbo The address of the HBO token contract 143 | */ 144 | function setHashBridgeOracleToken(address _hbo) internal { 145 | hbo = HashBridgeOracleTokenInterface(_hbo); 146 | } 147 | 148 | /** 149 | * @notice Sets the HashBridgeOracle token address for the public 150 | * network as given by the Pointer contract 151 | */ 152 | function setPublicHashBridgeOracleToken() internal { 153 | setHashBridgeOracleToken( 154 | PointerInterface(HBO_TOKEN_POINTER).getAddress() 155 | ); 156 | } 157 | 158 | /** 159 | * @notice Retrieves the stored address of the HBO token 160 | * @return The address of the HBO token 161 | */ 162 | function hashBridgeOracleTokenAddress() internal view returns (address) { 163 | return address(hbo); 164 | } 165 | 166 | /** 167 | * @notice Retrieves the stored address of the oracle contract 168 | * @return The address of the oracle contract 169 | */ 170 | function hashBridgeOracleAddress() internal view returns (address) { 171 | return address(oracle); 172 | } 173 | 174 | /** 175 | * @notice Allows for a request which was created on another contract to be fulfilled 176 | * on this contract 177 | * @param _oracle The address of the oracle contract that will fulfill the request 178 | * @param _requestId The request ID used for the response 179 | */ 180 | function addHashBridgeOracleExternalRequest( 181 | address _oracle, 182 | bytes32 _requestId 183 | ) internal notPendingRequest(_requestId) { 184 | pendingRequests[_requestId] = _oracle; 185 | } 186 | 187 | /** 188 | * @notice Sets the stored oracle and HBO token contracts with the addresses resolved by ENS 189 | * @dev Accounts for subnodes having different resolvers 190 | * @param _ens The address of the ENS contract 191 | * @param _node The ENS node hash 192 | */ 193 | function useHashBridgeOracleWithENS(address _ens, bytes32 _node) internal { 194 | ens = ENSInterface(_ens); 195 | ensNode = _node; 196 | bytes32 hboSubnode = 197 | keccak256(abi.encodePacked(ensNode, ENS_TOKEN_SUBNAME)); 198 | ENSResolver_HashBridgeOracle resolver = 199 | ENSResolver_HashBridgeOracle(ens.resolver(hboSubnode)); 200 | setHashBridgeOracleToken(resolver.addr(hboSubnode)); 201 | updateHashBridgeOracleOracleWithENS(); 202 | } 203 | 204 | /** 205 | * @notice Sets the stored oracle contract with the address resolved by ENS 206 | * @dev This may be called on its own as long as `useHashBridgeOracleWithENS` has been called previously 207 | */ 208 | function updateHashBridgeOracleOracleWithENS() internal { 209 | bytes32 oracleSubnode = 210 | keccak256(abi.encodePacked(ensNode, ENS_ORACLE_SUBNAME)); 211 | ENSResolver_HashBridgeOracle resolver = 212 | ENSResolver_HashBridgeOracle(ens.resolver(oracleSubnode)); 213 | setHashBridgeOracleOracle(resolver.addr(oracleSubnode)); 214 | } 215 | 216 | /** 217 | * @notice Encodes the request to be sent to the oracle contract 218 | * @dev The HashBridgeOracle node expects values to be in order for the request to be picked up. Order of types 219 | * will be validated in the oracle contract. 220 | * @param _req The initialized HashBridgeOracle Request 221 | * @return The bytes payload for the `transferAndCall` method 222 | */ 223 | function encodeRequest(HashBridgeOracle.Request memory _req) 224 | private 225 | view 226 | returns (bytes memory) 227 | { 228 | return 229 | abi.encodeWithSelector( 230 | oracle.oracleRequest.selector, 231 | SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address 232 | AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of HBO sent 233 | _req.id, 234 | _req.callbackAddress, 235 | _req.callbackFunctionId, 236 | _req.nonce, 237 | ARGS_VERSION, 238 | _req.buf.buf 239 | ); 240 | } 241 | 242 | /** 243 | * @notice Ensures that the fulfillment is valid for this contract 244 | * @dev Use if the contract developer prefers methods instead of modifiers for validation 245 | * @param _requestId The request ID for fulfillment 246 | */ 247 | function validateHashBridgeOracleCallback(bytes32 _requestId) 248 | internal 249 | recordHashBridgeOracleFulfillment(_requestId) 250 | // solhint-disable-next-line no-empty-blocks 251 | { 252 | 253 | } 254 | 255 | /** 256 | * @dev Reverts if the sender is not the oracle of the request. 257 | * Emits HashBridgeOracleFulfilled event. 258 | * @param _requestId The request ID for fulfillment 259 | */ 260 | modifier recordHashBridgeOracleFulfillment(bytes32 _requestId) { 261 | require( 262 | msg.sender == pendingRequests[_requestId], 263 | "Source must be the oracle of the request" 264 | ); 265 | delete pendingRequests[_requestId]; 266 | emit HashBridgeOracleFulfilled(_requestId); 267 | _; 268 | } 269 | 270 | /** 271 | * @dev Reverts if the request is already pending 272 | * @param _requestId The request ID for fulfillment 273 | */ 274 | modifier notPendingRequest(bytes32 _requestId) { 275 | require( 276 | pendingRequests[_requestId] == address(0), 277 | "Request is already pending" 278 | ); 279 | _; 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /contracts/HashBridgeOracleTokenReceiver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | abstract contract HashBridgeOracleTokenReceiver { 5 | bytes4 private constant ORACLE_REQUEST_SELECTOR = 0x40429946; 6 | uint256 private constant SELECTOR_LENGTH = 4; 7 | uint256 private constant EXPECTED_REQUEST_WORDS = 2; 8 | uint256 private constant MINIMUM_REQUEST_LENGTH = 9 | SELECTOR_LENGTH + (32 * EXPECTED_REQUEST_WORDS); 10 | 11 | /** 12 | * @notice Called when HBO is sent to the contract via `transferAndCall` 13 | * @dev The data payload's first 2 words will be overwritten by the `_sender` and `_amount` 14 | * values to ensure correctness. Calls oracleRequest. 15 | * @param _sender Address of the sender 16 | * @param _amount Amount of HBO sent (specified in wei) 17 | * @param _data Payload of the transaction 18 | */ 19 | function onTokenTransfer( 20 | address _sender, 21 | uint256 _amount, 22 | bytes memory _data 23 | ) public onlyHBO validRequestLength(_data) permittedFunctionsForHBO(_data) { 24 | assembly { 25 | // solhint-disable-next-line avoid-low-level-calls 26 | mstore(add(_data, 36), _sender) // ensure correct sender is passed 27 | // solhint-disable-next-line avoid-low-level-calls 28 | mstore(add(_data, 68), _amount) // ensure correct amount is passed 29 | } 30 | // solhint-disable-next-line avoid-low-level-calls 31 | (bool success, ) = address(this).delegatecall(_data); // calls oracleRequest 32 | require(success, "Unable to create request"); 33 | } 34 | 35 | function getHashBridgeOracleToken() public view virtual returns (address); 36 | 37 | /** 38 | * @dev Reverts if not sent from the HBO token 39 | */ 40 | modifier onlyHBO() { 41 | require(msg.sender == getHashBridgeOracleToken(), "Must use HBO token"); 42 | _; 43 | } 44 | 45 | /** 46 | * @dev Reverts if the given data does not begin with the `oracleRequest` function selector 47 | * @param _data The data payload of the request 48 | */ 49 | modifier permittedFunctionsForHBO(bytes memory _data) { 50 | bytes4 funcSelector; 51 | assembly { 52 | // solhint-disable-next-line avoid-low-level-calls 53 | funcSelector := mload(add(_data, 32)) 54 | } 55 | require( 56 | funcSelector == ORACLE_REQUEST_SELECTOR, 57 | "Must use whitelisted functions" 58 | ); 59 | _; 60 | } 61 | 62 | /** 63 | * @dev Reverts if the given payload is less than needed to create a request 64 | * @param _data The request payload 65 | */ 66 | modifier validRequestLength(bytes memory _data) { 67 | require( 68 | _data.length >= MINIMUM_REQUEST_LENGTH, 69 | "Invalid request length" 70 | ); 71 | _; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /contracts/Median.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "./vendor/SafeMathHashBridgeOracle.sol"; 5 | import "./SignedSafeMath.sol"; 6 | 7 | library Median { 8 | using SignedSafeMath for int256; 9 | 10 | int256 constant INT_MAX = 2**255 - 1; 11 | 12 | /** 13 | * @notice Returns the sorted middle, or the average of the two middle indexed items if the 14 | * array has an even number of elements. 15 | * @dev The list passed as an argument isn't modified. 16 | * @dev This algorithm has expected runtime O(n), but for adversarially chosen inputs 17 | * the runtime is O(n^2). 18 | * @param list The list of elements to compare 19 | */ 20 | function calculate(int256[] memory list) internal pure returns (int256) { 21 | return calculateInplace(copy(list)); 22 | } 23 | 24 | /** 25 | * @notice See documentation for function calculate. 26 | * @dev The list passed as an argument may be permuted. 27 | */ 28 | function calculateInplace(int256[] memory list) 29 | internal 30 | pure 31 | returns (int256) 32 | { 33 | require(0 < list.length, "list must not be empty"); 34 | uint256 len = list.length; 35 | uint256 middleIndex = len / 2; 36 | if (len % 2 == 0) { 37 | int256 median1; 38 | int256 median2; 39 | (median1, median2) = quickselectTwo( 40 | list, 41 | 0, 42 | len - 1, 43 | middleIndex - 1, 44 | middleIndex 45 | ); 46 | return SignedSafeMath.avg(median1, median2); 47 | } else { 48 | return quickselect(list, 0, len - 1, middleIndex); 49 | } 50 | } 51 | 52 | /** 53 | * @notice Maximum length of list that shortSelectTwo can handle 54 | */ 55 | uint256 constant SHORTSELECTTWO_MAX_LENGTH = 7; 56 | 57 | /** 58 | * @notice Select the k1-th and k2-th element from list of length at most 7 59 | * @dev Uses an optimal sorting network 60 | */ 61 | function shortSelectTwo( 62 | int256[] memory list, 63 | uint256 lo, 64 | uint256 hi, 65 | uint256 k1, 66 | uint256 k2 67 | ) private pure returns (int256 k1th, int256 k2th) { 68 | // Uses an optimal sorting network (https://en.wikipedia.org/wiki/Sorting_network) 69 | // for lists of length 7. Network layout is taken from 70 | // http://jgamble.ripco.net/cgi-bin/nw.cgi?inputs=7&algorithm=hibbard&output=svg 71 | 72 | uint256 len = hi + 1 - lo; 73 | int256 x0 = list[lo + 0]; 74 | int256 x1 = 1 < len ? list[lo + 1] : INT_MAX; 75 | int256 x2 = 2 < len ? list[lo + 2] : INT_MAX; 76 | int256 x3 = 3 < len ? list[lo + 3] : INT_MAX; 77 | int256 x4 = 4 < len ? list[lo + 4] : INT_MAX; 78 | int256 x5 = 5 < len ? list[lo + 5] : INT_MAX; 79 | int256 x6 = 6 < len ? list[lo + 6] : INT_MAX; 80 | 81 | if (x0 > x1) { 82 | (x0, x1) = (x1, x0); 83 | } 84 | if (x2 > x3) { 85 | (x2, x3) = (x3, x2); 86 | } 87 | if (x4 > x5) { 88 | (x4, x5) = (x5, x4); 89 | } 90 | if (x0 > x2) { 91 | (x0, x2) = (x2, x0); 92 | } 93 | if (x1 > x3) { 94 | (x1, x3) = (x3, x1); 95 | } 96 | if (x4 > x6) { 97 | (x4, x6) = (x6, x4); 98 | } 99 | if (x1 > x2) { 100 | (x1, x2) = (x2, x1); 101 | } 102 | if (x5 > x6) { 103 | (x5, x6) = (x6, x5); 104 | } 105 | if (x0 > x4) { 106 | (x0, x4) = (x4, x0); 107 | } 108 | if (x1 > x5) { 109 | (x1, x5) = (x5, x1); 110 | } 111 | if (x2 > x6) { 112 | (x2, x6) = (x6, x2); 113 | } 114 | if (x1 > x4) { 115 | (x1, x4) = (x4, x1); 116 | } 117 | if (x3 > x6) { 118 | (x3, x6) = (x6, x3); 119 | } 120 | if (x2 > x4) { 121 | (x2, x4) = (x4, x2); 122 | } 123 | if (x3 > x5) { 124 | (x3, x5) = (x5, x3); 125 | } 126 | if (x3 > x4) { 127 | (x3, x4) = (x4, x3); 128 | } 129 | 130 | uint256 index1 = k1 - lo; 131 | if (index1 == 0) { 132 | k1th = x0; 133 | } else if (index1 == 1) { 134 | k1th = x1; 135 | } else if (index1 == 2) { 136 | k1th = x2; 137 | } else if (index1 == 3) { 138 | k1th = x3; 139 | } else if (index1 == 4) { 140 | k1th = x4; 141 | } else if (index1 == 5) { 142 | k1th = x5; 143 | } else if (index1 == 6) { 144 | k1th = x6; 145 | } else { 146 | revert("k1 out of bounds"); 147 | } 148 | 149 | uint256 index2 = k2 - lo; 150 | if (k1 == k2) { 151 | return (k1th, k1th); 152 | } else if (index2 == 0) { 153 | return (k1th, x0); 154 | } else if (index2 == 1) { 155 | return (k1th, x1); 156 | } else if (index2 == 2) { 157 | return (k1th, x2); 158 | } else if (index2 == 3) { 159 | return (k1th, x3); 160 | } else if (index2 == 4) { 161 | return (k1th, x4); 162 | } else if (index2 == 5) { 163 | return (k1th, x5); 164 | } else if (index2 == 6) { 165 | return (k1th, x6); 166 | } else { 167 | revert("k2 out of bounds"); 168 | } 169 | } 170 | 171 | /** 172 | * @notice Selects the k-th ranked element from list, looking only at indices between lo and hi 173 | * (inclusive). Modifies list in-place. 174 | */ 175 | function quickselect( 176 | int256[] memory list, 177 | uint256 lo, 178 | uint256 hi, 179 | uint256 k 180 | ) private pure returns (int256 kth) { 181 | require(lo <= k); 182 | require(k <= hi); 183 | while (lo < hi) { 184 | if (hi - lo < SHORTSELECTTWO_MAX_LENGTH) { 185 | int256 ignore; 186 | (kth, ignore) = shortSelectTwo(list, lo, hi, k, k); 187 | return kth; 188 | } 189 | uint256 pivotIndex = partition(list, lo, hi); 190 | if (k <= pivotIndex) { 191 | // since pivotIndex < (original hi passed to partition), 192 | // termination is guaranteed in this case 193 | hi = pivotIndex; 194 | } else { 195 | // since (original lo passed to partition) <= pivotIndex, 196 | // termination is guaranteed in this case 197 | lo = pivotIndex + 1; 198 | } 199 | } 200 | return list[lo]; 201 | } 202 | 203 | /** 204 | * @notice Selects the k1-th and k2-th ranked elements from list, looking only at indices between 205 | * lo and hi (inclusive). Modifies list in-place. 206 | */ 207 | function quickselectTwo( 208 | int256[] memory list, 209 | uint256 lo, 210 | uint256 hi, 211 | uint256 k1, 212 | uint256 k2 // for testing 213 | ) internal pure returns (int256 k1th, int256 k2th) { 214 | require(k1 < k2); 215 | require(lo <= k1 && k1 <= hi); 216 | require(lo <= k2 && k2 <= hi); 217 | 218 | while (true) { 219 | if (hi - lo < SHORTSELECTTWO_MAX_LENGTH) { 220 | return shortSelectTwo(list, lo, hi, k1, k2); 221 | } 222 | uint256 pivotIdx = partition(list, lo, hi); 223 | if (k2 <= pivotIdx) { 224 | hi = pivotIdx; 225 | } else if (pivotIdx < k1) { 226 | lo = pivotIdx + 1; 227 | } else { 228 | assert(k1 <= pivotIdx && pivotIdx < k2); 229 | k1th = quickselect(list, lo, pivotIdx, k1); 230 | k2th = quickselect(list, pivotIdx + 1, hi, k2); 231 | return (k1th, k2th); 232 | } 233 | } 234 | } 235 | 236 | /** 237 | * @notice Partitions list in-place using Hoare's partitioning scheme. 238 | * Only elements of list between indices lo and hi (inclusive) will be modified. 239 | * Returns an index i, such that: 240 | * - lo <= i < hi 241 | * - forall j in [lo, i]. list[j] <= list[i] 242 | * - forall j in [i, hi]. list[i] <= list[j] 243 | */ 244 | function partition( 245 | int256[] memory list, 246 | uint256 lo, 247 | uint256 hi 248 | ) private pure returns (uint256) { 249 | // We don't care about overflow of the addition, because it would require a list 250 | // larger than any feasible computer's memory. 251 | int256 pivot = list[(lo + hi) / 2]; 252 | lo -= 1; // this can underflow. that's intentional. 253 | hi += 1; 254 | while (true) { 255 | do { 256 | lo += 1; 257 | } while (list[lo] < pivot); 258 | do { 259 | hi -= 1; 260 | } while (list[hi] > pivot); 261 | if (lo < hi) { 262 | (list[lo], list[hi]) = (list[hi], list[lo]); 263 | } else { 264 | // Let orig_lo and orig_hi be the original values of lo and hi passed to partition. 265 | // Then, hi < orig_hi, because hi decreases *strictly* monotonically 266 | // in each loop iteration and 267 | // - either list[orig_hi] > pivot, in which case the first loop iteration 268 | // will achieve hi < orig_hi; 269 | // - or list[orig_hi] <= pivot, in which case at least two loop iterations are 270 | // needed: 271 | // - lo will have to stop at least once in the interval 272 | // [orig_lo, (orig_lo + orig_hi)/2] 273 | // - (orig_lo + orig_hi)/2 < orig_hi 274 | return hi; 275 | } 276 | } 277 | } 278 | 279 | /** 280 | * @notice Makes an in-memory copy of the array passed in 281 | * @param list Reference to the array to be copied 282 | */ 283 | function copy(int256[] memory list) private pure returns (int256[] memory) { 284 | int256[] memory list2 = new int256[](list.length); 285 | for (uint256 i = 0; i < list.length; i++) { 286 | list2[i] = list[i]; 287 | } 288 | return list2; 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.22 <0.9.0; 3 | 4 | contract Migrations { 5 | address public owner = msg.sender; 6 | uint256 public last_completed_migration; 7 | 8 | modifier restricted() { 9 | require( 10 | msg.sender == owner, 11 | "This function is restricted to the contract's owner" 12 | ); 13 | _; 14 | } 15 | 16 | function setCompleted(uint256 completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /contracts/Oracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | import "./HashBridgeOracleTokenReceiver.sol"; 5 | import "./interfaces/HashBridgeOracleRequestInterface.sol"; 6 | import "./interfaces/OracleInterface.sol"; 7 | import "./interfaces/HashBridgeOracleTokenInterface.sol"; 8 | import "./interfaces/WithdrawalInterface.sol"; 9 | import "./vendor/Ownable.sol"; 10 | import "./vendor/SafeMathHashBridgeOracle.sol"; 11 | 12 | /** 13 | * @title The HashBridgeOracle Oracle contract 14 | * @notice Node operators can deploy this contract to fulfill requests sent to them 15 | */ 16 | contract Oracle is 17 | HashBridgeOracleRequestInterface, 18 | OracleInterface, 19 | Ownable, 20 | HashBridgeOracleTokenReceiver, 21 | WithdrawalInterface 22 | { 23 | using SafeMathHashBridgeOracle for uint256; 24 | 25 | uint256 public constant EXPIRY_TIME = 5 minutes; 26 | uint256 private constant MINIMUM_CONSUMER_GAS_LIMIT = 400000; 27 | // We initialize fields to 1 instead of 0 so that the first invocation 28 | // does not cost more gas. 29 | uint256 private constant ONE_FOR_CONSISTENT_GAS_COST = 1; 30 | 31 | HashBridgeOracleTokenInterface internal HboToken; 32 | mapping(bytes32 => bytes32) private commitments; 33 | mapping(address => bool) private authorizedNodes; 34 | uint256 private withdrawableTokens = ONE_FOR_CONSISTENT_GAS_COST; 35 | 36 | event OracleRequest( 37 | bytes32 indexed specId, 38 | address requester, 39 | bytes32 requestId, 40 | uint256 payment, 41 | address callbackAddr, 42 | bytes4 callbackFunctionId, 43 | uint256 cancelExpiration, 44 | uint256 dataVersion, 45 | bytes data 46 | ); 47 | 48 | event CancelOracleRequest(bytes32 indexed requestId); 49 | 50 | /** 51 | * @notice Deploy with the address of the HBO token 52 | * @dev Sets the HboToken address for the imported HashBridgeOracleTokenInterface 53 | * @param _hbo The address of the HBO token 54 | */ 55 | constructor(address _hbo) public Ownable() { 56 | HboToken = HashBridgeOracleTokenInterface(_hbo); // external but already deployed and unalterable 57 | } 58 | 59 | /** 60 | * @notice Creates the HashBridgeOracle request 61 | * @dev Stores the hash of the params as the on-chain commitment for the request. 62 | * Emits OracleRequest event for the HashBridgeOracle node to detect. 63 | * @param _sender The sender of the request 64 | * @param _payment The amount of payment given (specified in wei) 65 | * @param _specId The Job Specification ID 66 | * @param _callbackAddress The callback address for the response 67 | * @param _callbackFunctionId The callback function ID for the response 68 | * @param _nonce The nonce sent by the requester 69 | * @param _dataVersion The specified data version 70 | * @param _data The CBOR payload of the request 71 | */ 72 | function oracleRequest( 73 | address _sender, 74 | uint256 _payment, 75 | bytes32 _specId, 76 | address _callbackAddress, 77 | bytes4 _callbackFunctionId, 78 | uint256 _nonce, 79 | uint256 _dataVersion, 80 | bytes calldata _data 81 | ) external override onlyHBO() checkCallbackAddress(_callbackAddress) { 82 | bytes32 requestId = keccak256(abi.encodePacked(_sender, _nonce)); 83 | require(commitments[requestId] == 0, "Must use a unique ID"); 84 | // solhint-disable-next-line not-rely-on-time 85 | uint256 expiration = now.add(EXPIRY_TIME); 86 | 87 | commitments[requestId] = keccak256( 88 | abi.encodePacked( 89 | _payment, 90 | _callbackAddress, 91 | _callbackFunctionId, 92 | expiration 93 | ) 94 | ); 95 | 96 | emit OracleRequest( 97 | _specId, 98 | _sender, 99 | requestId, 100 | _payment, 101 | _callbackAddress, 102 | _callbackFunctionId, 103 | expiration, 104 | _dataVersion, 105 | _data 106 | ); 107 | } 108 | 109 | /** 110 | * @notice Called by the HashBridgeOracle node to fulfill requests 111 | * @dev Given params must hash back to the commitment stored from `oracleRequest`. 112 | * Will call the callback address' callback function without bubbling up error 113 | * checking in a `require` so that the node can get paid. 114 | * @param _requestId The fulfillment request ID that must match the requester's 115 | * @param _payment The payment amount that will be released for the oracle (specified in wei) 116 | * @param _callbackAddress The callback address to call for fulfillment 117 | * @param _callbackFunctionId The callback function ID to use for fulfillment 118 | * @param _expiration The expiration that the node should respond by before the requester can cancel 119 | * @param _data The data to return to the consuming contract 120 | * @return Status if the external call was successful 121 | */ 122 | function fulfillOracleRequest( 123 | bytes32 _requestId, 124 | uint256 _payment, 125 | address _callbackAddress, 126 | bytes4 _callbackFunctionId, 127 | uint256 _expiration, 128 | bytes32 _data 129 | ) 130 | external 131 | override 132 | onlyAuthorizedNode 133 | isValidRequest(_requestId) 134 | returns (bool) 135 | { 136 | bytes32 paramsHash = 137 | keccak256( 138 | abi.encodePacked( 139 | _payment, 140 | _callbackAddress, 141 | _callbackFunctionId, 142 | _expiration 143 | ) 144 | ); 145 | require( 146 | commitments[_requestId] == paramsHash, 147 | "Params do not match request ID" 148 | ); 149 | withdrawableTokens = withdrawableTokens.add(_payment); 150 | delete commitments[_requestId]; 151 | require( 152 | gasleft() >= MINIMUM_CONSUMER_GAS_LIMIT, 153 | "Must provide consumer enough gas" 154 | ); 155 | // All updates to the oracle's fulfillment should come before calling the 156 | // callback(addr+functionId) as it is untrusted. 157 | // See: https://solidity.readthedocs.io/en/develop/security-considerations.html#use-the-checks-effects-interactions-pattern 158 | (bool success, ) = 159 | _callbackAddress.call( 160 | abi.encodeWithSelector(_callbackFunctionId, _requestId, _data) 161 | ); // solhint-disable-line avoid-low-level-calls 162 | return success; 163 | } 164 | 165 | /** 166 | * @notice Use this to check if a node is authorized for fulfilling requests 167 | * @param _node The address of the HashBridgeOracle node 168 | * @return The authorization status of the node 169 | */ 170 | function getAuthorizationStatus(address _node) 171 | external 172 | view 173 | override 174 | returns (bool) 175 | { 176 | return authorizedNodes[_node]; 177 | } 178 | 179 | /** 180 | * @notice Sets the fulfillment permission for a given node. Use `true` to allow, `false` to disallow. 181 | * @param _node The address of the HashBridgeOracle node 182 | * @param _allowed Bool value to determine if the node can fulfill requests 183 | */ 184 | function setFulfillmentPermission(address _node, bool _allowed) 185 | external 186 | override 187 | onlyOwner() 188 | { 189 | authorizedNodes[_node] = _allowed; 190 | } 191 | 192 | /** 193 | * @notice Allows the node operator to withdraw earned HBO to a given address 194 | * @dev The owner of the contract can be another wallet and does not have to be a HashBridgeOracle node 195 | * @param _recipient The address to send the HBO token to 196 | * @param _amount The amount to send (specified in wei) 197 | */ 198 | function withdraw(address _recipient, uint256 _amount) 199 | external 200 | override(OracleInterface, WithdrawalInterface) 201 | onlyOwner 202 | hasAvailableFunds(_amount) 203 | { 204 | withdrawableTokens = withdrawableTokens.sub(_amount); 205 | assert(HboToken.transfer(_recipient, _amount)); 206 | } 207 | 208 | /** 209 | * @notice Displays the amount of HBO that is available for the node operator to withdraw 210 | * @dev We use `ONE_FOR_CONSISTENT_GAS_COST` in place of 0 in storage 211 | * @return The amount of withdrawable HBO on the contract 212 | */ 213 | function withdrawable() 214 | external 215 | view 216 | override(OracleInterface, WithdrawalInterface) 217 | onlyOwner() 218 | returns (uint256) 219 | { 220 | return withdrawableTokens.sub(ONE_FOR_CONSISTENT_GAS_COST); 221 | } 222 | 223 | /** 224 | * @notice Allows requesters to cancel requests sent to this oracle contract. Will transfer the HBO 225 | * sent for the request back to the requester's address. 226 | * @dev Given params must hash to a commitment stored on the contract in order for the request to be valid 227 | * Emits CancelOracleRequest event. 228 | * @param _requestId The request ID 229 | * @param _payment The amount of payment given (specified in wei) 230 | * @param _callbackFunc The requester's specified callback address 231 | * @param _expiration The time of the expiration for the request 232 | */ 233 | function cancelOracleRequest( 234 | bytes32 _requestId, 235 | uint256 _payment, 236 | bytes4 _callbackFunc, 237 | uint256 _expiration 238 | ) external override { 239 | bytes32 paramsHash = 240 | keccak256( 241 | abi.encodePacked( 242 | _payment, 243 | msg.sender, 244 | _callbackFunc, 245 | _expiration 246 | ) 247 | ); 248 | require( 249 | paramsHash == commitments[_requestId], 250 | "Params do not match request ID" 251 | ); 252 | // solhint-disable-next-line not-rely-on-time 253 | require(_expiration <= now, "Request is not expired"); 254 | 255 | delete commitments[_requestId]; 256 | emit CancelOracleRequest(_requestId); 257 | 258 | assert(HboToken.transfer(msg.sender, _payment)); 259 | } 260 | 261 | /** 262 | * @notice Returns the address of the HBO token 263 | * @dev This is the public implementation for hashBridgeOracleTokenAddress, which is 264 | * an internal method of the HashBridgeOracleClient contract 265 | */ 266 | function getHashBridgeOracleToken() public view override returns (address) { 267 | return address(HboToken); 268 | } 269 | 270 | // MODIFIERS 271 | 272 | /** 273 | * @dev Reverts if amount requested is greater than withdrawable balance 274 | * @param _amount The given amount to compare to `withdrawableTokens` 275 | */ 276 | modifier hasAvailableFunds(uint256 _amount) { 277 | require( 278 | withdrawableTokens >= _amount.add(ONE_FOR_CONSISTENT_GAS_COST), 279 | "Amount requested is greater than withdrawable balance" 280 | ); 281 | _; 282 | } 283 | 284 | /** 285 | * @dev Reverts if request ID does not exist 286 | * @param _requestId The given request ID to check in stored `commitments` 287 | */ 288 | modifier isValidRequest(bytes32 _requestId) { 289 | require(commitments[_requestId] != 0, "Must have a valid requestId"); 290 | _; 291 | } 292 | 293 | /** 294 | * @dev Reverts if `msg.sender` is not authorized to fulfill requests 295 | */ 296 | modifier onlyAuthorizedNode() { 297 | require( 298 | authorizedNodes[msg.sender] || msg.sender == owner(), 299 | "Not an authorized node to fulfill requests" 300 | ); 301 | _; 302 | } 303 | 304 | /** 305 | * @dev Reverts if the callback address is the HBO token 306 | * @param _to The callback address 307 | */ 308 | modifier checkCallbackAddress(address _to) { 309 | require(_to != address(HboToken), "Cannot callback to HBO"); 310 | _; 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /contracts/Owned.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | /** 5 | * @title The Owned contract 6 | * @notice A contract with helpers for basic contract ownership. 7 | */ 8 | contract Owned { 9 | address public owner; 10 | address private pendingOwner; 11 | 12 | event OwnershipTransferRequested(address indexed from, address indexed to); 13 | event OwnershipTransferred(address indexed from, address indexed to); 14 | 15 | constructor() public { 16 | owner = msg.sender; 17 | } 18 | 19 | /** 20 | * @dev Allows an owner to begin transferring ownership to a new address, 21 | * pending. 22 | */ 23 | function transferOwnership(address _to) external onlyOwner() { 24 | pendingOwner = _to; 25 | 26 | emit OwnershipTransferRequested(owner, _to); 27 | } 28 | 29 | /** 30 | * @dev Allows an ownership transfer to be completed by the recipient. 31 | */ 32 | function acceptOwnership() external { 33 | require(msg.sender == pendingOwner, "Must be proposed owner"); 34 | 35 | address oldOwner = owner; 36 | owner = msg.sender; 37 | pendingOwner = address(0); 38 | 39 | emit OwnershipTransferred(oldOwner, msg.sender); 40 | } 41 | 42 | /** 43 | * @dev Reverts if called by anyone other than the contract owner. 44 | */ 45 | modifier onlyOwner() { 46 | require(msg.sender == owner, "Only callable by owner"); 47 | _; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /contracts/PreCoordinator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | import "./HashBridgeOracleClient.sol"; 5 | import "./HashBridgeOracleTokenReceiver.sol"; 6 | import "./Median.sol"; 7 | import "./vendor/Ownable.sol"; 8 | import "./vendor/SafeMathHashBridgeOracle.sol"; 9 | 10 | /** 11 | * @title PreCoordinator is a contract that builds on-chain service agreements 12 | * using the current architecture of 1 request to 1 oracle contract. 13 | * @dev This contract accepts requests as service agreement IDs and loops over 14 | * the corresponding list of oracles to create distinct requests to each one. 15 | */ 16 | contract PreCoordinator is 17 | HashBridgeOracleClient, 18 | Ownable, 19 | HashBridgeOracleRequestInterface, 20 | HashBridgeOracleTokenReceiver 21 | { 22 | using SafeMathHashBridgeOracle for uint256; 23 | 24 | uint256 private constant MAX_ORACLE_COUNT = 45; 25 | 26 | uint256 private globalNonce; 27 | 28 | struct ServiceAgreement { 29 | uint256 totalPayment; 30 | uint256 minResponses; 31 | address[] oracles; 32 | bytes32[] jobIds; 33 | uint256[] payments; 34 | } 35 | 36 | struct Requester { 37 | bytes4 callbackFunctionId; 38 | address sender; 39 | address callbackAddress; 40 | int256[] responses; 41 | } 42 | 43 | // Service Agreement ID => ServiceAgreement 44 | mapping(bytes32 => ServiceAgreement) internal serviceAgreements; 45 | // Local Request ID => Service Agreement ID 46 | mapping(bytes32 => bytes32) internal serviceAgreementRequests; 47 | // Requester's Request ID => Requester 48 | mapping(bytes32 => Requester) internal requesters; 49 | // Local Request ID => Requester's Request ID 50 | mapping(bytes32 => bytes32) internal requests; 51 | 52 | event NewServiceAgreement( 53 | bytes32 indexed saId, 54 | uint256 payment, 55 | uint256 minresponses 56 | ); 57 | event ServiceAgreementRequested( 58 | bytes32 indexed saId, 59 | bytes32 indexed requestId, 60 | uint256 payment 61 | ); 62 | event ServiceAgreementResponseReceived( 63 | bytes32 indexed saId, 64 | bytes32 indexed requestId, 65 | address indexed oracle, 66 | int256 answer 67 | ); 68 | event ServiceAgreementAnswerUpdated( 69 | bytes32 indexed saId, 70 | bytes32 indexed requestId, 71 | int256 answer 72 | ); 73 | event ServiceAgreementDeleted(bytes32 indexed saId); 74 | 75 | /** 76 | * @notice Deploy the contract with a specified address for the HBO 77 | * and Oracle contract addresses 78 | * @dev Sets the storage for the specified addresses 79 | * @param _hbo The address of the HBO token contract 80 | */ 81 | constructor(address _hbo) public { 82 | if (_hbo == address(0)) { 83 | setPublicHashBridgeOracleToken(); 84 | } else { 85 | setHashBridgeOracleToken(_hbo); 86 | } 87 | } 88 | 89 | /** 90 | * @notice Allows the owner of the contract to create new service agreements 91 | * with multiple oracles. Each oracle will have their own Job ID and can have 92 | * their own payment amount. 93 | * @dev The globalNonce keeps service agreement IDs unique. Assume one cannot 94 | * create the max uint256 number of service agreements in the same block. 95 | * @param _minResponses The minimum number of responses before the requesting 96 | * contract is called with the response data. 97 | * @param _oracles The list of oracle contract addresses. 98 | * @param _jobIds The corresponding list of Job IDs. 99 | * @param _payments The corresponding list of payment amounts. 100 | */ 101 | function createServiceAgreement( 102 | uint256 _minResponses, 103 | address[] calldata _oracles, 104 | bytes32[] calldata _jobIds, 105 | uint256[] calldata _payments 106 | ) external returns (bytes32 saId) { 107 | require(_minResponses > 0, "Min responses must be > 0"); 108 | require( 109 | _oracles.length == _jobIds.length && 110 | _oracles.length == _payments.length, 111 | "Unmet length" 112 | ); 113 | require( 114 | _oracles.length <= MAX_ORACLE_COUNT, 115 | "Cannot have more than 45 oracles" 116 | ); 117 | require(_oracles.length >= _minResponses, "Invalid min responses"); 118 | uint256 totalPayment; 119 | for (uint256 i = 0; i < _payments.length; i++) { 120 | totalPayment = totalPayment.add(_payments[i]); 121 | } 122 | saId = keccak256(abi.encodePacked(globalNonce, now)); 123 | globalNonce++; // yes, let it overflow 124 | serviceAgreements[saId] = ServiceAgreement( 125 | totalPayment, 126 | _minResponses, 127 | _oracles, 128 | _jobIds, 129 | _payments 130 | ); 131 | 132 | emit NewServiceAgreement(saId, totalPayment, _minResponses); 133 | } 134 | 135 | /** 136 | * @notice This is a helper function to retrieve the details of a service agreement 137 | * by its given service agreement ID. 138 | * @dev This function is used instead of the public mapping to return the values 139 | * of the arrays: oracles, jobIds, and payments. 140 | */ 141 | function getServiceAgreement(bytes32 _saId) 142 | external 143 | view 144 | returns ( 145 | uint256 totalPayment, 146 | uint256 minResponses, 147 | address[] memory oracles, 148 | bytes32[] memory jobIds, 149 | uint256[] memory payments 150 | ) 151 | { 152 | return ( 153 | serviceAgreements[_saId].totalPayment, 154 | serviceAgreements[_saId].minResponses, 155 | serviceAgreements[_saId].oracles, 156 | serviceAgreements[_saId].jobIds, 157 | serviceAgreements[_saId].payments 158 | ); 159 | } 160 | 161 | /** 162 | * @notice Returns the address of the HBO token 163 | * @dev This is the public implementation for hashBridgeOracleTokenAddress, which is 164 | * an internal method of the HashBridgeOracleClient contract 165 | */ 166 | function getHashBridgeOracleToken() public view override returns (address) { 167 | return hashBridgeOracleTokenAddress(); 168 | } 169 | 170 | /** 171 | * @notice Creates the HashBridgeOracle request 172 | * @dev Stores the hash of the params as the on-chain commitment for the request. 173 | * Emits OracleRequest event for the HashBridgeOracle node to detect. 174 | * @param _sender The sender of the request 175 | * @param _payment The amount of payment given (specified in wei) 176 | * @param _saId The Job Specification ID 177 | * @param _callbackAddress The callback address for the response 178 | * @param _callbackFunctionId The callback function ID for the response 179 | * @param _nonce The nonce sent by the requester 180 | * @param _data The CBOR payload of the request 181 | */ 182 | function oracleRequest( 183 | address _sender, 184 | uint256 _payment, 185 | bytes32 _saId, 186 | address _callbackAddress, 187 | bytes4 _callbackFunctionId, 188 | uint256 _nonce, 189 | uint256, 190 | bytes calldata _data 191 | ) external override onlyHBO checkCallbackAddress(_callbackAddress) { 192 | uint256 totalPayment = serviceAgreements[_saId].totalPayment; 193 | // this revert message does not bubble up 194 | require(_payment >= totalPayment, "Insufficient payment"); 195 | bytes32 callbackRequestId = 196 | keccak256(abi.encodePacked(_sender, _nonce)); 197 | require( 198 | requesters[callbackRequestId].sender == address(0), 199 | "Nonce already in-use" 200 | ); 201 | requesters[callbackRequestId].callbackFunctionId = _callbackFunctionId; 202 | requesters[callbackRequestId].callbackAddress = _callbackAddress; 203 | requesters[callbackRequestId].sender = _sender; 204 | createRequests(_saId, callbackRequestId, _data); 205 | if (_payment > totalPayment) { 206 | uint256 overage = _payment.sub(totalPayment); 207 | HashBridgeOracleTokenInterface _hbo = 208 | HashBridgeOracleTokenInterface(hashBridgeOracleTokenAddress()); 209 | assert(_hbo.transfer(_sender, overage)); 210 | } 211 | } 212 | 213 | /** 214 | * @dev Creates HashBridgeOracle requests to each oracle in the service agreement with the 215 | * same data payload supplied by the requester 216 | * @param _saId The service agreement ID 217 | * @param _incomingRequestId The requester-supplied request ID 218 | * @param _data The data payload (request parameters) to send to each oracle 219 | */ 220 | function createRequests( 221 | bytes32 _saId, 222 | bytes32 _incomingRequestId, 223 | bytes memory _data 224 | ) private { 225 | ServiceAgreement memory sa = serviceAgreements[_saId]; 226 | require(sa.minResponses > 0, "Invalid service agreement"); 227 | HashBridgeOracle.Request memory request; 228 | bytes32 outgoingRequestId; 229 | emit ServiceAgreementRequested( 230 | _saId, 231 | _incomingRequestId, 232 | sa.totalPayment 233 | ); 234 | for (uint256 i = 0; i < sa.oracles.length; i++) { 235 | request = buildHashBridgeOracleRequest( 236 | sa.jobIds[i], 237 | address(this), 238 | this.hashBridgeOracleCallback.selector 239 | ); 240 | request.setBuffer(_data); 241 | outgoingRequestId = sendHashBridgeOracleRequestTo( 242 | sa.oracles[i], 243 | request, 244 | sa.payments[i] 245 | ); 246 | requests[outgoingRequestId] = _incomingRequestId; 247 | serviceAgreementRequests[outgoingRequestId] = _saId; 248 | } 249 | } 250 | 251 | /** 252 | * @notice The fulfill method from requests created by this contract 253 | * @dev The recordHashBridgeOracleFulfillment protects this function from being called 254 | * by anyone other than the oracle address that the request was sent to 255 | * @param _requestId The ID that was generated for the request 256 | * @param _data The answer provided by the oracle 257 | */ 258 | function hashBridgeOracleCallback(bytes32 _requestId, int256 _data) 259 | external 260 | recordHashBridgeOracleFulfillment(_requestId) 261 | returns (bool) 262 | { 263 | ServiceAgreement memory sa = 264 | serviceAgreements[serviceAgreementRequests[_requestId]]; 265 | bytes32 cbRequestId = requests[_requestId]; 266 | bytes32 saId = serviceAgreementRequests[_requestId]; 267 | delete requests[_requestId]; 268 | delete serviceAgreementRequests[_requestId]; 269 | emit ServiceAgreementResponseReceived( 270 | saId, 271 | cbRequestId, 272 | msg.sender, 273 | _data 274 | ); 275 | requesters[cbRequestId].responses.push(_data); 276 | Requester memory req = requesters[cbRequestId]; 277 | if (req.responses.length == sa.oracles.length) 278 | delete requesters[cbRequestId]; 279 | bool success = true; 280 | if (req.responses.length == sa.minResponses) { 281 | int256 result = Median.calculate(req.responses); 282 | emit ServiceAgreementAnswerUpdated(saId, cbRequestId, result); 283 | // solhint-disable-next-line avoid-low-level-calls 284 | (success, ) = req.callbackAddress.call( 285 | abi.encodeWithSelector( 286 | req.callbackFunctionId, 287 | cbRequestId, 288 | result 289 | ) 290 | ); 291 | } 292 | return success; 293 | } 294 | 295 | /** 296 | * @notice Allows the owner to withdraw any HBO balance on the contract 297 | * @dev The only valid case for there to be remaining HBO on this contract 298 | * is if a user accidentally sent HBO directly to this contract's address. 299 | */ 300 | function withdrawHbo() external onlyOwner { 301 | HashBridgeOracleTokenInterface _hbo = 302 | HashBridgeOracleTokenInterface(hashBridgeOracleTokenAddress()); 303 | require( 304 | _hbo.transfer(msg.sender, _hbo.balanceOf(address(this))), 305 | "Unable to transfer" 306 | ); 307 | } 308 | 309 | /** 310 | * @notice Call this method if no response is received within 5 minutes 311 | * @param _requestId The ID that was generated for the request to cancel 312 | * @param _payment The payment specified for the request to cancel 313 | * @param _callbackFunctionId The bytes4 callback function ID specified for 314 | * the request to cancel 315 | * @param _expiration The expiration generated for the request to cancel 316 | */ 317 | function cancelOracleRequest( 318 | bytes32 _requestId, 319 | uint256 _payment, 320 | bytes4 _callbackFunctionId, 321 | uint256 _expiration 322 | ) external override { 323 | bytes32 cbRequestId = requests[_requestId]; 324 | delete requests[_requestId]; 325 | delete serviceAgreementRequests[_requestId]; 326 | Requester memory req = requesters[cbRequestId]; 327 | require(req.sender == msg.sender, "Only requester can cancel"); 328 | delete requesters[cbRequestId]; 329 | cancelHashBridgeOracleRequest( 330 | _requestId, 331 | _payment, 332 | _callbackFunctionId, 333 | _expiration 334 | ); 335 | HashBridgeOracleTokenInterface _hbo = 336 | HashBridgeOracleTokenInterface(hashBridgeOracleTokenAddress()); 337 | require(_hbo.transfer(req.sender, _payment), "Unable to transfer"); 338 | } 339 | 340 | /** 341 | * @dev Reverts if the callback address is the HBO token 342 | * @param _to The callback address 343 | */ 344 | modifier checkCallbackAddress(address _to) { 345 | require( 346 | _to != hashBridgeOracleTokenAddress(), 347 | "Cannot callback to HBO" 348 | ); 349 | _; 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /contracts/SafeMath128.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | /** 5 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 6 | * checks. 7 | * 8 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 9 | * in bugs, because programmers usually assume that an overflow raises an 10 | * error, which is the standard behavior in high level programming languages. 11 | * `SafeMath` restores this intuition by reverting the transaction when an 12 | * operation overflows. 13 | * 14 | * Using this library instead of the unchecked operations eliminates an entire 15 | * class of bugs, so it's recommended to use it always. 16 | * 17 | * This library is a version of Open Zeppelin's SafeMath, modified to support 18 | * unsigned 128 bit integers. 19 | */ 20 | library SafeMath128 { 21 | /** 22 | * @dev Returns the addition of two unsigned integers, reverting on 23 | * overflow. 24 | * 25 | * Counterpart to Solidity's `+` operator. 26 | * 27 | * Requirements: 28 | * - Addition cannot overflow. 29 | */ 30 | function add(uint128 a, uint128 b) internal pure returns (uint128) { 31 | uint128 c = a + b; 32 | require(c >= a, "SafeMath: addition overflow"); 33 | 34 | return c; 35 | } 36 | 37 | /** 38 | * @dev Returns the subtraction of two unsigned integers, reverting on 39 | * overflow (when the result is negative). 40 | * 41 | * Counterpart to Solidity's `-` operator. 42 | * 43 | * Requirements: 44 | * - Subtraction cannot overflow. 45 | */ 46 | function sub(uint128 a, uint128 b) internal pure returns (uint128) { 47 | require(b <= a, "SafeMath: subtraction overflow"); 48 | uint128 c = a - b; 49 | 50 | return c; 51 | } 52 | 53 | /** 54 | * @dev Returns the multiplication of two unsigned integers, reverting on 55 | * overflow. 56 | * 57 | * Counterpart to Solidity's `*` operator. 58 | * 59 | * Requirements: 60 | * - Multiplication cannot overflow. 61 | */ 62 | function mul(uint128 a, uint128 b) internal pure returns (uint128) { 63 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 64 | // benefit is lost if 'b' is also tested. 65 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 66 | if (a == 0) { 67 | return 0; 68 | } 69 | 70 | uint128 c = a * b; 71 | require(c / a == b, "SafeMath: multiplication overflow"); 72 | 73 | return c; 74 | } 75 | 76 | /** 77 | * @dev Returns the integer division of two unsigned integers. Reverts on 78 | * division by zero. The result is rounded towards zero. 79 | * 80 | * Counterpart to Solidity's `/` operator. Note: this function uses a 81 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 82 | * uses an invalid opcode to revert (consuming all remaining gas). 83 | * 84 | * Requirements: 85 | * - The divisor cannot be zero. 86 | */ 87 | function div(uint128 a, uint128 b) internal pure returns (uint128) { 88 | // Solidity only automatically asserts when dividing by 0 89 | require(b > 0, "SafeMath: division by zero"); 90 | uint128 c = a / b; 91 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 92 | 93 | return c; 94 | } 95 | 96 | /** 97 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 98 | * Reverts when dividing by zero. 99 | * 100 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 101 | * opcode (which leaves remaining gas untouched) while Solidity uses an 102 | * invalid opcode to revert (consuming all remaining gas). 103 | * 104 | * Requirements: 105 | * - The divisor cannot be zero. 106 | */ 107 | function mod(uint128 a, uint128 b) internal pure returns (uint128) { 108 | require(b != 0, "SafeMath: modulo by zero"); 109 | return a % b; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /contracts/SafeMath32.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | /** 5 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 6 | * checks. 7 | * 8 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 9 | * in bugs, because programmers usually assume that an overflow raises an 10 | * error, which is the standard behavior in high level programming languages. 11 | * `SafeMath` restores this intuition by reverting the transaction when an 12 | * operation overflows. 13 | * 14 | * Using this library instead of the unchecked operations eliminates an entire 15 | * class of bugs, so it's recommended to use it always. 16 | * 17 | * This library is a version of Open Zeppelin's SafeMath, modified to support 18 | * unsigned 32 bit integers. 19 | */ 20 | library SafeMath32 { 21 | /** 22 | * @dev Returns the addition of two unsigned integers, reverting on 23 | * overflow. 24 | * 25 | * Counterpart to Solidity's `+` operator. 26 | * 27 | * Requirements: 28 | * - Addition cannot overflow. 29 | */ 30 | function add(uint32 a, uint32 b) internal pure returns (uint32) { 31 | uint32 c = a + b; 32 | require(c >= a, "SafeMath: addition overflow"); 33 | 34 | return c; 35 | } 36 | 37 | /** 38 | * @dev Returns the subtraction of two unsigned integers, reverting on 39 | * overflow (when the result is negative). 40 | * 41 | * Counterpart to Solidity's `-` operator. 42 | * 43 | * Requirements: 44 | * - Subtraction cannot overflow. 45 | */ 46 | function sub(uint32 a, uint32 b) internal pure returns (uint32) { 47 | require(b <= a, "SafeMath: subtraction overflow"); 48 | uint32 c = a - b; 49 | 50 | return c; 51 | } 52 | 53 | /** 54 | * @dev Returns the multiplication of two unsigned integers, reverting on 55 | * overflow. 56 | * 57 | * Counterpart to Solidity's `*` operator. 58 | * 59 | * Requirements: 60 | * - Multiplication cannot overflow. 61 | */ 62 | function mul(uint32 a, uint32 b) internal pure returns (uint32) { 63 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 64 | // benefit is lost if 'b' is also tested. 65 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 66 | if (a == 0) { 67 | return 0; 68 | } 69 | 70 | uint32 c = a * b; 71 | require(c / a == b, "SafeMath: multiplication overflow"); 72 | 73 | return c; 74 | } 75 | 76 | /** 77 | * @dev Returns the integer division of two unsigned integers. Reverts on 78 | * division by zero. The result is rounded towards zero. 79 | * 80 | * Counterpart to Solidity's `/` operator. Note: this function uses a 81 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 82 | * uses an invalid opcode to revert (consuming all remaining gas). 83 | * 84 | * Requirements: 85 | * - The divisor cannot be zero. 86 | */ 87 | function div(uint32 a, uint32 b) internal pure returns (uint32) { 88 | // Solidity only automatically asserts when dividing by 0 89 | require(b > 0, "SafeMath: division by zero"); 90 | uint32 c = a / b; 91 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 92 | 93 | return c; 94 | } 95 | 96 | /** 97 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 98 | * Reverts when dividing by zero. 99 | * 100 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 101 | * opcode (which leaves remaining gas untouched) while Solidity uses an 102 | * invalid opcode to revert (consuming all remaining gas). 103 | * 104 | * Requirements: 105 | * - The divisor cannot be zero. 106 | */ 107 | function mod(uint32 a, uint32 b) internal pure returns (uint32) { 108 | require(b != 0, "SafeMath: modulo by zero"); 109 | return a % b; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /contracts/SafeMath64.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | /** 5 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 6 | * checks. 7 | * 8 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 9 | * in bugs, because programmers usually assume that an overflow raises an 10 | * error, which is the standard behavior in high level programming languages. 11 | * `SafeMath` restores this intuition by reverting the transaction when an 12 | * operation overflows. 13 | * 14 | * Using this library instead of the unchecked operations eliminates an entire 15 | * class of bugs, so it's recommended to use it always. 16 | * 17 | * This library is a version of Open Zeppelin's SafeMath, modified to support 18 | * unsigned 64 bit integers. 19 | */ 20 | library SafeMath64 { 21 | /** 22 | * @dev Returns the addition of two unsigned integers, reverting on 23 | * overflow. 24 | * 25 | * Counterpart to Solidity's `+` operator. 26 | * 27 | * Requirements: 28 | * - Addition cannot overflow. 29 | */ 30 | function add(uint64 a, uint64 b) internal pure returns (uint64) { 31 | uint64 c = a + b; 32 | require(c >= a, "SafeMath: addition overflow"); 33 | 34 | return c; 35 | } 36 | 37 | /** 38 | * @dev Returns the subtraction of two unsigned integers, reverting on 39 | * overflow (when the result is negative). 40 | * 41 | * Counterpart to Solidity's `-` operator. 42 | * 43 | * Requirements: 44 | * - Subtraction cannot overflow. 45 | */ 46 | function sub(uint64 a, uint64 b) internal pure returns (uint64) { 47 | require(b <= a, "SafeMath: subtraction overflow"); 48 | uint64 c = a - b; 49 | 50 | return c; 51 | } 52 | 53 | /** 54 | * @dev Returns the multiplication of two unsigned integers, reverting on 55 | * overflow. 56 | * 57 | * Counterpart to Solidity's `*` operator. 58 | * 59 | * Requirements: 60 | * - Multiplication cannot overflow. 61 | */ 62 | function mul(uint64 a, uint64 b) internal pure returns (uint64) { 63 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 64 | // benefit is lost if 'b' is also tested. 65 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 66 | if (a == 0) { 67 | return 0; 68 | } 69 | 70 | uint64 c = a * b; 71 | require(c / a == b, "SafeMath: multiplication overflow"); 72 | 73 | return c; 74 | } 75 | 76 | /** 77 | * @dev Returns the integer division of two unsigned integers. Reverts on 78 | * division by zero. The result is rounded towards zero. 79 | * 80 | * Counterpart to Solidity's `/` operator. Note: this function uses a 81 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 82 | * uses an invalid opcode to revert (consuming all remaining gas). 83 | * 84 | * Requirements: 85 | * - The divisor cannot be zero. 86 | */ 87 | function div(uint64 a, uint64 b) internal pure returns (uint64) { 88 | // Solidity only automatically asserts when dividing by 0 89 | require(b > 0, "SafeMath: division by zero"); 90 | uint64 c = a / b; 91 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 92 | 93 | return c; 94 | } 95 | 96 | /** 97 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 98 | * Reverts when dividing by zero. 99 | * 100 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 101 | * opcode (which leaves remaining gas untouched) while Solidity uses an 102 | * invalid opcode to revert (consuming all remaining gas). 103 | * 104 | * Requirements: 105 | * - The divisor cannot be zero. 106 | */ 107 | function mod(uint64 a, uint64 b) internal pure returns (uint64) { 108 | require(b != 0, "SafeMath: modulo by zero"); 109 | return a % b; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /contracts/SignedSafeMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | library SignedSafeMath { 5 | int256 private constant _INT256_MIN = -2**255; 6 | 7 | /** 8 | * @dev Multiplies two signed integers, reverts on overflow. 9 | */ 10 | function mul(int256 a, int256 b) internal pure returns (int256) { 11 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 12 | // benefit is lost if 'b' is also tested. 13 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 14 | if (a == 0) { 15 | return 0; 16 | } 17 | 18 | require( 19 | !(a == -1 && b == _INT256_MIN), 20 | "SignedSafeMath: multiplication overflow" 21 | ); 22 | 23 | int256 c = a * b; 24 | require(c / a == b, "SignedSafeMath: multiplication overflow"); 25 | 26 | return c; 27 | } 28 | 29 | /** 30 | * @dev Integer division of two signed integers truncating the quotient, reverts on division by zero. 31 | */ 32 | function div(int256 a, int256 b) internal pure returns (int256) { 33 | require(b != 0, "SignedSafeMath: division by zero"); 34 | require( 35 | !(b == -1 && a == _INT256_MIN), 36 | "SignedSafeMath: division overflow" 37 | ); 38 | 39 | int256 c = a / b; 40 | 41 | return c; 42 | } 43 | 44 | /** 45 | * @dev Subtracts two signed integers, reverts on overflow. 46 | */ 47 | function sub(int256 a, int256 b) internal pure returns (int256) { 48 | int256 c = a - b; 49 | require( 50 | (b >= 0 && c <= a) || (b < 0 && c > a), 51 | "SignedSafeMath: subtraction overflow" 52 | ); 53 | 54 | return c; 55 | } 56 | 57 | /** 58 | * @dev Adds two signed integers, reverts on overflow. 59 | */ 60 | function add(int256 a, int256 b) internal pure returns (int256) { 61 | int256 c = a + b; 62 | require( 63 | (b >= 0 && c >= a) || (b < 0 && c < a), 64 | "SignedSafeMath: addition overflow" 65 | ); 66 | 67 | return c; 68 | } 69 | 70 | /** 71 | * @notice Computes average of two signed integers, ensuring that the computation 72 | * doesn't overflow. 73 | * @dev If the result is not an integer, it is rounded towards zero. For example, 74 | * avg(-3, -4) = -3 75 | */ 76 | function avg(int256 _a, int256 _b) internal pure returns (int256) { 77 | if ((_a < 0 && _b > 0) || (_a > 0 && _b < 0)) { 78 | return add(_a, _b) / 2; 79 | } 80 | int256 remainder = ((_a % 2) + (_b % 2)) / 2; 81 | return add(add(_a / 2, _b / 2), remainder); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /contracts/SimpleReadAccessController.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "./SimpleWriteAccessController.sol"; 5 | 6 | /** 7 | * @title SimpleReadAccessController 8 | * @notice Gives access to: 9 | * - any externally owned account (note that offchain actors can always read 10 | * any contract storage regardless of onchain access control measures, so this 11 | * does not weaken the access control while improving usability) 12 | * - accounts explicitly added to an access list 13 | * @dev SimpleReadAccessController is not suitable for access controlling writes 14 | * since it grants any externally owned account access! See 15 | * SimpleWriteAccessController for that. 16 | */ 17 | contract SimpleReadAccessController is SimpleWriteAccessController { 18 | /** 19 | * @notice Returns the access of an address 20 | * @param _user The address to query 21 | */ 22 | function hasAccess(address _user, bytes memory _calldata) 23 | public 24 | view 25 | virtual 26 | override 27 | returns (bool) 28 | { 29 | return super.hasAccess(_user, _calldata) || _user == tx.origin; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /contracts/SimpleWriteAccessController.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "./Owned.sol"; 5 | import "./interfaces/AccessControllerInterface.sol"; 6 | 7 | /** 8 | * @title SimpleWriteAccessController 9 | * @notice Gives access to accounts explicitly added to an access list by the 10 | * controller's owner. 11 | * @dev does not make any special permissions for externally, see 12 | * SimpleReadAccessController for that. 13 | */ 14 | contract SimpleWriteAccessController is AccessControllerInterface, Owned { 15 | bool public checkEnabled; 16 | mapping(address => bool) internal accessList; 17 | 18 | event AddedAccess(address user); 19 | event RemovedAccess(address user); 20 | event CheckAccessEnabled(); 21 | event CheckAccessDisabled(); 22 | 23 | constructor() public { 24 | checkEnabled = true; 25 | } 26 | 27 | /** 28 | * @notice Returns the access of an address 29 | * @param _user The address to query 30 | */ 31 | function hasAccess(address _user, bytes memory) 32 | public 33 | view 34 | virtual 35 | override 36 | returns (bool) 37 | { 38 | return accessList[_user] || !checkEnabled; 39 | } 40 | 41 | /** 42 | * @notice Adds an address to the access list 43 | * @param _user The address to add 44 | */ 45 | function addAccess(address _user) external onlyOwner() { 46 | if (!accessList[_user]) { 47 | accessList[_user] = true; 48 | 49 | emit AddedAccess(_user); 50 | } 51 | } 52 | 53 | /** 54 | * @notice Removes an address from the access list 55 | * @param _user The address to remove 56 | */ 57 | function removeAccess(address _user) external onlyOwner() { 58 | if (accessList[_user]) { 59 | accessList[_user] = false; 60 | 61 | emit RemovedAccess(_user); 62 | } 63 | } 64 | 65 | /** 66 | * @notice makes the access check enforced 67 | */ 68 | function enableAccessCheck() external onlyOwner() { 69 | if (!checkEnabled) { 70 | checkEnabled = true; 71 | 72 | emit CheckAccessEnabled(); 73 | } 74 | } 75 | 76 | /** 77 | * @notice makes the access check unenforced 78 | */ 79 | function disableAccessCheck() external onlyOwner() { 80 | if (checkEnabled) { 81 | checkEnabled = false; 82 | 83 | emit CheckAccessDisabled(); 84 | } 85 | } 86 | 87 | /** 88 | * @dev reverts if the caller does not have access 89 | */ 90 | modifier checkAccess() { 91 | require(hasAccess(msg.sender, msg.data), "No access"); 92 | _; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /contracts/VRFConsumerBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | import "./vendor/SafeMathHashBridgeOracle.sol"; 5 | 6 | import "./interfaces/HashBridgeOracleTokenInterface.sol"; 7 | 8 | import "./VRFRequestIDBase.sol"; 9 | 10 | /** **************************************************************************** 11 | * @notice Interface for contracts using VRF randomness 12 | * ***************************************************************************** 13 | * @dev PURPOSE 14 | * 15 | * @dev Reggie the Random Oracle (not his real job) wants to provide randomness 16 | * @dev to Vera the verifier in such a way that Vera can be sure he's not 17 | * @dev making his output up to suit himself. Reggie provides Vera a public key 18 | * @dev to which he knows the secret key. Each time Vera provides a seed to 19 | * @dev Reggie, he gives back a value which is computed completely 20 | * @dev deterministically from the seed and the secret key. 21 | * 22 | * @dev Reggie provides a proof by which Vera can verify that the output was 23 | * @dev correctly computed once Reggie tells it to her, but without that proof, 24 | * @dev the output is indistinguishable to her from a uniform random sample 25 | * @dev from the output space. 26 | * 27 | * @dev The purpose of this contract is to make it easy for unrelated contracts 28 | * @dev to talk to Vera the verifier about the work Reggie is doing, to provide 29 | * @dev simple access to a verifiable source of randomness. 30 | * ***************************************************************************** 31 | * @dev USAGE 32 | * 33 | * @dev Calling contracts must inherit from VRFConsumerBase, and can 34 | * @dev initialize VRFConsumerBase's attributes in their constructor as 35 | * @dev shown: 36 | * 37 | * @dev contract VRFConsumer { 38 | * @dev constuctor(, address _vrfCoordinator, address _hbo) 39 | * @dev VRFConsumerBase(_vrfCoordinator, _hbo) public { 40 | * @dev 41 | * @dev } 42 | * @dev } 43 | * 44 | * @dev The oracle will have given you an ID for the VRF keypair they have 45 | * @dev committed to (let's call it keyHash), and have told you the minimum HBO 46 | * @dev price for VRF service. Make sure your contract has sufficient HBO, and 47 | * @dev call requestRandomness(keyHash, fee, seed), where seed is the input you 48 | * @dev want to generate randomness from. 49 | * 50 | * @dev Once the VRFCoordinator has received and validated the oracle's response 51 | * @dev to your request, it will call your contract's fulfillRandomness method. 52 | * 53 | * @dev The randomness argument to fulfillRandomness is the actual random value 54 | * @dev generated from your seed. 55 | * 56 | * @dev The requestId argument is generated from the keyHash and the seed by 57 | * @dev makeRequestId(keyHash, seed). If your contract could have concurrent 58 | * @dev requests open, you can use the requestId to track which seed is 59 | * @dev associated with which randomness. See VRFRequestIDBase.sol for more 60 | * @dev details. (See "SECURITY CONSIDERATIONS" for principles to keep in mind, 61 | * @dev if your contract could have multiple requests in flight simultaneously.) 62 | * 63 | * @dev Colliding `requestId`s are cryptographically impossible as long as seeds 64 | * @dev differ. (Which is critical to making unpredictable randomness! See the 65 | * @dev next section.) 66 | * 67 | * ***************************************************************************** 68 | * @dev SECURITY CONSIDERATIONS 69 | * 70 | * @dev A method with the ability to call your fulfillRandomness method directly 71 | * @dev could spoof a VRF response with any random value, so it's critical that 72 | * @dev it cannot be directly called by anything other than this base contract 73 | * @dev (specifically, by the VRFConsumerBase.rawFulfillRandomness method). 74 | * 75 | * @dev For your users to trust that your contract's random behavior is free 76 | * @dev from malicious interference, it's best if you can write it so that all 77 | * @dev behaviors implied by a VRF response are executed *during* your 78 | * @dev fulfillRandomness method. If your contract must store the response (or 79 | * @dev anything derived from it) and use it later, you must ensure that any 80 | * @dev user-significant behavior which depends on that stored value cannot be 81 | * @dev manipulated by a subsequent VRF request. 82 | * 83 | * @dev Similarly, both miners and the VRF oracle itself have some influence 84 | * @dev over the order in which VRF responses appear on the blockchain, so if 85 | * @dev your contract could have multiple VRF requests in flight simultaneously, 86 | * @dev you must ensure that the order in which the VRF responses arrive cannot 87 | * @dev be used to manipulate your contract's user-significant behavior. 88 | * 89 | * @dev Since the ultimate input to the VRF is mixed with the block hash of the 90 | * @dev block in which the request is made, user-provided seeds have no impact 91 | * @dev on its economic security properties. They are only included for API 92 | * @dev compatability with previous versions of this contract. 93 | * 94 | * @dev Since the block hash of the block which contains the requestRandomness 95 | * @dev call is mixed into the input to the VRF *last*, a sufficiently powerful 96 | * @dev miner could, in principle, fork the blockchain to evict the block 97 | * @dev containing the request, forcing the request to be included in a 98 | * @dev different block with a different hash, and therefore a different input 99 | * @dev to the VRF. However, such an attack would incur a substantial economic 100 | * @dev cost. This cost scales with the number of blocks the VRF oracle waits 101 | * @dev until it calls responds to a request. 102 | */ 103 | abstract contract VRFConsumerBase is VRFRequestIDBase { 104 | using SafeMathHashBridgeOracle for uint256; 105 | 106 | /** 107 | * @notice fulfillRandomness handles the VRF response. Your contract must 108 | * @notice implement it. See "SECURITY CONSIDERATIONS" above for important 109 | * @notice principles to keep in mind when implementing your fulfillRandomness 110 | * @notice method. 111 | * 112 | * @dev VRFConsumerBase expects its subcontracts to have a method with this 113 | * @dev signature, and will call it once it has verified the proof 114 | * @dev associated with the randomness. (It is triggered via a call to 115 | * @dev rawFulfillRandomness, below.) 116 | * 117 | * @param requestId The Id initially returned by requestRandomness 118 | * @param randomness the VRF output 119 | */ 120 | function fulfillRandomness(bytes32 requestId, uint256 randomness) 121 | internal 122 | virtual; 123 | 124 | /** 125 | * @notice requestRandomness initiates a request for VRF output given _seed 126 | * 127 | * @dev The fulfillRandomness method receives the output, once it's provided 128 | * @dev by the Oracle, and verified by the vrfCoordinator. 129 | * 130 | * @dev The _keyHash must already be registered with the VRFCoordinator, and 131 | * @dev the _fee must exceed the fee specified during registration of the 132 | * @dev _keyHash. 133 | * 134 | * @dev The _seed parameter is vestigial, and is kept only for API 135 | * @dev compatibility with older versions. It can't *hurt* to mix in some of 136 | * @dev your own randomness, here, but it's not necessary because the VRF 137 | * @dev oracle will mix the hash of the block containing your request into the 138 | * @dev VRF seed it ultimately uses. 139 | * 140 | * @param _keyHash ID of public key against which randomness is generated 141 | * @param _fee The amount of HBO to send with the request 142 | * @param _seed seed mixed into the input of the VRF. 143 | * 144 | * @return requestId unique ID for this request 145 | * 146 | * @dev The returned requestId can be used to distinguish responses to 147 | * @dev concurrent requests. It is passed as the first argument to 148 | * @dev fulfillRandomness. 149 | */ 150 | function requestRandomness( 151 | bytes32 _keyHash, 152 | uint256 _fee, 153 | uint256 _seed 154 | ) internal returns (bytes32 requestId) { 155 | HBO.transferAndCall(vrfCoordinator, _fee, abi.encode(_keyHash, _seed)); 156 | // This is the seed passed to VRFCoordinator. The oracle will mix this with 157 | // the hash of the block containing this request to obtain the seed/input 158 | // which is finally passed to the VRF cryptographic machinery. 159 | uint256 vRFSeed = 160 | makeVRFInputSeed(_keyHash, _seed, address(this), nonces[_keyHash]); 161 | // nonces[_keyHash] must stay in sync with 162 | // VRFCoordinator.nonces[_keyHash][this], which was incremented by the above 163 | // successful HBO.transferAndCall (in VRFCoordinator.randomnessRequest). 164 | // This provides protection against the user repeating their input seed, 165 | // which would result in a predictable/duplicate output, if multiple such 166 | // requests appeared in the same block. 167 | nonces[_keyHash] = nonces[_keyHash].add(1); 168 | return makeRequestId(_keyHash, vRFSeed); 169 | } 170 | 171 | HashBridgeOracleTokenInterface internal immutable HBO; 172 | address private immutable vrfCoordinator; 173 | 174 | // Nonces for each VRF key from which randomness has been requested. 175 | // 176 | // Must stay in sync with VRFCoordinator[_keyHash][this] 177 | /* keyHash */ 178 | /* nonce */ 179 | mapping(bytes32 => uint256) private nonces; 180 | 181 | /** 182 | * @param _vrfCoordinator address of VRFCoordinator contract 183 | * @param _hbo address of HBO token contract 184 | * 185 | */ 186 | constructor(address _vrfCoordinator, address _hbo) public { 187 | vrfCoordinator = _vrfCoordinator; 188 | HBO = HashBridgeOracleTokenInterface(_hbo); 189 | } 190 | 191 | // rawFulfillRandomness is called by VRFCoordinator when it receives a valid VRF 192 | // proof. rawFulfillRandomness then calls fulfillRandomness, after validating 193 | // the origin of the call 194 | function rawFulfillRandomness(bytes32 requestId, uint256 randomness) 195 | external 196 | { 197 | require( 198 | msg.sender == vrfCoordinator, 199 | "Only VRFCoordinator can fulfill" 200 | ); 201 | fulfillRandomness(requestId, randomness); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /contracts/VRFCoordinator.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | import "./vendor/SafeMathHashBridgeOracle.sol"; 5 | 6 | import "./interfaces/HashBridgeOracleTokenInterface.sol"; 7 | import "./interfaces/BlockHashStoreInterface.sol"; 8 | 9 | import "./VRF.sol"; 10 | import "./VRFRequestIDBase.sol"; 11 | import "./VRFConsumerBase.sol"; 12 | 13 | /** 14 | * @title VRFCoordinator coordinates on-chain verifiable-randomness requests 15 | * @title with off-chain responses 16 | */ 17 | contract VRFCoordinator is VRF, VRFRequestIDBase { 18 | using SafeMathHashBridgeOracle for uint256; 19 | 20 | HashBridgeOracleTokenInterface internal HBO; 21 | BlockHashStoreInterface internal blockHashStore; 22 | 23 | constructor(address _HBO, address _blockHashStore) public { 24 | HBO = HashBridgeOracleTokenInterface(_HBO); 25 | blockHashStore = BlockHashStoreInterface(_blockHashStore); 26 | } 27 | 28 | struct Callback { 29 | // Tracks an ongoing request 30 | address callbackContract; // Requesting contract, which will receive response 31 | // Amount of HBO paid at request time. Total HBO = 1e9 * 1e18 < 2^96, so 32 | // this representation is adequate, and saves a word of storage when this 33 | // field follows the 160-bit callbackContract address. 34 | uint96 randomnessFee; 35 | // Commitment to seed passed to oracle by this contract, and the number of 36 | // the block in which the request appeared. This is the keccak256 of the 37 | // concatenation of those values. Storing this commitment saves a word of 38 | // storage. 39 | bytes32 seedAndBlockNum; 40 | } 41 | 42 | struct ServiceAgreement { 43 | // Tracks oracle commitments to VRF service 44 | address vRFOracle; // Oracle committing to respond with VRF service 45 | uint96 fee; // Minimum payment for oracle response. Total HBO=1e9*1e18<2^96 46 | bytes32 jobID; // ID of corresponding HashBridgeOracle job in oracle's DB 47 | } 48 | 49 | /* (provingKey, seed) */ 50 | mapping(bytes32 => Callback) public callbacks; 51 | /* provingKey */ 52 | mapping(bytes32 => ServiceAgreement) public serviceAgreements; 53 | /* oracle */ 54 | /* HBO balance */ 55 | mapping(address => uint256) public withdrawableTokens; 56 | /* provingKey */ 57 | /* consumer */ 58 | mapping(bytes32 => mapping(address => uint256)) private nonces; 59 | 60 | // The oracle only needs the jobID to look up the VRF, but specifying public 61 | // key as well prevents a malicious oracle from inducing VRF outputs from 62 | // another oracle by reusing the jobID. 63 | event RandomnessRequest( 64 | bytes32 keyHash, 65 | uint256 seed, 66 | bytes32 indexed jobID, 67 | address sender, 68 | uint256 fee, 69 | bytes32 requestID 70 | ); 71 | 72 | event NewServiceAgreement(bytes32 keyHash, uint256 fee); 73 | 74 | event RandomnessRequestFulfilled(bytes32 requestId, uint256 output); 75 | 76 | /** 77 | * @notice Commits calling address to serve randomness 78 | * @param _fee minimum HBO payment required to serve randomness 79 | * @param _oracle the address of the HashBridgeOracle node with the proving key and job 80 | * @param _publicProvingKey public key used to prove randomness 81 | * @param _jobID ID of the corresponding HashBridgeOracle job in the oracle's db 82 | */ 83 | function registerProvingKey( 84 | uint256 _fee, 85 | address _oracle, 86 | uint256[2] calldata _publicProvingKey, 87 | bytes32 _jobID 88 | ) external { 89 | bytes32 keyHash = hashOfKey(_publicProvingKey); 90 | address oldVRFOracle = serviceAgreements[keyHash].vRFOracle; 91 | require(oldVRFOracle == address(0), "please register a new key"); 92 | require(_oracle != address(0), "_oracle must not be 0x0"); 93 | serviceAgreements[keyHash].vRFOracle = _oracle; 94 | serviceAgreements[keyHash].jobID = _jobID; 95 | // Yes, this revert message doesn't fit in a word 96 | require( 97 | _fee <= 1e9 ether, 98 | "you can't charge more than all the HBO in the world, greedy" 99 | ); 100 | serviceAgreements[keyHash].fee = uint96(_fee); 101 | emit NewServiceAgreement(keyHash, _fee); 102 | } 103 | 104 | /** 105 | * @notice Called by HBO.transferAndCall, on successful HBO transfer 106 | * 107 | * @dev To invoke this, use the requestRandomness method in VRFConsumerBase. 108 | * 109 | * @dev The VRFCoordinator will call back to the calling contract when the 110 | * @dev oracle responds, on the method fulfillRandomness. See 111 | * @dev VRFConsumerBase.fulfilRandomness for its signature. Your consuming 112 | * @dev contract should inherit from VRFConsumerBase, and implement 113 | * @dev fulfilRandomness. 114 | * 115 | * @param _sender address: who sent the HBO (must be a contract) 116 | * @param _fee amount of HBO sent 117 | * @param _data abi-encoded call to randomnessRequest 118 | */ 119 | function onTokenTransfer( 120 | address _sender, 121 | uint256 _fee, 122 | bytes memory _data 123 | ) public onlyHBO { 124 | (bytes32 keyHash, uint256 seed) = abi.decode(_data, (bytes32, uint256)); 125 | randomnessRequest(keyHash, seed, _fee, _sender); 126 | } 127 | 128 | /** 129 | * @notice creates the HashBridgeOracle request for randomness 130 | * 131 | * @param _keyHash ID of the VRF public key against which to generate output 132 | * @param _consumerSeed Input to the VRF, from which randomness is generated 133 | * @param _feePaid Amount of HBO sent with request. Must exceed fee for key 134 | * @param _sender Requesting contract; to be called back with VRF output 135 | * 136 | * @dev _consumerSeed is mixed with key hash, sender address and nonce to 137 | * @dev obtain preSeed, which is passed to VRF oracle, which mixes it with the 138 | * @dev hash of the block containing this request, to compute the final seed. 139 | * 140 | * @dev The requestId used to store the request data is constructed from the 141 | * @dev preSeed and keyHash. 142 | */ 143 | function randomnessRequest( 144 | bytes32 _keyHash, 145 | uint256 _consumerSeed, 146 | uint256 _feePaid, 147 | address _sender 148 | ) internal sufficientHBO(_feePaid, _keyHash) { 149 | uint256 nonce = nonces[_keyHash][_sender]; 150 | uint256 preSeed = 151 | makeVRFInputSeed(_keyHash, _consumerSeed, _sender, nonce); 152 | bytes32 requestId = makeRequestId(_keyHash, preSeed); 153 | // Cryptographically guaranteed by preSeed including an increasing nonce 154 | assert(callbacks[requestId].callbackContract == address(0)); 155 | callbacks[requestId].callbackContract = _sender; 156 | assert(_feePaid < 1e27); // Total HBO fits in uint96 157 | callbacks[requestId].randomnessFee = uint96(_feePaid); 158 | callbacks[requestId].seedAndBlockNum = keccak256( 159 | abi.encodePacked(preSeed, block.number) 160 | ); 161 | emit RandomnessRequest( 162 | _keyHash, 163 | preSeed, 164 | serviceAgreements[_keyHash].jobID, 165 | _sender, 166 | _feePaid, 167 | requestId 168 | ); 169 | nonces[_keyHash][_sender] = nonces[_keyHash][_sender].add(1); 170 | } 171 | 172 | // Offsets into fulfillRandomnessRequest's _proof of various values 173 | // 174 | // Public key. Skips byte array's length prefix. 175 | uint256 public constant PUBLIC_KEY_OFFSET = 0x20; 176 | // Seed is 7th word in proof, plus word for length, (6+1)*0x20=0xe0 177 | uint256 public constant PRESEED_OFFSET = 0xe0; 178 | 179 | /** 180 | * @notice Called by the HashBridgeOracle node to fulfill requests 181 | * 182 | * @param _proof the proof of randomness. Actual random output built from this 183 | * 184 | * @dev The structure of _proof corresponds to vrf.MarshaledOnChainResponse, 185 | * @dev in the node source code. I.e., it is a vrf.MarshaledProof with the 186 | * @dev seed replaced by the preSeed, followed by the hash of the requesting 187 | * @dev block. 188 | */ 189 | function fulfillRandomnessRequest(bytes memory _proof) public { 190 | ( 191 | bytes32 currentKeyHash, 192 | Callback memory callback, 193 | bytes32 requestId, 194 | uint256 randomness 195 | ) = getRandomnessFromProof(_proof); 196 | 197 | // Pay oracle 198 | address oadd = serviceAgreements[currentKeyHash].vRFOracle; 199 | withdrawableTokens[oadd] = withdrawableTokens[oadd].add( 200 | callback.randomnessFee 201 | ); 202 | 203 | // Forget request. Must precede callback (prevents reentrancy) 204 | delete callbacks[requestId]; 205 | callBackWithRandomness( 206 | requestId, 207 | randomness, 208 | callback.callbackContract 209 | ); 210 | 211 | emit RandomnessRequestFulfilled(requestId, randomness); 212 | } 213 | 214 | function callBackWithRandomness( 215 | bytes32 requestId, 216 | uint256 randomness, 217 | address consumerContract 218 | ) internal { 219 | // Dummy variable; allows access to method selector in next line. See 220 | // https://github.com/ethereum/solidity/issues/3506#issuecomment-553727797 221 | VRFConsumerBase v; 222 | bytes memory resp = 223 | abi.encodeWithSelector( 224 | v.rawFulfillRandomness.selector, 225 | requestId, 226 | randomness 227 | ); 228 | // The bound b here comes from https://eips.ethereum.org/EIPS/eip-150. The 229 | // actual gas available to the consuming contract will be b-floor(b/64). 230 | // This is chosen to leave the consuming contract ~200k gas, after the cost 231 | // of the call itself. 232 | uint256 b = 206000; 233 | require(gasleft() >= b, "not enough gas for consumer"); 234 | // A low-level call is necessary, here, because we don't want the consuming 235 | // contract to be able to revert this execution, and thus deny the oracle 236 | // payment for a valid randomness response. This also necessitates the above 237 | // check on the gasleft, as otherwise there would be no indication if the 238 | // callback method ran out of gas. 239 | // 240 | // solhint-disable-next-line avoid-low-level-calls 241 | (bool success, ) = consumerContract.call(resp); 242 | // Avoid unused-local-variable warning. (success is only present to prevent 243 | // a warning that the return value of consumerContract.call is unused.) 244 | (success); 245 | } 246 | 247 | function getRandomnessFromProof(bytes memory _proof) 248 | internal 249 | view 250 | returns ( 251 | bytes32 currentKeyHash, 252 | Callback memory callback, 253 | bytes32 requestId, 254 | uint256 randomness 255 | ) 256 | { 257 | // blockNum follows proof, which follows length word (only direct-number 258 | // constants are allowed in assembly, so have to compute this in code) 259 | uint256 BLOCKNUM_OFFSET = 0x20 + PROOF_LENGTH; 260 | // _proof.length skips the initial length word, so not including the 261 | // blocknum in this length check balances out. 262 | require(_proof.length == BLOCKNUM_OFFSET, "wrong proof length"); 263 | uint256[2] memory publicKey; 264 | uint256 preSeed; 265 | uint256 blockNum; 266 | assembly { 267 | // solhint-disable-line no-inline-assembly 268 | publicKey := add(_proof, PUBLIC_KEY_OFFSET) 269 | preSeed := mload(add(_proof, PRESEED_OFFSET)) 270 | blockNum := mload(add(_proof, BLOCKNUM_OFFSET)) 271 | } 272 | currentKeyHash = hashOfKey(publicKey); 273 | requestId = makeRequestId(currentKeyHash, preSeed); 274 | callback = callbacks[requestId]; 275 | require( 276 | callback.callbackContract != address(0), 277 | "no corresponding request" 278 | ); 279 | require( 280 | callback.seedAndBlockNum == 281 | keccak256(abi.encodePacked(preSeed, blockNum)), 282 | "wrong preSeed or block num" 283 | ); 284 | 285 | bytes32 blockHash = blockhash(blockNum); 286 | if (blockHash == bytes32(0)) { 287 | blockHash = blockHashStore.getBlockhash(blockNum); 288 | require(blockHash != bytes32(0), "please prove blockhash"); 289 | } 290 | // The seed actually used by the VRF machinery, mixing in the blockhash 291 | uint256 actualSeed = 292 | uint256(keccak256(abi.encodePacked(preSeed, blockHash))); 293 | // solhint-disable-next-line no-inline-assembly 294 | assembly { 295 | // Construct the actual proof from the remains of _proof 296 | mstore(add(_proof, PRESEED_OFFSET), actualSeed) 297 | mstore(_proof, PROOF_LENGTH) 298 | } 299 | randomness = VRF.randomValueFromVRFProof(_proof); // Reverts on failure 300 | } 301 | 302 | /** 303 | * @dev Allows the oracle operator to withdraw their HBO 304 | * @param _recipient is the address the funds will be sent to 305 | * @param _amount is the amount of HBO transferred from the Coordinator contract 306 | */ 307 | function withdraw(address _recipient, uint256 _amount) 308 | external 309 | hasAvailableFunds(_amount) 310 | { 311 | withdrawableTokens[msg.sender] = withdrawableTokens[msg.sender].sub( 312 | _amount 313 | ); 314 | assert(HBO.transfer(_recipient, _amount)); 315 | } 316 | 317 | /** 318 | * @notice Returns the serviceAgreements key associated with this public key 319 | * @param _publicKey the key to return the address for 320 | */ 321 | function hashOfKey(uint256[2] memory _publicKey) 322 | public 323 | pure 324 | returns (bytes32) 325 | { 326 | return keccak256(abi.encodePacked(_publicKey)); 327 | } 328 | 329 | /** 330 | * @dev Reverts if amount is not at least what was agreed upon in the service agreement 331 | * @param _feePaid The payment for the request 332 | * @param _keyHash The key which the request is for 333 | */ 334 | modifier sufficientHBO(uint256 _feePaid, bytes32 _keyHash) { 335 | require( 336 | _feePaid >= serviceAgreements[_keyHash].fee, 337 | "Below agreed payment" 338 | ); 339 | _; 340 | } 341 | 342 | /** 343 | * @dev Reverts if not sent from the HBO token 344 | */ 345 | modifier onlyHBO() { 346 | require(msg.sender == address(HBO), "Must use HBO token"); 347 | _; 348 | } 349 | 350 | /** 351 | * @dev Reverts if amount requested is greater than withdrawable balance 352 | * @param _amount The given amount to compare to `withdrawableTokens` 353 | */ 354 | modifier hasAvailableFunds(uint256 _amount) { 355 | require( 356 | withdrawableTokens[msg.sender] >= _amount, 357 | "can't withdraw more than balance" 358 | ); 359 | _; 360 | } 361 | } 362 | -------------------------------------------------------------------------------- /contracts/VRFRequestIDBase.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | contract VRFRequestIDBase { 5 | /** 6 | * @notice returns the seed which is actually input to the VRF coordinator 7 | * 8 | * @dev To prevent repetition of VRF output due to repetition of the 9 | * @dev user-supplied seed, that seed is combined in a hash with the 10 | * @dev user-specific nonce, and the address of the consuming contract. The 11 | * @dev risk of repetition is mostly mitigated by inclusion of a blockhash in 12 | * @dev the final seed, but the nonce does protect against repetition in 13 | * @dev requests which are included in a single block. 14 | * 15 | * @param _userSeed VRF seed input provided by user 16 | * @param _requester Address of the requesting contract 17 | * @param _nonce User-specific nonce at the time of the request 18 | */ 19 | function makeVRFInputSeed( 20 | bytes32 _keyHash, 21 | uint256 _userSeed, 22 | address _requester, 23 | uint256 _nonce 24 | ) internal pure returns (uint256) { 25 | return 26 | uint256( 27 | keccak256(abi.encode(_keyHash, _userSeed, _requester, _nonce)) 28 | ); 29 | } 30 | 31 | /** 32 | * @notice Returns the id for this request 33 | * @param _keyHash The serviceAgreement ID to be used for this request 34 | * @param _vRFInputSeed The seed to be passed directly to the VRF 35 | * @return The id for this request 36 | * 37 | * @dev Note that _vRFInputSeed is not the seed passed by the consuming 38 | * @dev contract, but the one generated by makeVRFInputSeed 39 | */ 40 | function makeRequestId(bytes32 _keyHash, uint256 _vRFInputSeed) 41 | internal 42 | pure 43 | returns (bytes32) 44 | { 45 | return keccak256(abi.encodePacked(_keyHash, _vRFInputSeed)); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /contracts/dev/BlockhashStore.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | /** 5 | * @title BlockhashStore 6 | * @notice This contract provides a way to access blockhashes older than 7 | * the 256 block limit imposed by the BLOCKHASH opcode. 8 | * You may assume that any blockhash stored by the contract is correct. 9 | * Note that the contract depends on the format of serialized Ethereum 10 | * blocks. If a future hardfork of Ethereum changes that format, the 11 | * logic in this contract may become incorrect and an updated version 12 | * would have to be deployed. 13 | */ 14 | contract BlockhashStore { 15 | 16 | mapping(uint => bytes32) internal s_blockhashes; 17 | 18 | /** 19 | * @notice stores blockhash of a given block, assuming it is available through BLOCKHASH 20 | * @param n the number of the block whose blockhash should be stored 21 | */ 22 | function store(uint256 n) public { 23 | bytes32 h = blockhash(n); 24 | require(h != 0x0, "blockhash(n) failed"); 25 | s_blockhashes[n] = h; 26 | } 27 | 28 | 29 | /** 30 | * @notice stores blockhash of the earliest block still available through BLOCKHASH. 31 | */ 32 | function storeEarliest() external { 33 | store(block.number - 256); 34 | } 35 | 36 | /** 37 | * @notice stores blockhash after verifying blockheader of child/subsequent block 38 | * @param n the number of the block whose blockhash should be stored 39 | * @param header the rlp-encoded blockheader of block n+1. We verify its correctness by checking 40 | * that it hashes to a stored blockhash, and then extract parentHash to get the n-th blockhash. 41 | */ 42 | function storeVerifyHeader(uint256 n, bytes memory header) public { 43 | require(keccak256(header) == s_blockhashes[n + 1], "header has unknown blockhash"); 44 | 45 | // At this point, we know that header is the correct blockheader for block n+1. 46 | 47 | // The header is an rlp-encoded list. The head item of that list is the 32-byte blockhash of the parent block. 48 | // Based on how rlp works, we know that blockheaders always have the following form: 49 | // 0xf9____a0PARENTHASH... 50 | // ^ ^ ^ 51 | // | | | 52 | // | | +--- PARENTHASH is 32 bytes. rlpenc(PARENTHASH) is 0xa || PARENTHASH. 53 | // | | 54 | // | +--- 2 bytes containing the sum of the lengths of the encoded list items 55 | // | 56 | // +--- 0xf9 because we have a list and (sum of lengths of encoded list items) fits exactly into two bytes. 57 | // 58 | // As a consequence, the PARENTHASH is always at offset 4 of the rlp-encoded block header. 59 | 60 | bytes32 parentHash; 61 | assembly { 62 | parentHash := mload(add(header, 36)) // 36 = 32 byte offset for length prefix of ABI-encoded array 63 | // + 4 byte offset of PARENTHASH (see above) 64 | } 65 | 66 | s_blockhashes[n] = parentHash; 67 | } 68 | 69 | /** 70 | * @notice gets a blockhash from the store. If no hash is known, this function reverts. 71 | * @param n the number of the block whose blockhash should be returned 72 | */ 73 | function getBlockhash(uint256 n) external view returns (bytes32) { 74 | bytes32 h = s_blockhashes[n]; 75 | require(h != 0x0, "blockhash not found in store"); 76 | return h; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /contracts/examples/OracleDemo.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.6.0; 2 | 3 | import "../HashBridgeOracleClient.sol"; 4 | 5 | contract APIConsumer is HashBridgeOracleClient { 6 | 7 | uint256 public volume; 8 | 9 | address private oracle; 10 | bytes32 private jobId; 11 | uint256 private fee; 12 | 13 | constructor(address _oracle, address _hbo) public { 14 | setHashBridgeOracleToken(_hbo); 15 | oracle = _oracle; 16 | jobId = "29fa9aa13bf1468788b7cc4a500a45b8"; 17 | fee = 0.1 * 10 ** 18; // 0.1 HBO 18 | } 19 | 20 | /** 21 | * Create a HashBridge request to retrieve API response, find the target 22 | * data, then multiply by 1000000000000000000 (to remove decimal places from data). 23 | */ 24 | function requestVolumeData() public returns (bytes32 requestId) 25 | { 26 | HashBridgeOracle.Request memory request = buildHashBridgeOracleRequest(jobId, address(this), this.fulfill.selector); 27 | 28 | // Set the URL to perform the GET request on 29 | request.add("get", "https://min-api.cryptocompare.com/data/pricemultifull?fsyms=ETH&tsyms=USD"); 30 | request.add("path", "RAW.ETH.USD.VOLUME24HOUR"); 31 | 32 | // Multiply the result by 1000000000000000000 to remove decimals 33 | int timesAmount = 10**18; 34 | request.addInt("times", timesAmount); 35 | 36 | // Sends the request 37 | return sendHashBridgeOracleRequestTo(oracle, request, fee); 38 | } 39 | 40 | /** 41 | * Receive the response in the form of uint256 42 | */ 43 | function fulfill(bytes32 _requestId, uint256 _volume) public recordHashBridgeOracleFulfillment(_requestId) 44 | { 45 | volume = _volume; 46 | } 47 | } -------------------------------------------------------------------------------- /contracts/examples/VRFD20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | import "../VRFConsumerBase.sol"; 5 | import "../Owned.sol"; 6 | 7 | /** 8 | * @notice A HashBridgeOracle VRF consumer which uses randomness to mimic the rolling 9 | * of a 20 sided die 10 | * @dev This is only an example implementation and not necessarily suitable for mainnet. 11 | */ 12 | contract VRFD20 is VRFConsumerBase, Owned { 13 | using SafeMathHashBridgeOracle for uint256; 14 | 15 | uint256 private constant ROLL_IN_PROGRESS = 42; 16 | 17 | bytes32 private s_keyHash; 18 | uint256 private s_fee; 19 | mapping(bytes32 => address) private s_rollers; 20 | mapping(address => uint256) private s_results; 21 | 22 | event DiceRolled(bytes32 indexed requestId, address indexed roller); 23 | event DiceLanded(bytes32 indexed requestId, uint256 indexed result); 24 | 25 | /** 26 | * @notice Constructor inherits VRFConsumerBase 27 | * 28 | * @dev NETWORK: KOVAN 29 | * @dev HashBridgeOracle VRF Coordinator address: 0xdD3782915140c8f3b190B5D67eAc6dc5760C46E9 30 | * @dev HBO token address: 0xa36085F69e2889c224210F603D836748e7dC0088 31 | * @dev Key Hash: 0x6c3699283bda56ad74f6b855546325b68d482e983852a7a82979cc4807b641f4 32 | * @dev Fee: 0.1 HBO (100000000000000000) 33 | * 34 | * @param vrfCoordinator address of the VRF Coordinator 35 | * @param hbo address of the HBO token 36 | * @param keyHash bytes32 representing the hash of the VRF job 37 | * @param fee uint256 fee to pay the VRF oracle 38 | */ 39 | constructor( 40 | address vrfCoordinator, 41 | address hbo, 42 | bytes32 keyHash, 43 | uint256 fee 44 | ) public VRFConsumerBase(vrfCoordinator, hbo) { 45 | s_keyHash = keyHash; 46 | s_fee = fee; 47 | } 48 | 49 | /** 50 | * @notice Requests randomness from a user-provided seed 51 | * @dev Warning: if the VRF response is delayed, avoid calling requestRandomness repeatedly 52 | * as that would give miners/VRF operators latitude about which VRF response arrives first. 53 | * @dev You must review your implementation details with extreme care. 54 | * 55 | * @param userProvidedSeed uint256 unpredictable seed 56 | * @param roller address of the roller 57 | */ 58 | function rollDice(uint256 userProvidedSeed, address roller) 59 | public 60 | onlyOwner 61 | returns (bytes32 requestId) 62 | { 63 | require( 64 | HBO.balanceOf(address(this)) >= s_fee, 65 | "Not enough HBO to pay fee" 66 | ); 67 | require(s_results[roller] == 0, "Already rolled"); 68 | requestId = requestRandomness(s_keyHash, s_fee, userProvidedSeed); 69 | s_rollers[requestId] = roller; 70 | s_results[roller] = ROLL_IN_PROGRESS; 71 | emit DiceRolled(requestId, roller); 72 | } 73 | 74 | /** 75 | * @notice Callback function used by VRF Coordinator to return the random number 76 | * to this contract. 77 | * @dev Some action on the contract state should be taken here, like storing the result. 78 | * @dev WARNING: take care to avoid having multiple VRF requests in flight if their order of arrival would result 79 | * in contract states with different outcomes. Otherwise miners or the VRF operator would could take advantage 80 | * by controlling the order. 81 | * @dev The VRF Coordinator will only send this function verified responses, and the parent VRFConsumerBase 82 | * contract ensures that this method only receives randomness from the designated VRFCoordinator. 83 | * 84 | * @param requestId bytes32 85 | * @param randomness The random result returned by the oracle 86 | */ 87 | function fulfillRandomness(bytes32 requestId, uint256 randomness) 88 | internal 89 | override 90 | { 91 | uint256 d20Value = randomness.mod(20).add(1); 92 | s_results[s_rollers[requestId]] = d20Value; 93 | emit DiceLanded(requestId, d20Value); 94 | } 95 | 96 | /** 97 | * @notice Get the house assigned to the player once the address has rolled 98 | * @param player address 99 | * @return house as a string 100 | */ 101 | function house(address player) public view returns (string memory) { 102 | require(s_results[player] != 0, "Dice not rolled"); 103 | require(s_results[player] != ROLL_IN_PROGRESS, "Roll in progress"); 104 | return getHouseName(s_results[player]); 105 | } 106 | 107 | /** 108 | * @notice Withdraw HBO from this contract. 109 | * @dev this is an example only, and in a real contract withdrawals should 110 | * happen according to the established withdrawal pattern: 111 | * https://docs.soliditylang.org/en/v0.4.24/common-patterns.html#withdrawal-from-contracts 112 | * @param to the address to withdraw HBO to 113 | * @param value the amount of HBO to withdraw 114 | */ 115 | function withdrawHBO(address to, uint256 value) public onlyOwner { 116 | require(HBO.transfer(to, value), "Not enough HBO"); 117 | } 118 | 119 | /** 120 | * @notice Set the key hash for the oracle 121 | * 122 | * @param keyHash bytes32 123 | */ 124 | function setKeyHash(bytes32 keyHash) public onlyOwner { 125 | s_keyHash = keyHash; 126 | } 127 | 128 | /** 129 | * @notice Get the current key hash 130 | * 131 | * @return bytes32 132 | */ 133 | function keyHash() public view returns (bytes32) { 134 | return s_keyHash; 135 | } 136 | 137 | /** 138 | * @notice Set the oracle fee for requesting randomness 139 | * 140 | * @param fee uint256 141 | */ 142 | function setFee(uint256 fee) public onlyOwner { 143 | s_fee = fee; 144 | } 145 | 146 | /** 147 | * @notice Get the current fee 148 | * 149 | * @return uint256 150 | */ 151 | function fee() public view returns (uint256) { 152 | return s_fee; 153 | } 154 | 155 | /** 156 | * @notice Get the house namne from the id 157 | * @param id uint256 158 | * @return house name string 159 | */ 160 | function getHouseName(uint256 id) private pure returns (string memory) { 161 | string[20] memory houseNames = 162 | [ 163 | "Targaryen", 164 | "Lannister", 165 | "Stark", 166 | "Tyrell", 167 | "Baratheon", 168 | "Martell", 169 | "Tully", 170 | "Bolton", 171 | "Greyjoy", 172 | "Arryn", 173 | "Frey", 174 | "Mormont", 175 | "Tarley", 176 | "Dayne", 177 | "Umber", 178 | "Valeryon", 179 | "Manderly", 180 | "Clegane", 181 | "Glover", 182 | "Karstark" 183 | ]; 184 | return houseNames[id.sub(1)]; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /contracts/interfaces/AccessControllerInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface AccessControllerInterface { 5 | function hasAccess(address user, bytes calldata data) 6 | external 7 | view 8 | returns (bool); 9 | } 10 | -------------------------------------------------------------------------------- /contracts/interfaces/AggregatorInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.0; 3 | 4 | interface AggregatorInterface { 5 | function latestAnswer() external view returns (int256); 6 | 7 | function latestTimestamp() external view returns (uint256); 8 | 9 | function latestRound() external view returns (uint256); 10 | 11 | function getAnswer(uint256 roundId) external view returns (int256); 12 | 13 | function getTimestamp(uint256 roundId) external view returns (uint256); 14 | 15 | event AnswerUpdated( 16 | int256 indexed current, 17 | uint256 indexed roundId, 18 | uint256 updatedAt 19 | ); 20 | event NewRound( 21 | uint256 indexed roundId, 22 | address indexed startedBy, 23 | uint256 startedAt 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /contracts/interfaces/AggregatorV2V3Interface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.0; 3 | 4 | import "./AggregatorInterface.sol"; 5 | import "./AggregatorV3Interface.sol"; 6 | 7 | interface AggregatorV2V3Interface is 8 | AggregatorInterface, 9 | AggregatorV3Interface 10 | {} 11 | -------------------------------------------------------------------------------- /contracts/interfaces/AggregatorV3Interface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.6.0; 3 | 4 | interface AggregatorV3Interface { 5 | function decimals() external view returns (uint8); 6 | 7 | function description() external view returns (string memory); 8 | 9 | function version() external view returns (uint256); 10 | 11 | // getRoundData and latestRoundData should both raise "No data present" 12 | // if they do not have data to report, instead of returning unset values 13 | // which could be misinterpreted as actual reported values. 14 | function getRoundData(uint80 _roundId) 15 | external 16 | view 17 | returns ( 18 | uint80 roundId, 19 | int256 answer, 20 | uint256 startedAt, 21 | uint256 updatedAt, 22 | uint80 answeredInRound 23 | ); 24 | 25 | function latestRoundData() 26 | external 27 | view 28 | returns ( 29 | uint80 roundId, 30 | int256 answer, 31 | uint256 startedAt, 32 | uint256 updatedAt, 33 | uint80 answeredInRound 34 | ); 35 | } 36 | -------------------------------------------------------------------------------- /contracts/interfaces/AggregatorValidatorInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface AggregatorValidatorInterface { 5 | function validate( 6 | uint256 previousRoundId, 7 | int256 previousAnswer, 8 | uint256 currentRoundId, 9 | int256 currentAnswer 10 | ) external returns (bool); 11 | } 12 | -------------------------------------------------------------------------------- /contracts/interfaces/BlockHashStoreInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity 0.6.6; 3 | 4 | interface BlockHashStoreInterface { 5 | function getBlockhash(uint256 number) external view returns (bytes32); 6 | } 7 | -------------------------------------------------------------------------------- /contracts/interfaces/ENSInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface ENSInterface { 5 | // Logged when the owner of a node assigns a new owner to a subnode. 6 | event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner); 7 | 8 | // Logged when the owner of a node transfers ownership to a new account. 9 | event Transfer(bytes32 indexed node, address owner); 10 | 11 | // Logged when the resolver for a node changes. 12 | event NewResolver(bytes32 indexed node, address resolver); 13 | 14 | // Logged when the TTL of a node changes 15 | event NewTTL(bytes32 indexed node, uint64 ttl); 16 | 17 | function setSubnodeOwner( 18 | bytes32 node, 19 | bytes32 label, 20 | address _owner 21 | ) external; 22 | 23 | function setResolver(bytes32 node, address _resolver) external; 24 | 25 | function setOwner(bytes32 node, address _owner) external; 26 | 27 | function setTTL(bytes32 node, uint64 _ttl) external; 28 | 29 | function owner(bytes32 node) external view returns (address); 30 | 31 | function resolver(bytes32 node) external view returns (address); 32 | 33 | function ttl(bytes32 node) external view returns (uint64); 34 | } 35 | -------------------------------------------------------------------------------- /contracts/interfaces/FlagsInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface FlagsInterface { 5 | function getFlag(address) external view returns (bool); 6 | 7 | function getFlags(address[] calldata) external view returns (bool[] memory); 8 | 9 | function raiseFlag(address) external; 10 | 11 | function raiseFlags(address[] calldata) external; 12 | 13 | function lowerFlags(address[] calldata) external; 14 | 15 | function setRaisingAccessController(address) external; 16 | } 17 | -------------------------------------------------------------------------------- /contracts/interfaces/HashBridgeOracleRequestInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface HashBridgeOracleRequestInterface { 5 | function oracleRequest( 6 | address sender, 7 | uint256 requestPrice, 8 | bytes32 serviceAgreementID, 9 | address callbackAddress, 10 | bytes4 callbackFunctionId, 11 | uint256 nonce, 12 | uint256 dataVersion, 13 | bytes calldata data 14 | ) external; 15 | 16 | function cancelOracleRequest( 17 | bytes32 requestId, 18 | uint256 payment, 19 | bytes4 callbackFunctionId, 20 | uint256 expiration 21 | ) external; 22 | } 23 | -------------------------------------------------------------------------------- /contracts/interfaces/HashBridgeOracleTokenInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface HashBridgeOracleTokenInterface { 5 | function allowance(address owner, address spender) 6 | external 7 | view 8 | returns (uint256 remaining); 9 | 10 | function approve(address spender, uint256 value) 11 | external 12 | returns (bool success); 13 | 14 | function balanceOf(address owner) external view returns (uint256 balance); 15 | 16 | function decimals() external view returns (uint8 decimalPlaces); 17 | 18 | function decreaseApproval(address spender, uint256 addedValue) 19 | external 20 | returns (bool success); 21 | 22 | function increaseApproval(address spender, uint256 subtractedValue) 23 | external; 24 | 25 | function name() external view returns (string memory tokenName); 26 | 27 | function symbol() external view returns (string memory tokenSymbol); 28 | 29 | function totalSupply() external view returns (uint256 totalTokensIssued); 30 | 31 | function transfer(address to, uint256 value) 32 | external 33 | returns (bool success); 34 | 35 | function transferAndCall( 36 | address to, 37 | uint256 value, 38 | bytes calldata data 39 | ) external returns (bool success); 40 | 41 | function transferFrom( 42 | address from, 43 | address to, 44 | uint256 value 45 | ) external returns (bool success); 46 | } 47 | -------------------------------------------------------------------------------- /contracts/interfaces/OracleInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface OracleInterface { 5 | function fulfillOracleRequest( 6 | bytes32 requestId, 7 | uint256 payment, 8 | address callbackAddress, 9 | bytes4 callbackFunctionId, 10 | uint256 expiration, 11 | bytes32 data 12 | ) external returns (bool); 13 | 14 | function getAuthorizationStatus(address node) external view returns (bool); 15 | 16 | function setFulfillmentPermission(address node, bool allowed) external; 17 | 18 | function withdraw(address recipient, uint256 amount) external; 19 | 20 | function withdrawable() external view returns (uint256); 21 | } 22 | -------------------------------------------------------------------------------- /contracts/interfaces/PointerInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface PointerInterface { 5 | function getAddress() external view returns (address); 6 | } 7 | -------------------------------------------------------------------------------- /contracts/interfaces/WithdrawalInterface.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | interface WithdrawalInterface { 5 | /** 6 | * @notice transfer HBO held by the contract belonging to msg.sender to 7 | * another address 8 | * @param recipient is the address to send the HBO to 9 | * @param amount is the amount of HBO to send 10 | */ 11 | function withdraw(address recipient, uint256 amount) external; 12 | 13 | /** 14 | * @notice query the available amount of HBO to withdraw by msg.sender 15 | */ 16 | function withdrawable() external view returns (uint256); 17 | } 18 | -------------------------------------------------------------------------------- /contracts/vendor/BufferHashBridgeOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | /** 5 | * @dev A library for working with mutable byte buffers in Solidity. 6 | * 7 | * Byte buffers are mutable and expandable, and provide a variety of primitives 8 | * for writing to them. At any time you can fetch a bytes object containing the 9 | * current contents of the buffer. The bytes object should not be stored between 10 | * operations, as it may change due to resizing of the buffer. 11 | */ 12 | library BufferHashBridgeOracle { 13 | /** 14 | * @dev Represents a mutable buffer. Buffers have a current value (buf) and 15 | * a capacity. The capacity may be longer than the current value, in 16 | * which case it can be extended without the need to allocate more memory. 17 | */ 18 | struct buffer { 19 | bytes buf; 20 | uint256 capacity; 21 | } 22 | 23 | /** 24 | * @dev Initializes a buffer with an initial capacity. 25 | * @param buf The buffer to initialize. 26 | * @param capacity The number of bytes of space to allocate the buffer. 27 | * @return The buffer, for chaining. 28 | */ 29 | function init(buffer memory buf, uint256 capacity) 30 | internal 31 | pure 32 | returns (buffer memory) 33 | { 34 | if (capacity % 32 != 0) { 35 | capacity += 32 - (capacity % 32); 36 | } 37 | // Allocate space for the buffer data 38 | buf.capacity = capacity; 39 | assembly { 40 | let ptr := mload(0x40) 41 | mstore(buf, ptr) 42 | mstore(ptr, 0) 43 | mstore(0x40, add(32, add(ptr, capacity))) 44 | } 45 | return buf; 46 | } 47 | 48 | /** 49 | * @dev Initializes a new buffer from an existing bytes object. 50 | * Changes to the buffer may mutate the original value. 51 | * @param b The bytes object to initialize the buffer with. 52 | * @return A new buffer. 53 | */ 54 | function fromBytes(bytes memory b) internal pure returns (buffer memory) { 55 | buffer memory buf; 56 | buf.buf = b; 57 | buf.capacity = b.length; 58 | return buf; 59 | } 60 | 61 | function resize(buffer memory buf, uint256 capacity) private pure { 62 | bytes memory oldbuf = buf.buf; 63 | init(buf, capacity); 64 | append(buf, oldbuf); 65 | } 66 | 67 | function max(uint256 a, uint256 b) private pure returns (uint256) { 68 | if (a > b) { 69 | return a; 70 | } 71 | return b; 72 | } 73 | 74 | /** 75 | * @dev Sets buffer length to 0. 76 | * @param buf The buffer to truncate. 77 | * @return The original buffer, for chaining.. 78 | */ 79 | function truncate(buffer memory buf) internal pure returns (buffer memory) { 80 | assembly { 81 | let bufptr := mload(buf) 82 | mstore(bufptr, 0) 83 | } 84 | return buf; 85 | } 86 | 87 | /** 88 | * @dev Writes a byte string to a buffer. Resizes if doing so would exceed 89 | * the capacity of the buffer. 90 | * @param buf The buffer to append to. 91 | * @param off The start offset to write to. 92 | * @param data The data to append. 93 | * @param len The number of bytes to copy. 94 | * @return The original buffer, for chaining. 95 | */ 96 | function write( 97 | buffer memory buf, 98 | uint256 off, 99 | bytes memory data, 100 | uint256 len 101 | ) internal pure returns (buffer memory) { 102 | require(len <= data.length); 103 | 104 | if (off + len > buf.capacity) { 105 | resize(buf, max(buf.capacity, len + off) * 2); 106 | } 107 | 108 | uint256 dest; 109 | uint256 src; 110 | assembly { 111 | // Memory address of the buffer data 112 | let bufptr := mload(buf) 113 | // Length of existing buffer data 114 | let buflen := mload(bufptr) 115 | // Start address = buffer address + offset + sizeof(buffer length) 116 | dest := add(add(bufptr, 32), off) 117 | // Update buffer length if we're extending it 118 | if gt(add(len, off), buflen) { 119 | mstore(bufptr, add(len, off)) 120 | } 121 | src := add(data, 32) 122 | } 123 | 124 | // Copy word-length chunks while possible 125 | for (; len >= 32; len -= 32) { 126 | assembly { 127 | mstore(dest, mload(src)) 128 | } 129 | dest += 32; 130 | src += 32; 131 | } 132 | 133 | // Copy remaining bytes 134 | uint256 mask = 256**(32 - len) - 1; 135 | assembly { 136 | let srcpart := and(mload(src), not(mask)) 137 | let destpart := and(mload(dest), mask) 138 | mstore(dest, or(destpart, srcpart)) 139 | } 140 | 141 | return buf; 142 | } 143 | 144 | /** 145 | * @dev Appends a byte string to a buffer. Resizes if doing so would exceed 146 | * the capacity of the buffer. 147 | * @param buf The buffer to append to. 148 | * @param data The data to append. 149 | * @param len The number of bytes to copy. 150 | * @return The original buffer, for chaining. 151 | */ 152 | function append( 153 | buffer memory buf, 154 | bytes memory data, 155 | uint256 len 156 | ) internal pure returns (buffer memory) { 157 | return write(buf, buf.buf.length, data, len); 158 | } 159 | 160 | /** 161 | * @dev Appends a byte string to a buffer. Resizes if doing so would exceed 162 | * the capacity of the buffer. 163 | * @param buf The buffer to append to. 164 | * @param data The data to append. 165 | * @return The original buffer, for chaining. 166 | */ 167 | function append(buffer memory buf, bytes memory data) 168 | internal 169 | pure 170 | returns (buffer memory) 171 | { 172 | return write(buf, buf.buf.length, data, data.length); 173 | } 174 | 175 | /** 176 | * @dev Writes a byte to the buffer. Resizes if doing so would exceed the 177 | * capacity of the buffer. 178 | * @param buf The buffer to append to. 179 | * @param off The offset to write the byte at. 180 | * @param data The data to append. 181 | * @return The original buffer, for chaining. 182 | */ 183 | function writeUint8( 184 | buffer memory buf, 185 | uint256 off, 186 | uint8 data 187 | ) internal pure returns (buffer memory) { 188 | if (off >= buf.capacity) { 189 | resize(buf, buf.capacity * 2); 190 | } 191 | 192 | assembly { 193 | // Memory address of the buffer data 194 | let bufptr := mload(buf) 195 | // Length of existing buffer data 196 | let buflen := mload(bufptr) 197 | // Address = buffer address + sizeof(buffer length) + off 198 | let dest := add(add(bufptr, off), 32) 199 | mstore8(dest, data) 200 | // Update buffer length if we extended it 201 | if eq(off, buflen) { 202 | mstore(bufptr, add(buflen, 1)) 203 | } 204 | } 205 | return buf; 206 | } 207 | 208 | /** 209 | * @dev Appends a byte to the buffer. Resizes if doing so would exceed the 210 | * capacity of the buffer. 211 | * @param buf The buffer to append to. 212 | * @param data The data to append. 213 | * @return The original buffer, for chaining. 214 | */ 215 | function appendUint8(buffer memory buf, uint8 data) 216 | internal 217 | pure 218 | returns (buffer memory) 219 | { 220 | return writeUint8(buf, buf.buf.length, data); 221 | } 222 | 223 | /** 224 | * @dev Writes up to 32 bytes to the buffer. Resizes if doing so would 225 | * exceed the capacity of the buffer. 226 | * @param buf The buffer to append to. 227 | * @param off The offset to write at. 228 | * @param data The data to append. 229 | * @param len The number of bytes to write (left-aligned). 230 | * @return The original buffer, for chaining. 231 | */ 232 | function write( 233 | buffer memory buf, 234 | uint256 off, 235 | bytes32 data, 236 | uint256 len 237 | ) private pure returns (buffer memory) { 238 | if (len + off > buf.capacity) { 239 | resize(buf, (len + off) * 2); 240 | } 241 | 242 | uint256 mask = 256**len - 1; 243 | // Right-align data 244 | data = data >> (8 * (32 - len)); 245 | assembly { 246 | // Memory address of the buffer data 247 | let bufptr := mload(buf) 248 | // Address = buffer address + sizeof(buffer length) + off + len 249 | let dest := add(add(bufptr, off), len) 250 | mstore(dest, or(and(mload(dest), not(mask)), data)) 251 | // Update buffer length if we extended it 252 | if gt(add(off, len), mload(bufptr)) { 253 | mstore(bufptr, add(off, len)) 254 | } 255 | } 256 | return buf; 257 | } 258 | 259 | /** 260 | * @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the 261 | * capacity of the buffer. 262 | * @param buf The buffer to append to. 263 | * @param off The offset to write at. 264 | * @param data The data to append. 265 | * @return The original buffer, for chaining. 266 | */ 267 | function writeBytes20( 268 | buffer memory buf, 269 | uint256 off, 270 | bytes20 data 271 | ) internal pure returns (buffer memory) { 272 | return write(buf, off, bytes32(data), 20); 273 | } 274 | 275 | /** 276 | * @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed 277 | * the capacity of the buffer. 278 | * @param buf The buffer to append to. 279 | * @param data The data to append. 280 | * @return The original buffer, for chhaining. 281 | */ 282 | function appendBytes20(buffer memory buf, bytes20 data) 283 | internal 284 | pure 285 | returns (buffer memory) 286 | { 287 | return write(buf, buf.buf.length, bytes32(data), 20); 288 | } 289 | 290 | /** 291 | * @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed 292 | * the capacity of the buffer. 293 | * @param buf The buffer to append to. 294 | * @param data The data to append. 295 | * @return The original buffer, for chaining. 296 | */ 297 | function appendBytes32(buffer memory buf, bytes32 data) 298 | internal 299 | pure 300 | returns (buffer memory) 301 | { 302 | return write(buf, buf.buf.length, data, 32); 303 | } 304 | 305 | /** 306 | * @dev Writes an integer to the buffer. Resizes if doing so would exceed 307 | * the capacity of the buffer. 308 | * @param buf The buffer to append to. 309 | * @param off The offset to write at. 310 | * @param data The data to append. 311 | * @param len The number of bytes to write (right-aligned). 312 | * @return The original buffer, for chaining. 313 | */ 314 | function writeInt( 315 | buffer memory buf, 316 | uint256 off, 317 | uint256 data, 318 | uint256 len 319 | ) private pure returns (buffer memory) { 320 | if (len + off > buf.capacity) { 321 | resize(buf, (len + off) * 2); 322 | } 323 | 324 | uint256 mask = 256**len - 1; 325 | assembly { 326 | // Memory address of the buffer data 327 | let bufptr := mload(buf) 328 | // Address = buffer address + off + sizeof(buffer length) + len 329 | let dest := add(add(bufptr, off), len) 330 | mstore(dest, or(and(mload(dest), not(mask)), data)) 331 | // Update buffer length if we extended it 332 | if gt(add(off, len), mload(bufptr)) { 333 | mstore(bufptr, add(off, len)) 334 | } 335 | } 336 | return buf; 337 | } 338 | 339 | /** 340 | * @dev Appends a byte to the end of the buffer. Resizes if doing so would 341 | * exceed the capacity of the buffer. 342 | * @param buf The buffer to append to. 343 | * @param data The data to append. 344 | * @return The original buffer. 345 | */ 346 | function appendInt( 347 | buffer memory buf, 348 | uint256 data, 349 | uint256 len 350 | ) internal pure returns (buffer memory) { 351 | return writeInt(buf, buf.buf.length, data, len); 352 | } 353 | } 354 | -------------------------------------------------------------------------------- /contracts/vendor/CBORHashBridgeOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.19 <0.7.0; 3 | 4 | import {BufferHashBridgeOracle} from "./BufferHashBridgeOracle.sol"; 5 | 6 | library CBORHashBridgeOracle { 7 | using BufferHashBridgeOracle for BufferHashBridgeOracle.buffer; 8 | 9 | uint8 private constant MAJOR_TYPE_INT = 0; 10 | uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1; 11 | uint8 private constant MAJOR_TYPE_BYTES = 2; 12 | uint8 private constant MAJOR_TYPE_STRING = 3; 13 | uint8 private constant MAJOR_TYPE_ARRAY = 4; 14 | uint8 private constant MAJOR_TYPE_MAP = 5; 15 | uint8 private constant MAJOR_TYPE_TAG = 6; 16 | uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7; 17 | 18 | uint8 private constant TAG_TYPE_BIGNUM = 2; 19 | uint8 private constant TAG_TYPE_NEGATIVE_BIGNUM = 3; 20 | 21 | function encodeType( 22 | BufferHashBridgeOracle.buffer memory buf, 23 | uint8 major, 24 | uint256 value 25 | ) private pure { 26 | if (value <= 23) { 27 | buf.appendUint8(uint8((major << 5) | value)); 28 | } else if (value <= 0xFF) { 29 | buf.appendUint8(uint8((major << 5) | 24)); 30 | buf.appendInt(value, 1); 31 | } else if (value <= 0xFFFF) { 32 | buf.appendUint8(uint8((major << 5) | 25)); 33 | buf.appendInt(value, 2); 34 | } else if (value <= 0xFFFFFFFF) { 35 | buf.appendUint8(uint8((major << 5) | 26)); 36 | buf.appendInt(value, 4); 37 | } else if (value <= 0xFFFFFFFFFFFFFFFF) { 38 | buf.appendUint8(uint8((major << 5) | 27)); 39 | buf.appendInt(value, 8); 40 | } 41 | } 42 | 43 | function encodeIndefiniteLengthType( 44 | BufferHashBridgeOracle.buffer memory buf, 45 | uint8 major 46 | ) private pure { 47 | buf.appendUint8(uint8((major << 5) | 31)); 48 | } 49 | 50 | function encodeUInt(BufferHashBridgeOracle.buffer memory buf, uint256 value) 51 | internal 52 | pure 53 | { 54 | encodeType(buf, MAJOR_TYPE_INT, value); 55 | } 56 | 57 | function encodeInt(BufferHashBridgeOracle.buffer memory buf, int256 value) 58 | internal 59 | pure 60 | { 61 | if (value < -0x10000000000000000) { 62 | encodeSignedBigNum(buf, value); 63 | } else if (value > 0xFFFFFFFFFFFFFFFF) { 64 | encodeBigNum(buf, value); 65 | } else if (value >= 0) { 66 | encodeType(buf, MAJOR_TYPE_INT, uint256(value)); 67 | } else { 68 | encodeType(buf, MAJOR_TYPE_NEGATIVE_INT, uint256(-1 - value)); 69 | } 70 | } 71 | 72 | function encodeBytes( 73 | BufferHashBridgeOracle.buffer memory buf, 74 | bytes memory value 75 | ) internal pure { 76 | encodeType(buf, MAJOR_TYPE_BYTES, value.length); 77 | buf.append(value); 78 | } 79 | 80 | function encodeBigNum( 81 | BufferHashBridgeOracle.buffer memory buf, 82 | int256 value 83 | ) internal pure { 84 | buf.appendUint8(uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_BIGNUM)); 85 | encodeBytes(buf, abi.encode(uint256(value))); 86 | } 87 | 88 | function encodeSignedBigNum( 89 | BufferHashBridgeOracle.buffer memory buf, 90 | int256 input 91 | ) internal pure { 92 | buf.appendUint8( 93 | uint8((MAJOR_TYPE_TAG << 5) | TAG_TYPE_NEGATIVE_BIGNUM) 94 | ); 95 | encodeBytes(buf, abi.encode(uint256(-1 - input))); 96 | } 97 | 98 | function encodeString( 99 | BufferHashBridgeOracle.buffer memory buf, 100 | string memory value 101 | ) internal pure { 102 | encodeType(buf, MAJOR_TYPE_STRING, bytes(value).length); 103 | buf.append(bytes(value)); 104 | } 105 | 106 | function startArray(BufferHashBridgeOracle.buffer memory buf) 107 | internal 108 | pure 109 | { 110 | encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY); 111 | } 112 | 113 | function startMap(BufferHashBridgeOracle.buffer memory buf) internal pure { 114 | encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP); 115 | } 116 | 117 | function endSequence(BufferHashBridgeOracle.buffer memory buf) 118 | internal 119 | pure 120 | { 121 | encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /contracts/vendor/ENSResolver.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | abstract contract ENSResolver { 5 | function addr(bytes32 node) public view virtual returns (address); 6 | } 7 | -------------------------------------------------------------------------------- /contracts/vendor/Ownable.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | /** 5 | * @dev Contract module which provides a basic access control mechanism, where 6 | * there is an account (an owner) that can be granted exclusive access to 7 | * specific functions. 8 | * 9 | * This module is used through inheritance. It will make available the modifier 10 | * `onlyOwner`, which can be aplied to your functions to restrict their use to 11 | * the owner. 12 | * 13 | * This contract has been modified to remove the revokeOwnership function 14 | */ 15 | contract Ownable { 16 | address private _owner; 17 | 18 | event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); 19 | 20 | /** 21 | * @dev Initializes the contract setting the deployer as the initial owner. 22 | */ 23 | constructor () internal { 24 | _owner = msg.sender; 25 | emit OwnershipTransferred(address(0), _owner); 26 | } 27 | 28 | /** 29 | * @dev Returns the address of the current owner. 30 | */ 31 | function owner() public view returns (address) { 32 | return _owner; 33 | } 34 | 35 | /** 36 | * @dev Throws if called by any account other than the owner. 37 | */ 38 | modifier onlyOwner() { 39 | require(isOwner(), "Ownable: caller is not the owner"); 40 | _; 41 | } 42 | 43 | /** 44 | * @dev Returns true if the caller is the current owner. 45 | */ 46 | function isOwner() public view returns (bool) { 47 | return msg.sender == _owner; 48 | } 49 | 50 | /** 51 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 52 | * Can only be called by the current owner. 53 | */ 54 | function transferOwnership(address newOwner) public onlyOwner { 55 | _transferOwnership(newOwner); 56 | } 57 | 58 | /** 59 | * @dev Transfers ownership of the contract to a new account (`newOwner`). 60 | */ 61 | function _transferOwnership(address newOwner) internal { 62 | require(newOwner != address(0), "Ownable: new owner is the zero address"); 63 | emit OwnershipTransferred(_owner, newOwner); 64 | _owner = newOwner; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /contracts/vendor/SafeMathHashBridgeOracle.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.6.0; 3 | 4 | /** 5 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 6 | * checks. 7 | * 8 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 9 | * in bugs, because programmers usually assume that an overflow raises an 10 | * error, which is the standard behavior in high level programming languages. 11 | * `SafeMath` restores this intuition by reverting the transaction when an 12 | * operation overflows. 13 | * 14 | * Using this library instead of the unchecked operations eliminates an entire 15 | * class of bugs, so it's recommended to use it always. 16 | */ 17 | library SafeMathHashBridgeOracle { 18 | /** 19 | * @dev Returns the addition of two unsigned integers, reverting on 20 | * overflow. 21 | * 22 | * Counterpart to Solidity's `+` operator. 23 | * 24 | * Requirements: 25 | * - Addition cannot overflow. 26 | */ 27 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 28 | uint256 c = a + b; 29 | require(c >= a, "SafeMath: addition overflow"); 30 | 31 | return c; 32 | } 33 | 34 | /** 35 | * @dev Returns the subtraction of two unsigned integers, reverting on 36 | * overflow (when the result is negative). 37 | * 38 | * Counterpart to Solidity's `-` operator. 39 | * 40 | * Requirements: 41 | * - Subtraction cannot overflow. 42 | */ 43 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 44 | require(b <= a, "SafeMath: subtraction overflow"); 45 | uint256 c = a - b; 46 | 47 | return c; 48 | } 49 | 50 | /** 51 | * @dev Returns the multiplication of two unsigned integers, reverting on 52 | * overflow. 53 | * 54 | * Counterpart to Solidity's `*` operator. 55 | * 56 | * Requirements: 57 | * - Multiplication cannot overflow. 58 | */ 59 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 60 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 61 | // benefit is lost if 'b' is also tested. 62 | // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522 63 | if (a == 0) { 64 | return 0; 65 | } 66 | 67 | uint256 c = a * b; 68 | require(c / a == b, "SafeMath: multiplication overflow"); 69 | 70 | return c; 71 | } 72 | 73 | /** 74 | * @dev Returns the integer division of two unsigned integers. Reverts on 75 | * division by zero. The result is rounded towards zero. 76 | * 77 | * Counterpart to Solidity's `/` operator. Note: this function uses a 78 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 79 | * uses an invalid opcode to revert (consuming all remaining gas). 80 | * 81 | * Requirements: 82 | * - The divisor cannot be zero. 83 | */ 84 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 85 | // Solidity only automatically asserts when dividing by 0 86 | require(b > 0, "SafeMath: division by zero"); 87 | uint256 c = a / b; 88 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 89 | 90 | return c; 91 | } 92 | 93 | /** 94 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 95 | * Reverts when dividing by zero. 96 | * 97 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 98 | * opcode (which leaves remaining gas untouched) while Solidity uses an 99 | * invalid opcode to revert (consuming all remaining gas). 100 | * 101 | * Requirements: 102 | * - The divisor cannot be zero. 103 | */ 104 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 105 | require(b != 0, "SafeMath: modulo by zero"); 106 | return a % b; 107 | } 108 | } 109 | --------------------------------------------------------------------------------