Skip to content

Instantly share code, notes, and snippets.

@ngyam
Created November 25, 2019 16:20
Show Gist options
  • Save ngyam/21db5a581949c4ab7882add2bb0d5867 to your computer and use it in GitHub Desktop.
Save ngyam/21db5a581949c4ab7882add2bb0d5867 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.5.13+commit.5b0b510c.js&optimize=false&gist=
pragma solidity ^0.5.0;
/**
* @dev Collection of functions related to the address type,
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* This test is non-exhaustive, and there may be false-negatives: during the
* execution of a contract's constructor, its address will be reported as
* not containing a contract.
*
* > It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*/
function isContract(address account) internal view returns (bool) {
// This method relies in extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
}
pragma solidity ^0.4.24;
import "./ChainlinkClient.sol";
import "./SignedSafeMath.sol";
import "./Ownable.sol";
/**
* @title An example Chainlink contract with aggregation
* @notice Requesters can use this contract as a framework for creating
* requests to multiple Chainlink nodes and running aggregation
* as the contract receives answers.
*/
contract Aggregator is ChainlinkClient, Ownable {
using SignedSafeMath for int256;
struct Answer {
uint128 minimumResponses;
uint128 maxResponses;
int256[] responses;
}
event ResponseReceived(int256 indexed response, uint256 indexed answerId, address indexed sender);
event AnswerUpdated(int256 indexed current, uint256 indexed answerId);
int256 public currentAnswer;
uint256 public latestCompletedAnswer;
uint256 public updatedHeight;
uint128 public paymentAmount;
uint128 public minimumResponses;
bytes32[] public jobIds;
address[] public oracles;
uint256 private answerCounter = 1;
mapping(address => bool) public authorizedRequesters;
mapping(bytes32 => uint256) private requestAnswers;
mapping(uint256 => Answer) private answers;
uint256 constant private MAX_ORACLE_COUNT = 45;
/**
* @notice Deploy with the address of the LINK token and arrays of matching
* length containing the addresses of the oracles and their corresponding
* Job IDs.
* @dev Sets the LinkToken address for the network, addresses of the oracles,
* and jobIds in storage.
* @param _link The address of the LINK token
* @param _paymentAmount the amount of LINK to be sent to each oracle for each request
* @param _minimumResponses the minimum number of responses
* before an answer will be calculated
* @param _oracles An array of oracle addresses
* @param _jobIds An array of Job IDs
*/
constructor(
address _link,
uint128 _paymentAmount,
uint128 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
) public Ownable() {
setChainlinkToken(_link);
updateRequestDetails(_paymentAmount, _minimumResponses, _oracles, _jobIds);
}
/**
* @notice Creates a Chainlink request for each oracle in the oracles array.
* @dev This example does not include request parameters. Reference any documentation
* associated with the Job IDs used to determine the required parameters per-request.
*/
function requestRateUpdate()
external
ensureAuthorizedRequester()
{
Chainlink.Request memory request;
bytes32 requestId;
uint256 oraclePayment = paymentAmount;
for (uint i = 0; i < oracles.length; i++) {
request = buildChainlinkRequest(jobIds[i], this, this.chainlinkCallback.selector);
requestId = sendChainlinkRequestTo(oracles[i], request, oraclePayment);
requestAnswers[requestId] = answerCounter;
}
answers[answerCounter].minimumResponses = minimumResponses;
answers[answerCounter].maxResponses = uint128(oracles.length);
answerCounter = answerCounter.add(1);
}
/**
* @notice Receives the answer from the Chainlink node.
* @dev This function can only be called by the oracle that received the request.
* @param _clRequestId The Chainlink request ID associated with the answer
* @param _response The answer provided by the Chainlink node
*/
function chainlinkCallback(bytes32 _clRequestId, int256 _response)
external
{
validateChainlinkCallback(_clRequestId);
uint256 answerId = requestAnswers[_clRequestId];
delete requestAnswers[_clRequestId];
answers[answerId].responses.push(_response);
emit ResponseReceived(_response, answerId, msg.sender);
updateLatestAnswer(answerId);
deleteAnswer(answerId);
}
/**
* @notice Updates the arrays of oracles and jobIds with new values,
* overwriting the old values.
* @dev Arrays are validated to be equal length.
* @param _paymentAmount the amount of LINK to be sent to each oracle for each request
* @param _minimumResponses the minimum number of responses
* before an answer will be calculated
* @param _oracles An array of oracle addresses
* @param _jobIds An array of Job IDs
*/
function updateRequestDetails(
uint128 _paymentAmount,
uint128 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
)
public
onlyOwner()
validateAnswerRequirements(_minimumResponses, _oracles, _jobIds)
{
paymentAmount = _paymentAmount;
minimumResponses = _minimumResponses;
jobIds = _jobIds;
oracles = _oracles;
}
/**
* @notice Allows the owner of the contract to withdraw any LINK balance
* available on the contract.
* @dev The contract will need to have a LINK balance in order to create requests.
* @param _recipient The address to receive the LINK tokens
* @param _amount The amount of LINK to send from the contract
*/
function transferLINK(address _recipient, uint256 _amount)
public
onlyOwner()
{
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(link.transfer(_recipient, _amount), "LINK transfer failed");
}
/**
* @notice Called by the owner to permission other addresses to generate new
* requests to oracles.
* @param _requester the address whose permissions are being set
* @param _allowed boolean that determines whether the requester is
* permissioned or not
*/
function setAuthorization(address _requester, bool _allowed)
external
onlyOwner()
{
authorizedRequesters[_requester] = _allowed;
}
/**
* @notice Cancels an outstanding Chainlink request.
* The oracle contract requires the request ID and additional metadata to
* validate the cancellation. Only old answers can be cancelled.
* @param _requestId is the identifier for the chainlink request being cancelled
* @param _payment is the amount of LINK paid to the oracle for the request
* @param _expiration is the time when the request expires
*/
function cancelRequest(
bytes32 _requestId,
uint256 _payment,
uint256 _expiration
)
external
ensureAuthorizedRequester()
{
uint256 answerId = requestAnswers[_requestId];
require(answerId < latestCompletedAnswer, "Cannot modify an in-progress answer");
cancelChainlinkRequest(
_requestId,
_payment,
this.chainlinkCallback.selector,
_expiration
);
delete requestAnswers[_requestId];
answers[answerId].responses.push(0);
deleteAnswer(answerId);
}
/**
* @notice Called by the owner to kill the contract. This transfers all LINK
* balance and ETH balance (if there is any) to the owner.
*/
function destroy()
external
onlyOwner()
{
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
transferLINK(owner, link.balanceOf(address(this)));
selfdestruct(owner);
}
/**
* @dev Performs aggregation of the answers received from the Chainlink nodes.
* Assumes that at least half the oracles are honest and so can't contol the
* middle of the ordered responses.
* @param _answerId The answer ID associated with the group of requests
*/
function updateLatestAnswer(uint256 _answerId)
private
ensureMinResponsesReceived(_answerId)
ensureOnlyLatestAnswer(_answerId)
{
uint256 responseLength = answers[_answerId].responses.length;
uint256 middleIndex = responseLength.div(2);
if (responseLength % 2 == 0) {
int256 median1 = quickselect(answers[_answerId].responses, middleIndex);
int256 median2 = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
currentAnswer = median1.add(median2) / 2; // signed integers are not supported by SafeMath
} else {
currentAnswer = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
}
latestCompletedAnswer = _answerId;
updatedHeight = block.number;
emit AnswerUpdated(currentAnswer, _answerId);
}
/**
* @dev Returns the kth value of the ordered array
* See: http://www.cs.yale.edu/homes/aspnes/pinewiki/QuickSelect.html
* @param _a The list of elements to pull from
* @param _k The index, 1 based, of the elements you want to pull from when ordered
*/
function quickselect(int256[] memory _a, uint256 _k)
private
pure
returns (int256)
{
int256[] memory a = _a;
uint256 k = _k;
uint256 aLen = a.length;
int256[] memory a1 = new int256[](aLen);
int256[] memory a2 = new int256[](aLen);
uint256 a1Len;
uint256 a2Len;
int256 pivot;
uint256 i;
while (true) {
pivot = a[aLen.div(2)];
a1Len = 0;
a2Len = 0;
for (i = 0; i < aLen; i++) {
if (a[i] < pivot) {
a1[a1Len] = a[i];
a1Len++;
} else if (a[i] > pivot) {
a2[a2Len] = a[i];
a2Len++;
}
}
if (k <= a1Len) {
aLen = a1Len;
(a, a1) = swap(a, a1);
} else if (k > (aLen.sub(a2Len))) {
k = k.sub(aLen.sub(a2Len));
aLen = a2Len;
(a, a2) = swap(a, a2);
} else {
return pivot;
}
}
}
/**
* @dev Swaps the pointers to two uint256 arrays in memory
* @param _a The pointer to the first in memory array
* @param _b The pointer to the second in memory array
*/
function swap(int256[] memory _a, int256[] memory _b)
private
pure
returns(int256[] memory, int256[] memory)
{
return (_b, _a);
}
/**
* @dev Cleans up the answer record if all responses have been received.
* @param _answerId The identifier of the answer to be deleted
*/
function deleteAnswer(uint256 _answerId)
private
ensureAllResponsesReceived(_answerId)
{
delete answers[_answerId];
}
/**
* @dev Prevents taking an action if the minimum number of responses has not
* been received for an answer.
* @param _answerId The the identifier of the answer that keeps track of the responses.
*/
modifier ensureMinResponsesReceived(uint256 _answerId) {
if (answers[_answerId].responses.length >= answers[_answerId].minimumResponses) {
_;
}
}
/**
* @dev Prevents taking an action if not all responses are received for an answer.
* @param _answerId The the identifier of the answer that keeps track of the responses.
*/
modifier ensureAllResponsesReceived(uint256 _answerId) {
if (answers[_answerId].responses.length == answers[_answerId].maxResponses) {
_;
}
}
/**
* @dev Prevents taking an action if a newer answer has been recorded.
* @param _answerId The current answer's identifier.
* Answer IDs are in ascending order.
*/
modifier ensureOnlyLatestAnswer(uint256 _answerId) {
if (latestCompletedAnswer <= _answerId) {
_;
}
}
/**
* @dev Ensures corresponding number of oracles and jobs.
* @param _oracles The list of oracles.
* @param _jobIds The list of jobs.
*/
modifier validateAnswerRequirements(
uint256 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
) {
require(_oracles.length <= MAX_ORACLE_COUNT, "cannot have more than 45 oracles");
require(_oracles.length >= _minimumResponses, "must have at least as many oracles as responses");
require(_oracles.length == _jobIds.length, "must have exactly as many oracles as job IDs");
_;
}
/**
* @dev Reverts if `msg.sender` is not authorized to make requests.
*/
modifier ensureAuthorizedRequester() {
require(authorizedRequesters[msg.sender] || msg.sender == owner, "Not an authorized address for creating requests");
_;
}
}
pragma solidity ^0.4.24;
interface AggregatorInterface {
function currentAnswer() external view returns (int256);
function updatedHeight() external view returns (uint256);
}
pragma solidity ^0.4.24;
import "./AggregatorInterface.sol";
import "./Ownable.sol";
/**
* @title A trusted proxy for updating where current answers are read from
* @notice This contract provides a consistent address for the
* CurrentAnwerInterface but delegates where it reads from to the owner, who is
* trusted to update it.
*/
contract AggregatorProxy is AggregatorInterface, Ownable {
AggregatorInterface public aggregator;
constructor(address _aggregator) public Ownable() {
setAggregator(_aggregator);
}
/**
* @notice Reads the current answer from aggregator delegated to.
*/
function currentAnswer()
external
view
returns (int256)
{
return aggregator.currentAnswer();
}
/**
* @notice Reads the last updated height from aggregator delegated to.
*/
function updatedHeight()
external
view
returns (uint256)
{
return aggregator.updatedHeight();
}
/**
* @notice Allows the owner to update the aggregator address.
* @param _aggregator The new address for the aggregator contract
*/
function setAggregator(address _aggregator)
public
onlyOwner()
{
aggregator = AggregatorInterface(_aggregator);
}
/**
* @notice Allows the owner to destroy the contract if it is not intended to
* be used any longer.
*/
function destroy()
external
onlyOwner()
{
selfdestruct(owner);
}
}
pragma solidity >0.4.18;
/**
* @dev A library for working with mutable byte buffers in Solidity.
*
* Byte buffers are mutable and expandable, and provide a variety of primitives
* for writing to them. At any time you can fetch a bytes object containing the
* current contents of the buffer. The bytes object should not be stored between
* operations, as it may change due to resizing of the buffer.
*/
library Buffer {
/**
* @dev Represents a mutable buffer. Buffers have a current value (buf) and
* a capacity. The capacity may be longer than the current value, in
* which case it can be extended without the need to allocate more memory.
*/
struct buffer {
bytes buf;
uint capacity;
}
/**
* @dev Initializes a buffer with an initial capacity.
* @param buf The buffer to initialize.
* @param capacity The number of bytes of space to allocate the buffer.
* @return The buffer, for chaining.
*/
function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
if (capacity % 32 != 0) {
capacity += 32 - (capacity % 32);
}
// Allocate space for the buffer data
buf.capacity = capacity;
assembly {
let ptr := mload(0x40)
mstore(buf, ptr)
mstore(ptr, 0)
mstore(0x40, add(32, add(ptr, capacity)))
}
return buf;
}
/**
* @dev Initializes a new buffer from an existing bytes object.
* Changes to the buffer may mutate the original value.
* @param b The bytes object to initialize the buffer with.
* @return A new buffer.
*/
function fromBytes(bytes memory b) internal pure returns(buffer memory) {
buffer memory buf;
buf.buf = b;
buf.capacity = b.length;
return buf;
}
function resize(buffer memory buf, uint capacity) private pure {
bytes memory oldbuf = buf.buf;
init(buf, capacity);
append(buf, oldbuf);
}
function max(uint a, uint b) private pure returns(uint) {
if (a > b) {
return a;
}
return b;
}
/**
* @dev Sets buffer length to 0.
* @param buf The buffer to truncate.
* @return The original buffer, for chaining..
*/
function truncate(buffer memory buf) internal pure returns (buffer memory) {
assembly {
let bufptr := mload(buf)
mstore(bufptr, 0)
}
return buf;
}
/**
* @dev Writes a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param off The start offset to write to.
* @param data The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/
function write(buffer memory buf, uint off, bytes memory data, uint len) internal pure returns(buffer memory) {
require(len <= data.length);
if (off + len > buf.capacity) {
resize(buf, max(buf.capacity, len + off) * 2);
}
uint dest;
uint src;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Length of existing buffer data
let buflen := mload(bufptr)
// Start address = buffer address + offset + sizeof(buffer length)
dest := add(add(bufptr, 32), off)
// Update buffer length if we're extending it
if gt(add(len, off), buflen) {
mstore(bufptr, add(len, off))
}
src := add(data, 32)
}
// Copy word-length chunks while possible
for (; len >= 32; len -= 32) {
assembly {
mstore(dest, mload(src))
}
dest += 32;
src += 32;
}
// Copy remaining bytes
uint mask = 256 ** (32 - len) - 1;
assembly {
let srcpart := and(mload(src), not(mask))
let destpart := and(mload(dest), mask)
mstore(dest, or(destpart, srcpart))
}
return buf;
}
/**
* @dev Appends a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @param len The number of bytes to copy.
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes memory data, uint len) internal pure returns (buffer memory) {
return write(buf, buf.buf.length, data, len);
}
/**
* @dev Appends a byte string to a buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function append(buffer memory buf, bytes memory data) internal pure returns (buffer memory) {
return write(buf, buf.buf.length, data, data.length);
}
/**
* @dev Writes a byte to the buffer. Resizes if doing so would exceed the
* capacity of the buffer.
* @param buf The buffer to append to.
* @param off The offset to write the byte at.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function writeUint8(buffer memory buf, uint off, uint8 data) internal pure returns(buffer memory) {
if (off >= buf.capacity) {
resize(buf, buf.capacity * 2);
}
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Length of existing buffer data
let buflen := mload(bufptr)
// Address = buffer address + sizeof(buffer length) + off
let dest := add(add(bufptr, off), 32)
mstore8(dest, data)
// Update buffer length if we extended it
if eq(off, buflen) {
mstore(bufptr, add(buflen, 1))
}
}
return buf;
}
/**
* @dev Appends a byte to the buffer. Resizes if doing so would exceed the
* capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function appendUint8(buffer memory buf, uint8 data) internal pure returns(buffer memory) {
return writeUint8(buf, buf.buf.length, data);
}
/**
* @dev Writes up to 32 bytes to the buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param off The offset to write at.
* @param data The data to append.
* @param len The number of bytes to write (left-aligned).
* @return The original buffer, for chaining.
*/
function write(buffer memory buf, uint off, bytes32 data, uint len) private pure returns(buffer memory) {
if (len + off > buf.capacity) {
resize(buf, (len + off) * 2);
}
uint mask = 256 ** len - 1;
// Right-align data
data = data >> (8 * (32 - len));
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + sizeof(buffer length) + off + len
let dest := add(add(bufptr, off), len)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended it
if gt(add(off, len), mload(bufptr)) {
mstore(bufptr, add(off, len))
}
}
return buf;
}
/**
* @dev Writes a bytes20 to the buffer. Resizes if doing so would exceed the
* capacity of the buffer.
* @param buf The buffer to append to.
* @param off The offset to write at.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function writeBytes20(buffer memory buf, uint off, bytes20 data) internal pure returns (buffer memory) {
return write(buf, off, bytes32(data), 20);
}
/**
* @dev Appends a bytes20 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chhaining.
*/
function appendBytes20(buffer memory buf, bytes20 data) internal pure returns (buffer memory) {
return write(buf, buf.buf.length, bytes32(data), 20);
}
/**
* @dev Appends a bytes32 to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer, for chaining.
*/
function appendBytes32(buffer memory buf, bytes32 data) internal pure returns (buffer memory) {
return write(buf, buf.buf.length, data, 32);
}
/**
* @dev Writes an integer to the buffer. Resizes if doing so would exceed
* the capacity of the buffer.
* @param buf The buffer to append to.
* @param off The offset to write at.
* @param data The data to append.
* @param len The number of bytes to write (right-aligned).
* @return The original buffer, for chaining.
*/
function writeInt(buffer memory buf, uint off, uint data, uint len) private pure returns(buffer memory) {
if (len + off > buf.capacity) {
resize(buf, (len + off) * 2);
}
uint mask = 256 ** len - 1;
assembly {
// Memory address of the buffer data
let bufptr := mload(buf)
// Address = buffer address + off + sizeof(buffer length) + len
let dest := add(add(bufptr, off), len)
mstore(dest, or(and(mload(dest), not(mask)), data))
// Update buffer length if we extended it
if gt(add(off, len), mload(bufptr)) {
mstore(bufptr, add(off, len))
}
}
return buf;
}
/**
* @dev Appends a byte to the end of the buffer. Resizes if doing so would
* exceed the capacity of the buffer.
* @param buf The buffer to append to.
* @param data The data to append.
* @return The original buffer.
*/
function appendInt(buffer memory buf, uint data, uint len) internal pure returns(buffer memory) {
return writeInt(buf, buf.buf.length, data, len);
}
}
pragma solidity ^0.4.19;
import "./Buffer.sol";
library CBOR {
using Buffer for Buffer.buffer;
uint8 private constant MAJOR_TYPE_INT = 0;
uint8 private constant MAJOR_TYPE_NEGATIVE_INT = 1;
uint8 private constant MAJOR_TYPE_BYTES = 2;
uint8 private constant MAJOR_TYPE_STRING = 3;
uint8 private constant MAJOR_TYPE_ARRAY = 4;
uint8 private constant MAJOR_TYPE_MAP = 5;
uint8 private constant MAJOR_TYPE_CONTENT_FREE = 7;
function encodeType(Buffer.buffer memory buf, uint8 major, uint value) private pure {
if(value <= 23) {
buf.appendUint8(uint8((major << 5) | value));
} else if(value <= 0xFF) {
buf.appendUint8(uint8((major << 5) | 24));
buf.appendInt(value, 1);
} else if(value <= 0xFFFF) {
buf.appendUint8(uint8((major << 5) | 25));
buf.appendInt(value, 2);
} else if(value <= 0xFFFFFFFF) {
buf.appendUint8(uint8((major << 5) | 26));
buf.appendInt(value, 4);
} else if(value <= 0xFFFFFFFFFFFFFFFF) {
buf.appendUint8(uint8((major << 5) | 27));
buf.appendInt(value, 8);
}
}
function encodeIndefiniteLengthType(Buffer.buffer memory buf, uint8 major) private pure {
buf.appendUint8(uint8((major << 5) | 31));
}
function encodeUInt(Buffer.buffer memory buf, uint value) internal pure {
encodeType(buf, MAJOR_TYPE_INT, value);
}
function encodeInt(Buffer.buffer memory buf, int value) internal pure {
if(value >= 0) {
encodeType(buf, MAJOR_TYPE_INT, uint(value));
} else {
encodeType(buf, MAJOR_TYPE_NEGATIVE_INT, uint(-1 - value));
}
}
function encodeBytes(Buffer.buffer memory buf, bytes value) internal pure {
encodeType(buf, MAJOR_TYPE_BYTES, value.length);
buf.append(value);
}
function encodeString(Buffer.buffer memory buf, string value) internal pure {
encodeType(buf, MAJOR_TYPE_STRING, bytes(value).length);
buf.append(bytes(value));
}
function startArray(Buffer.buffer memory buf) internal pure {
encodeIndefiniteLengthType(buf, MAJOR_TYPE_ARRAY);
}
function startMap(Buffer.buffer memory buf) internal pure {
encodeIndefiniteLengthType(buf, MAJOR_TYPE_MAP);
}
function endSequence(Buffer.buffer memory buf) internal pure {
encodeIndefiniteLengthType(buf, MAJOR_TYPE_CONTENT_FREE);
}
}
pragma solidity ^0.4.24;
import "./Chainlink.sol";
import "./ENSInterface.sol";
import "./LinkTokenInterface.sol";
import "./ChainlinkRequestInterface.sol";
import "./PointerInterface.sol";
import { ENSResolver as ENSResolver_Chainlink } from "./ENSResolver.sol";
import { SafeMath as SafeMath_Chainlink } from "./SafeMath.sol";
/**
* @title The ChainlinkClient contract
* @notice Contract writers can inherit this contract in order to create requests for the
* Chainlink network
*/
contract ChainlinkClient {
using Chainlink for Chainlink.Request;
using SafeMath_Chainlink for uint256;
uint256 constant internal LINK = 10**18;
uint256 constant private AMOUNT_OVERRIDE = 0;
address constant private SENDER_OVERRIDE = 0x0;
uint256 constant private ARGS_VERSION = 1;
bytes32 constant private ENS_TOKEN_SUBNAME = keccak256("link");
bytes32 constant private ENS_ORACLE_SUBNAME = keccak256("oracle");
address constant private LINK_TOKEN_POINTER = 0x859a5A7bBe21C56AbB8AAc36B0A0B5D258D0445b;
ENSInterface private ens;
bytes32 private ensNode;
LinkTokenInterface private link;
ChainlinkRequestInterface private oracle;
uint256 private requests = 1;
mapping(bytes32 => address) private pendingRequests;
event ChainlinkRequested(bytes32 indexed id);
event ChainlinkFulfilled(bytes32 indexed id);
event ChainlinkCancelled(bytes32 indexed id);
/**
* @notice Creates a request that can hold additional parameters
* @param _specId The Job Specification ID that the request will be created for
* @param _callbackAddress The callback address that the response will be sent to
* @param _callbackFunctionSignature The callback function signature to use for the callback address
* @return A Chainlink Request struct in memory
*/
function buildChainlinkRequest(
bytes32 _specId,
address _callbackAddress,
bytes4 _callbackFunctionSignature
) internal pure returns (Chainlink.Request memory) {
Chainlink.Request memory req;
return req.initialize(_specId, _callbackAddress, _callbackFunctionSignature);
}
/**
* @notice Creates a Chainlink request to the stored oracle address
* @dev Calls `chainlinkRequestTo` with the stored oracle address
* @param _req The initialized Chainlink Request
* @param _payment The amount of LINK to send for the request
* @return The request ID
*/
function sendChainlinkRequest(Chainlink.Request memory _req, uint256 _payment)
internal
returns (bytes32)
{
return sendChainlinkRequestTo(oracle, _req, _payment);
}
/**
* @notice Creates a Chainlink request to the specified oracle address
* @dev Generates and stores a request ID, increments the local nonce, and uses `transferAndCall` to
* send LINK which creates a request on the target oracle contract.
* Emits ChainlinkRequested event.
* @param _oracle The address of the oracle for the request
* @param _req The initialized Chainlink Request
* @param _payment The amount of LINK to send for the request
* @return The request ID
*/
function sendChainlinkRequestTo(address _oracle, Chainlink.Request memory _req, uint256 _payment)
internal
returns (bytes32 requestId)
{
requestId = keccak256(abi.encodePacked(this, requests));
_req.nonce = requests;
pendingRequests[requestId] = _oracle;
emit ChainlinkRequested(requestId);
require(link.transferAndCall(_oracle, _payment, encodeRequest(_req)), "unable to transferAndCall to oracle");
requests += 1;
return requestId;
}
/**
* @notice Allows a request to be cancelled if it has not been fulfilled
* @dev Requires keeping track of the expiration value emitted from the oracle contract.
* Deletes the request from the `pendingRequests` mapping.
* Emits ChainlinkCancelled event.
* @param _requestId The request ID
* @param _payment The amount of LINK sent for the request
* @param _callbackFunc The callback function specified for the request
* @param _expiration The time of the expiration for the request
*/
function cancelChainlinkRequest(
bytes32 _requestId,
uint256 _payment,
bytes4 _callbackFunc,
uint256 _expiration
)
internal
{
ChainlinkRequestInterface requested = ChainlinkRequestInterface(pendingRequests[_requestId]);
delete pendingRequests[_requestId];
emit ChainlinkCancelled(_requestId);
requested.cancelOracleRequest(_requestId, _payment, _callbackFunc, _expiration);
}
/**
* @notice Sets the stored oracle address
* @param _oracle The address of the oracle contract
*/
function setChainlinkOracle(address _oracle) internal {
oracle = ChainlinkRequestInterface(_oracle);
}
/**
* @notice Sets the LINK token address
* @param _link The address of the LINK token contract
*/
function setChainlinkToken(address _link) internal {
link = LinkTokenInterface(_link);
}
/**
* @notice Sets the Chainlink token address for the public
* network as given by the Pointer contract
*/
function setPublicChainlinkToken() internal {
setChainlinkToken(PointerInterface(LINK_TOKEN_POINTER).getAddress());
}
/**
* @notice Retrieves the stored address of the LINK token
* @return The address of the LINK token
*/
function chainlinkTokenAddress()
internal
view
returns (address)
{
return address(link);
}
/**
* @notice Retrieves the stored address of the oracle contract
* @return The address of the oracle contract
*/
function chainlinkOracleAddress()
internal
view
returns (address)
{
return address(oracle);
}
/**
* @notice Allows for a request which was created on another contract to be fulfilled
* on this contract
* @param _oracle The address of the oracle contract that will fulfill the request
* @param _requestId The request ID used for the response
*/
function addChainlinkExternalRequest(address _oracle, bytes32 _requestId)
internal
notPendingRequest(_requestId)
{
pendingRequests[_requestId] = _oracle;
}
/**
* @notice Sets the stored oracle and LINK token contracts with the addresses resolved by ENS
* @dev Accounts for subnodes having different resolvers
* @param _ens The address of the ENS contract
* @param _node The ENS node hash
*/
function useChainlinkWithENS(address _ens, bytes32 _node)
internal
{
ens = ENSInterface(_ens);
ensNode = _node;
bytes32 linkSubnode = keccak256(abi.encodePacked(ensNode, ENS_TOKEN_SUBNAME));
ENSResolver_Chainlink resolver = ENSResolver_Chainlink(ens.resolver(linkSubnode));
setChainlinkToken(resolver.addr(linkSubnode));
updateChainlinkOracleWithENS();
}
/**
* @notice Sets the stored oracle contract with the address resolved by ENS
* @dev This may be called on its own as long as `useChainlinkWithENS` has been called previously
*/
function updateChainlinkOracleWithENS()
internal
{
bytes32 oracleSubnode = keccak256(abi.encodePacked(ensNode, ENS_ORACLE_SUBNAME));
ENSResolver_Chainlink resolver = ENSResolver_Chainlink(ens.resolver(oracleSubnode));
setChainlinkOracle(resolver.addr(oracleSubnode));
}
/**
* @notice Encodes the request to be sent to the oracle contract
* @dev The Chainlink node expects values to be in order for the request to be picked up. Order of types
* will be validated in the oracle contract.
* @param _req The initialized Chainlink Request
* @return The bytes payload for the `transferAndCall` method
*/
function encodeRequest(Chainlink.Request memory _req)
private
view
returns (bytes memory)
{
return abi.encodeWithSelector(
oracle.oracleRequest.selector,
SENDER_OVERRIDE, // Sender value - overridden by onTokenTransfer by the requesting contract's address
AMOUNT_OVERRIDE, // Amount value - overridden by onTokenTransfer by the actual amount of LINK sent
_req.id,
_req.callbackAddress,
_req.callbackFunctionId,
_req.nonce,
ARGS_VERSION,
_req.buf.buf);
}
/**
* @notice Ensures that the fulfillment is valid for this contract
* @dev Use if the contract developer prefers methods instead of modifiers for validation
* @param _requestId The request ID for fulfillment
*/
function validateChainlinkCallback(bytes32 _requestId)
internal
recordChainlinkFulfillment(_requestId)
// solhint-disable-next-line no-empty-blocks
{}
/**
* @dev Reverts if the sender is not the oracle of the request.
* Emits ChainlinkFulfilled event.
* @param _requestId The request ID for fulfillment
*/
modifier recordChainlinkFulfillment(bytes32 _requestId) {
require(msg.sender == pendingRequests[_requestId], "Source must be the oracle of the request");
delete pendingRequests[_requestId];
emit ChainlinkFulfilled(_requestId);
_;
}
/**
* @dev Reverts if the request is already pending
* @param _requestId The request ID for fulfillment
*/
modifier notPendingRequest(bytes32 _requestId) {
require(pendingRequests[_requestId] == address(0), "Request is already pending");
_;
}
}
pragma solidity ^0.4.24;
interface ChainlinkRequestInterface {
function oracleRequest(
address sender,
uint256 payment,
bytes32 id,
address callbackAddress,
bytes4 callbackFunctionId,
uint256 nonce,
uint256 version,
bytes data
) external;
function cancelOracleRequest(
bytes32 requestId,
uint256 payment,
bytes4 callbackFunctionId,
uint256 expiration
) external;
}
pragma solidity ^0.5.0;
/*
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with GSN meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
contract Context {
// Empty internal constructor, to prevent people from mistakenly deploying
// an instance of this contract, which should be used via inheritance.
constructor () internal { }
// solhint-disable-previous-line no-empty-blocks
function _msgSender() internal view returns (address payable) {
return msg.sender;
}
function _msgData() internal view returns (bytes memory) {
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
return msg.data;
}
}
pragma solidity ^0.5.0;
import "./Context.sol";
import "./IERC20.sol";
import "./SafeMath5.sol";
import "./SafeERC20.sol";
import "./ReentrancyGuard.sol";
/**
* @title Crowdsale
* @dev Crowdsale is a base contract for managing a token crowdsale,
* allowing investors to purchase tokens with ether. This contract implements
* such functionality in its most fundamental form and can be extended to provide additional
* functionality and/or custom behavior.
* The external interface represents the basic interface for purchasing tokens, and conforms
* the base architecture for crowdsales. It is *not* intended to be modified / overridden.
* The internal interface conforms the extensible and modifiable surface of crowdsales. Override
* the methods to add functionality. Consider using 'super' where appropriate to concatenate
* behavior.
*/
contract Crowdsale is Context, ReentrancyGuard {
using SafeMath for uint256;
using SafeERC20 for IERC20;
// The token being sold
IERC20 private _token;
// Address where funds are collected
address payable private _wallet;
// How many token units a buyer gets per wei.
// The rate is the conversion between wei and the smallest and indivisible token unit.
// So, if you are using a rate of 1 with a ERC20Detailed token with 3 decimals called TOK
// 1 wei will give you 1 unit, or 0.001 TOK.
uint256 private _rate;
// Amount of wei raised
uint256 private _weiRaised;
/**
* Event for token purchase logging
* @param purchaser who paid for the tokens
* @param beneficiary who got the tokens
* @param value weis paid for purchase
* @param amount amount of tokens purchased
*/
event TokensPurchased(address indexed purchaser, address indexed beneficiary, uint256 value, uint256 amount);
/**
* @param rate Number of token units a buyer gets per wei
* @dev The rate is the conversion between wei and the smallest and indivisible
* token unit. So, if you are using a rate of 1 with a ERC20Detailed token
* with 3 decimals called TOK, 1 wei will give you 1 unit, or 0.001 TOK.
* @param wallet Address where collected funds will be forwarded to
* @param token Address of the token being sold
*/
constructor (uint256 rate, address payable wallet, IERC20 token) public {
require(rate > 0, "Crowdsale: rate is 0");
require(wallet != address(0), "Crowdsale: wallet is the zero address");
require(address(token) != address(0), "Crowdsale: token is the zero address");
_rate = rate;
_wallet = wallet;
_token = token;
}
/**
* @dev fallback function ***DO NOT OVERRIDE***
* Note that other contracts will transfer funds with a base gas stipend
* of 2300, which is not enough to call buyTokens. Consider calling
* buyTokens directly when purchasing tokens from a contract.
*/
function () external payable {
buyTokens(_msgSender());
}
/**
* @return the token being sold.
*/
function token() public view returns (IERC20) {
return _token;
}
/**
* @return the address where funds are collected.
*/
function wallet() public view returns (address payable) {
return _wallet;
}
/**
* @return the number of token units a buyer gets per wei.
*/
function rate() public view returns (uint256) {
return _rate;
}
/**
* @return the amount of wei raised.
*/
function weiRaised() public view returns (uint256) {
return _weiRaised;
}
/**
* @dev low level token purchase ***DO NOT OVERRIDE***
* This function has a non-reentrancy guard, so it shouldn't be called by
* another `nonReentrant` function.
* @param beneficiary Recipient of the token purchase
*/
function buyTokens(address beneficiary) public nonReentrant payable {
uint256 weiAmount = msg.value;
_preValidatePurchase(beneficiary, weiAmount);
// calculate token amount to be created
uint256 tokens = _getTokenAmount(weiAmount);
// update state
_weiRaised = _weiRaised.add(weiAmount);
_processPurchase(beneficiary, tokens);
emit TokensPurchased(_msgSender(), beneficiary, weiAmount, tokens);
_updatePurchasingState(beneficiary, weiAmount);
_forwardFunds();
_postValidatePurchase(beneficiary, weiAmount);
}
/**
* @dev Validation of an incoming purchase. Use require statements to revert state when conditions are not met.
* Use `super` in contracts that inherit from Crowdsale to extend their validations.
* Example from CappedCrowdsale.sol's _preValidatePurchase method:
* super._preValidatePurchase(beneficiary, weiAmount);
* require(weiRaised().add(weiAmount) <= cap);
* @param beneficiary Address performing the token purchase
* @param weiAmount Value in wei involved in the purchase
*/
function _preValidatePurchase(address beneficiary, uint256 weiAmount) internal view {
require(beneficiary != address(0), "Crowdsale: beneficiary is the zero address");
require(weiAmount != 0, "Crowdsale: weiAmount is 0");
this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
}
/**
* @dev Validation of an executed purchase. Observe state and use revert statements to undo rollback when valid
* conditions are not met.
* @param beneficiary Address performing the token purchase
* @param weiAmount Value in wei involved in the purchase
*/
function _postValidatePurchase(address beneficiary, uint256 weiAmount) internal view {
// solhint-disable-previous-line no-empty-blocks
}
/**
* @dev Source of tokens. Override this method to modify the way in which the crowdsale ultimately gets and sends
* its tokens.
* @param beneficiary Address performing the token purchase
* @param tokenAmount Number of tokens to be emitted
*/
function _deliverTokens(address beneficiary, uint256 tokenAmount) internal {
_token.safeTransfer(beneficiary, tokenAmount);
}
/**
* @dev Executed when a purchase has been validated and is ready to be executed. Doesn't necessarily emit/send
* tokens.
* @param beneficiary Address receiving the tokens
* @param tokenAmount Number of tokens to be purchased
*/
function _processPurchase(address beneficiary, uint256 tokenAmount) internal {
_deliverTokens(beneficiary, tokenAmount);
}
/**
* @dev Override for extensions that require an internal state to check for validity (current user contributions,
* etc.)
* @param beneficiary Address receiving the tokens
* @param weiAmount Value in wei involved in the purchase
*/
function _updatePurchasingState(address beneficiary, uint256 weiAmount) internal {
// solhint-disable-previous-line no-empty-blocks
}
/**
* @dev Override to extend the way in which ether is converted to tokens.
* @param weiAmount Value in wei to be converted into tokens
* @return Number of tokens that can be purchased with the specified _weiAmount
*/
function _getTokenAmount(uint256 weiAmount) internal view returns (uint256) {
return weiAmount.mul(_rate);
}
/**
* @dev Determines how ETH is stored/forwarded on purchases.
*/
function _forwardFunds()
internal
{
_wallet.transfer(msg.value);
}
function _setRate(uint256 _newRate)
internal
{
require(_newRate > 0, "Crowdsale: rate is 0");
_rate = _newRate;
}
}
pragma solidity ^0.4.24;
interface ENS {
// Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner);
// Logged when the resolver for a node changes.
event NewResolver(bytes32 indexed node, address resolver);
// Logged when the TTL of a node changes
event NewTTL(bytes32 indexed node, uint64 ttl);
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public;
function setResolver(bytes32 node, address resolver) public;
function setOwner(bytes32 node, address owner) public;
function setTTL(bytes32 node, uint64 ttl) public;
function owner(bytes32 node) public view returns (address);
function resolver(bytes32 node) public view returns (address);
function ttl(bytes32 node) public view returns (uint64);
}
pragma solidity ^0.4.24;
interface ENSInterface {
// Logged when the owner of a node assigns a new owner to a subnode.
event NewOwner(bytes32 indexed node, bytes32 indexed label, address owner);
// Logged when the owner of a node transfers ownership to a new account.
event Transfer(bytes32 indexed node, address owner);
// Logged when the resolver for a node changes.
event NewResolver(bytes32 indexed node, address resolver);
// Logged when the TTL of a node changes
event NewTTL(bytes32 indexed node, uint64 ttl);
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) external;
function setResolver(bytes32 node, address resolver) external;
function setOwner(bytes32 node, address owner) external;
function setTTL(bytes32 node, uint64 ttl) external;
function owner(bytes32 node) external view returns (address);
function resolver(bytes32 node) external view returns (address);
function ttl(bytes32 node) external view returns (uint64);
}
pragma solidity ^0.4.24;
import "./ENS.sol";
/**
* The ENS registry contract.
*/
contract ENSRegistry is ENS {
struct Record {
address owner;
address resolver;
uint64 ttl;
}
mapping (bytes32 => Record) records;
// Permits modifications only by the owner of the specified node.
modifier only_owner(bytes32 node) {
require(records[node].owner == msg.sender);
_;
}
/**
* @dev Constructs a new ENS registrar.
*/
constructor() public {
records[0x0].owner = msg.sender;
}
/**
* @dev Transfers ownership of a node to a new address. May only be called by the current owner of the node.
* @param node The node to transfer ownership of.
* @param owner The address of the new owner.
*/
function setOwner(bytes32 node, address owner) public only_owner(node) {
emit Transfer(node, owner);
records[node].owner = owner;
}
/**
* @dev Transfers ownership of a subnode keccak256(node, label) to a new address. May only be called by the owner of the parent node.
* @param node The parent node.
* @param label The hash of the label specifying the subnode.
* @param owner The address of the new owner.
*/
function setSubnodeOwner(bytes32 node, bytes32 label, address owner) public only_owner(node) {
bytes32 subnode = keccak256(abi.encodePacked(node, label));
emit NewOwner(node, label, owner);
records[subnode].owner = owner;
}
/**
* @dev Sets the resolver address for the specified node.
* @param node The node to update.
* @param resolver The address of the resolver.
*/
function setResolver(bytes32 node, address resolver) public only_owner(node) {
emit NewResolver(node, resolver);
records[node].resolver = resolver;
}
/**
* @dev Sets the TTL for the specified node.
* @param node The node to update.
* @param ttl The TTL in seconds.
*/
function setTTL(bytes32 node, uint64 ttl) public only_owner(node) {
emit NewTTL(node, ttl);
records[node].ttl = ttl;
}
/**
* @dev Returns the address that owns the specified node.
* @param node The specified node.
* @return address of the owner.
*/
function owner(bytes32 node) public view returns (address) {
return records[node].owner;
}
/**
* @dev Returns the address of the resolver for the specified node.
* @param node The specified node.
* @return address of the resolver.
*/
function resolver(bytes32 node) public view returns (address) {
return records[node].resolver;
}
/**
* @dev Returns the TTL of a node, and any records associated with it.
* @param node The specified node.
* @return ttl of the node.
*/
function ttl(bytes32 node) public view returns (uint64) {
return records[node].ttl;
}
}
pragma solidity ^0.4.24;
contract ENSResolver {
function addr(bytes32 node) public view returns (address);
}
pragma solidity ^0.5.0;
import "./linkERC20.sol";
contract ERC677 is linkERC20 {
function transferAndCall(address to, uint value, bytes memory data) public returns (bool success);
event Transfer(address indexed from, address indexed to, uint value, bytes data);
}
pragma solidity ^0.5.0;
contract ERC677Receiver {
function onTokenTransfer(address _sender, uint _value, bytes memory _data) public;
}
pragma solidity ^0.5.0;
import "./ERC677.sol";
import "./ERC677Receiver.sol";
contract ERC677Token is ERC677 {
/**
* @dev transfer token to a contract address with additional data if the recipient is a contact.
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
* @param _data The extra data to be passed to the receiving contract.
*/
function transferAndCall(address _to, uint _value, bytes memory _data)
public
returns (bool success)
{
transfer(_to, _value);
emit Transfer(msg.sender, _to, _value, _data);
if (isContract(_to)) {
contractFallback(_to, _value, _data);
}
return true;
}
function contractFallback(address _to, uint _value, bytes memory _data)
private
{
ERC677Receiver receiver = ERC677Receiver(_to);
receiver.onTokenTransfer(msg.sender, _value, _data);
}
function isContract(address _addr)
private
view
returns (bool hasCode)
{
uint length;
assembly { length := extcodesize(_addr) }
return length > 0;
}
}
pragma solidity ^0.4.24;
import "./ChainlinkClient.sol";
import "./SafeMath.sol";
import "./Ownable.sol";
/**
* @title An example Chainlink contract with aggregation
* @notice Requesters can use this contract as a framework for creating
* requests to multiple Chainlink nodes and running aggregation
* as the contract receives answers.
*/
contract ExecutorPublicPriceAggregator is ChainlinkClient, Ownable {
using SafeMath for uint256;
struct Answer {
uint256 minimumResponses;
uint256 maxResponses;
uint256 transactionID;
uint256[] responses;
}
struct Transaction {
address destination;
uint value;
bytes data;
bool executed;
}
uint256 public currentAnswer;
uint256 public latestCompletedAnswer;
uint256 public updatedHeight;
uint256 public paymentAmount;
uint256 public minimumResponses;
bytes32[] public jobIds;
address[] public oracles;
Transaction[] public transactions;
uint256 public answerCounter = 1;
mapping(address => bool) public blacklistedRequesters;
mapping(bytes32 => uint256) public requestAnswers;
mapping(uint256 => Answer) public answers;
mapping(address => uint256) public requestTokens;
uint256 constant public MAX_ORACLE_COUNT = 45;
event ResponseReceived(uint256 indexed response, uint256 indexed answerId, address indexed sender);
event AnswerUpdated(uint256 indexed current, uint256 indexed answerId);
event Execution(uint indexed transactionId, uint256 indexed answerId);
event ExecutionFailure(uint indexed transactionId, uint256 indexed answerId);
/**
* @notice Deploy with the address of the LINK token and arrays of matching
* length containing the addresses of the oracles and their corresponding
* Job IDs.
* @dev Sets the LinkToken address for the network, addresses of the oracles,
* and jobIds in storage.
* @param _link The address of the LINK token
* @param _paymentAmount the amount of LINK to be sent to each oracle for each request
* @param _minimumResponses the minimum number of responses
* before an answer will be calculated
* @param _oracles An array of oracle addresses
* @param _jobIds An array of Job IDs
*/
constructor(
address _link,
uint256 _paymentAmount,
uint256 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
)
public
Ownable()
{
setChainlinkToken(_link);
updateRequestDetails(
_paymentAmount,
_minimumResponses,
_oracles,
_jobIds
);
transactions.push(
Transaction(address(0), 0, "", true)
);
}
/**
* @notice Creates a Chainlink request for each oracle in the oracles array.
* @dev This example does not include request parameters. Reference any documentation
* associated with the Job IDs used to determine the required parameters per-request.
*/
function requestRateUpdate()
external
ensureAuthorizedRequester()
ensurePayment()
{
_requestRate();
answers[answerCounter].minimumResponses = minimumResponses;
answers[answerCounter].maxResponses = oracles.length;
answerCounter = answerCounter.add(1);
}
function requestRateUpdateWithTransaction(
address _destination,
uint _value,
bytes _data
)
external
payable
ensureAuthorizedRequester()
ensurePayment()
ensureValue(_value)
{
_requestRate();
answers[answerCounter].minimumResponses = minimumResponses;
answers[answerCounter].maxResponses = oracles.length;
answers[answerCounter].transactionID = transactions.push(Transaction(_destination, _value, _data, false)) - 1;
answerCounter = answerCounter.add(1);
}
/**
* @notice Called by the owner to permission other addresses to generate new
* requests to oracles.
* @param _requester the address whose permissions are being set
* @param _blacklisted boolean that determines whether the requester is
* blacklisted or not
*/
function setAuthorization(address _requester, bool _blacklisted)
external
onlyOwner()
{
blacklistedRequesters[_requester] = _blacklisted;
}
/**
* @notice Cancels an outstanding Chainlink request.
* The oracle contract requires the request ID and additional metadata to
* validate the cancellation. Only old answers can be cancelled.
* @param _requestId is the identifier for the chainlink request being cancelled
* @param _payment is the amount of LINK paid to the oracle for the request
* @param _expiration is the time when the request expires
*/
function cancelRequest(
bytes32 _requestId,
uint256 _payment,
uint256 _expiration
)
external
ensureAuthorizedRequester()
{
uint256 answerId = requestAnswers[_requestId];
require(answerId < latestCompletedAnswer, "Cannot modify an in-progress answer");
cancelChainlinkRequest(
_requestId,
_payment,
this.chainlinkCallback.selector,
_expiration
);
delete requestAnswers[_requestId];
answers[answerId].responses.push(0);
deleteAnswer(answerId);
}
/**
* @notice Receives the answer from the Chainlink node.
* @dev This function can only be called by the oracle that received the request.
* @param _clRequestId The Chainlink request ID associated with the answer
* @param _response The answer provided by the Chainlink node
*/
function chainlinkCallback(bytes32 _clRequestId, uint256 _response)
external
{
validateChainlinkCallback(_clRequestId);
uint256 answerId = requestAnswers[_clRequestId];
delete requestAnswers[_clRequestId];
answers[answerId].responses.push(_response);
emit ResponseReceived(_response, answerId, msg.sender);
updateLatestAnswer(answerId);
deleteAnswer(answerId);
}
/**
* @notice Called by the owner to kill the contract. This transfers all LINK
* balance and ETH balance (if there is any) to the owner.
*/
function destroy()
external
onlyOwner()
{
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
transferLINK(owner, link.balanceOf(address(this)));
selfdestruct(owner);
}
/**
* @notice Updates the arrays of oracles and jobIds with new values,
* overwriting the old values.
* @dev Arrays are validated to be equal length.
* @param _paymentAmount the amount of LINK to be sent to each oracle for each request
* @param _minimumResponses the minimum number of responses
* before an answer will be calculated
* @param _oracles An array of oracle addresses
* @param _jobIds An array of Job IDs
*/
function updateRequestDetails(
uint256 _paymentAmount,
uint256 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
)
public
onlyOwner()
validateAnswerRequirements(_minimumResponses, _oracles, _jobIds)
{
paymentAmount = _paymentAmount;
minimumResponses = _minimumResponses;
jobIds = _jobIds;
oracles = _oracles;
}
/**
* @notice Allows the owner of the contract to withdraw any LINK balance
* available on the contract.
* @dev The contract will need to have a LINK balance in order to create requests.
* @param _recipient The address to receive the LINK tokens
* @param _amount The amount of LINK to send from the contract
*/
function transferLINK(address _recipient, uint256 _amount)
public
onlyOwner()
{
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(link.transfer(_recipient, _amount), "LINK transfer failed");
}
function calculateRequestFee()
public
view
returns (uint256 _linkFee)
{
_linkFee = paymentAmount * oracles.length;
}
function _requestRate()
private
{
Chainlink.Request memory request;
bytes32 requestId;
for (uint i = 0; i < oracles.length; i++) {
request = buildChainlinkRequest(jobIds[i], this, this.chainlinkCallback.selector);
requestId = sendChainlinkRequestTo(oracles[i], request, paymentAmount);
requestAnswers[requestId] = answerCounter;
}
}
/**
* @dev Performs aggregation of the answers received from the Chainlink nodes.
* Assumes that at least half the oracles are honest and so can't contol the
* middle of the ordered responses.
* @param _answerId The answer ID associated with the group of requests
*/
function updateLatestAnswer(uint256 _answerId)
private
ensureMinResponsesReceived(_answerId)
ensureOnlyLatestAnswer(_answerId)
{
uint256 responseLength = answers[_answerId].responses.length;
uint256 middleIndex = responseLength.div(2);
if (responseLength % 2 == 0) {
uint256 median1 = quickselect(answers[_answerId].responses, middleIndex);
uint256 median2 = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
currentAnswer = median1.add(median2) / 2; // signed integers are not supported by SafeMath
} else {
currentAnswer = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
}
latestCompletedAnswer = _answerId;
updatedHeight = block.number;
emit AnswerUpdated(currentAnswer, _answerId);
uint256 _id = answers[_answerId].transactionID;
if (_id > 0 && transactions[_id].executed == false) {
Transaction storage txn = transactions[_id];
txn.executed = true;
if (externalCall(txn.destination, txn.value, txn.data.length, txn.data))
emit Execution(_id, _answerId);
else {
emit ExecutionFailure(_id, _answerId);
txn.executed = false;
}
}
}
/**
* @dev Returns the kth value of the ordered array
* See: http://www.cs.yale.edu/homes/aspnes/pinewiki/QuickSelect.html
* @param _a The list of elements to pull from
* @param _k The index, 1 based, of the elements you want to pull from when ordered
*/
function quickselect(uint256[] memory _a, uint256 _k)
private
pure
returns (uint256)
{
uint256[] memory a = _a;
uint256 k = _k;
uint256 aLen = a.length;
uint256[] memory a1 = new uint256[](aLen);
uint256[] memory a2 = new uint256[](aLen);
uint256 a1Len;
uint256 a2Len;
uint256 pivot;
uint256 i;
while (true) {
pivot = a[aLen.div(2)];
a1Len = 0;
a2Len = 0;
for (i = 0; i < aLen; i++) {
if (a[i] < pivot) {
a1[a1Len] = a[i];
a1Len++;
} else if (a[i] > pivot) {
a2[a2Len] = a[i];
a2Len++;
}
}
if (k <= a1Len) {
aLen = a1Len;
(a, a1) = swap(a, a1);
} else if (k > (aLen.sub(a2Len))) {
k = k.sub(aLen.sub(a2Len));
aLen = a2Len;
(a, a2) = swap(a, a2);
} else {
return pivot;
}
}
}
/**
* @dev Swaps the pointers to two uint256 arrays in memory
* @param _a The pointer to the first in memory array
* @param _b The pointer to the second in memory array
*/
function swap(uint256[] memory _a, uint256[] memory _b)
private
pure
returns(uint256[] memory, uint256[] memory)
{
return (_b, _a);
}
/**
* @dev Cleans up the answer record if all responses have been received.
* @param _answerId The identifier of the answer to be deleted
*/
function deleteAnswer(uint256 _answerId)
private
ensureAllResponsesReceived(_answerId)
{
delete answers[_answerId];
}
// call has been separated into its own function in order to take advantage
// of the Solidity's code generator to produce a loop that copies tx.data into memory.
function externalCall(address destination, uint value, uint dataLength, bytes data)
internal
returns (bool)
{
bool result;
assembly {
let x := mload(0x40) // "Allocate" memory for output (0x40 is where "free memory" pointer is stored by convention)
let d := add(data, 32) // First 32 bytes are the padded length of data, so exclude that
result := call(
sub(gas, 34710), // 34710 is the value that solidity is currently emitting
// It includes callGas (700) + callVeryLow (3, to pay for SUB) + callValueTransferGas (9000) +
// callNewAccountGas (25000, in case the destination address does not exist and needs creating)
destination,
value,
d,
dataLength, // Size of the input (in bytes) - this is what fixes the padding problem
x,
0 // Output is ignored, therefore the output size is zero
)
}
return result;
}
/**
* @dev Prevents taking an action if the minimum number of responses has not
* been received for an answer.
* @param _answerId The the identifier of the answer that keeps track of the responses.
*/
modifier ensureMinResponsesReceived(uint256 _answerId) {
if (answers[_answerId].responses.length >= answers[_answerId].minimumResponses) {
_;
}
}
/**
* @dev Prevents taking an action if not all responses are received for an answer.
* @param _answerId The the identifier of the answer that keeps track of the responses.
*/
modifier ensureAllResponsesReceived(uint256 _answerId) {
if (answers[_answerId].responses.length == answers[_answerId].maxResponses) {
_;
}
}
/**
* @dev Prevents taking an action if a newer answer has been recorded.
* @param _answerId The current answer's identifier.
* Answer IDs are in ascending order.
*/
modifier ensureOnlyLatestAnswer(uint256 _answerId) {
if (latestCompletedAnswer <= _answerId) {
_;
}
}
/**
* @dev Ensures corresponding number of oracles and jobs.
* @param _oracles The list of oracles.
* @param _jobIds The list of jobs.
*/
modifier validateAnswerRequirements(
uint256 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
) {
require(_oracles.length <= MAX_ORACLE_COUNT, "cannot have more than 45 oracles");
require(_oracles.length >= _minimumResponses, "must have at least as many oracles as responses");
require(_oracles.length == _jobIds.length, "must have exactly as many oracles as job IDs");
_;
}
/**
* @dev Reverts if `msg.sender` is blacklisted to make requests.
*/
modifier ensureAuthorizedRequester() {
require(
!blacklistedRequesters[msg.sender] || msg.sender == owner,
"Not an authorized address for creating requests"
);
_;
}
modifier ensurePayment() {
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(
link.transferFrom(msg.sender, address(this), oracles.length * paymentAmount),
"LINK transferFrom failed"
);
_;
}
modifier ensureValue(uint256 _value) {
require(
msg.value >= _value,
"Insufficient value amount sent for callback transaction"
);
_;
}
}
pragma solidity ^0.5.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP. Does not include
* the optional functions; to access them see `ERC20Detailed`.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a `Transfer` event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through `transferFrom`. This is
* zero by default.
*
* This value changes when `approve` or `transferFrom` are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* > Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an `Approval` event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a `Transfer` event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to `approve`. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity ^0.5.0;
import './linkERC20Basic.sol';
import "./SafeMath.sol";
/**
* @title Basic token
* @dev Basic version of StandardToken, with no allowances.
*/
contract linkBasicToken is linkERC20Basic {
using SafeMath for uint256;
mapping(address => uint256) balances;
/**
* @dev transfer token for a specified address
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint256 _value)
public
returns (bool)
{
balances[msg.sender] = balances[msg.sender].sub(_value);
balances[_to] = balances[_to].add(_value);
emit Transfer(msg.sender, _to, _value);
return true;
}
/**
* @dev Gets the balance of the specified address.
* @param _owner The address to query the the balance of.
* @return An uint256 representing the amount owned by the passed address.
*/
function balanceOf(address _owner) public view returns (uint256 balance) {
return balances[_owner];
}
}
pragma solidity ^0.5.0;
import './linkERC20Basic.sol';
/**
* @title ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/20
*/
contract linkERC20 is linkERC20Basic {
function allowance(address owner, address spender) public view returns (uint256);
function transferFrom(address from, address to, uint256 value) public returns (bool);
function approve(address spender, uint256 value) public returns (bool);
event Approval(address indexed owner, address indexed spender, uint256 value);
}
pragma solidity ^0.5.0;
/**
* @title ERC20Basic
* @dev Simpler version of ERC20 interface
* @dev see https://github.com/ethereum/EIPs/issues/179
*/
contract linkERC20Basic {
uint256 public totalSupply;
function balanceOf(address who) public view returns (uint256);
function transfer(address to, uint256 value) public returns (bool);
event Transfer(address indexed from, address indexed to, uint256 value);
}
pragma solidity ^0.5.0;
import './linkBasicToken.sol';
import './linkERC20.sol';
/**
* @title Standard ERC20 token
*
* @dev Implementation of the basic standard token.
* @dev https://github.com/ethereum/EIPs/issues/20
* @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol
*/
contract linkStandardToken is linkERC20, linkBasicToken {
mapping (address => mapping (address => uint256)) allowed;
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value)
public
returns (bool)
{
uint256 _allowance = allowed[_from][msg.sender];
// Check is not needed because sub(_allowance, _value) will already throw if this condition is not met
// require (_value <= _allowance);
balances[_from] = balances[_from].sub(_value);
balances[_to] = balances[_to].add(_value);
allowed[_from][msg.sender] = _allowance.sub(_value);
emit Transfer(_from, _to, _value);
return true;
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value)
public
returns (bool)
{
allowed[msg.sender][_spender] = _value;
emit Approval(msg.sender, _spender, _value);
return true;
}
/**
* @dev Function to check the amount of tokens that an owner allowed to a spender.
* @param _owner address The address which owns the funds.
* @param _spender address The address which will spend the funds.
* @return A uint256 specifying the amount of tokens still available for the spender.
*/
function allowance(address _owner, address _spender)
public
view
returns (uint256 remaining)
{
return allowed[_owner][_spender];
}
/*
* approve should be called when allowed[_spender] == 0. To increment
* allowed value is better to use this function to avoid 2 calls (and wait until
* the first transaction is mined)
* From MonolithDAO Token.sol
*/
function increaseApproval (address _spender, uint _addedValue)
public
returns (bool success)
{
allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue);
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
function decreaseApproval (address _spender, uint _subtractedValue)
public
returns (bool success)
{
uint oldValue = allowed[msg.sender][_spender];
if (_subtractedValue > oldValue) {
allowed[msg.sender][_spender] = 0;
} else {
allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue);
}
emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]);
return true;
}
}
pragma solidity ^0.5.0;
import './ERC677Token.sol';
import './linkStandardToken.sol';
contract LinkToken is linkStandardToken, ERC677Token {
uint public constant totalSupply = 10**27;
string public constant name = "EWLink Token";
uint8 public constant decimals = 18;
string public constant symbol = "EWLINK";
modifier validRecipient(address _recipient) {
require(_recipient != address(0) && _recipient != address(this));
_;
}
constructor()
public
{
balances[msg.sender] = totalSupply;
}
/**
* @dev transfer token to a specified address with additional data if the recipient is a contract.
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
* @param _data The extra data to be passed to the receiving contract.
*/
function transferAndCall(address _to, uint _value, bytes memory _data)
public
validRecipient(_to)
returns (bool success)
{
return super.transferAndCall(_to, _value, _data);
}
/**
* @dev transfer token to a specified address.
* @param _to The address to transfer to.
* @param _value The amount to be transferred.
*/
function transfer(address _to, uint _value)
public
validRecipient(_to)
returns (bool success)
{
return super.transfer(_to, _value);
}
/**
* @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.
* @param _spender The address which will spend the funds.
* @param _value The amount of tokens to be spent.
*/
function approve(address _spender, uint256 _value)
public
validRecipient(_spender)
returns (bool)
{
return super.approve(_spender, _value);
}
/**
* @dev Transfer tokens from one address to another
* @param _from address The address which you want to send tokens from
* @param _to address The address which you want to transfer to
* @param _value uint256 the amount of tokens to be transferred
*/
function transferFrom(address _from, address _to, uint256 _value)
public
validRecipient(_to)
returns (bool)
{
return super.transferFrom(_from, _to, _value);
}
}
pragma solidity ^0.4.24;
interface LinkTokenInterface {
function allowance(address owner, address spender) external returns (uint256 remaining);
function approve(address spender, uint256 value) external returns (bool success);
function balanceOf(address owner) external returns (uint256 balance);
function decimals() external returns (uint8 decimalPlaces);
function decreaseApproval(address spender, uint256 addedValue) external returns (bool success);
function increaseApproval(address spender, uint256 subtractedValue) external;
function name() external returns (string tokenName);
function symbol() external returns (string tokenSymbol);
function totalSupply() external returns (uint256 totalTokensIssued);
function transfer(address to, uint256 value) external returns (bool success);
function transferAndCall(address to, uint256 value, bytes data) external returns (bool success);
function transferFrom(address from, address to, uint256 value) external returns (bool success);
}
pragma solidity ^0.5.0;
import "./Crowdsale.sol";
import "./Ownable.sol";
contract LinkTokenSale is Crowdsale, Ownable {
constructor(
uint256 rate,
address payable wallet,
address token
)
public
Crowdsale(rate, wallet, IERC20(token)) {
}
function setRate(uint256 _newRate)
public
onlyOwner
{
_setRate(_newRate);
}
}
pragma solidity ^0.4.24;
interface OracleInterface {
function fulfillOracleRequest(
bytes32 requestId,
uint256 payment,
address callbackAddress,
bytes4 callbackFunctionId,
uint256 expiration,
bytes32 data
) external returns (bool);
function getAuthorizationStatus(address node) external view returns (bool);
function setFulfillmentPermission(address node, bool allowed) external;
function withdraw(address recipient, uint256 amount) external;
function withdrawable() external view returns (uint256);
}
pragma solidity >= 0.4.24;
/**
* @title Ownable
* @dev The Ownable contract has an owner address, and provides basic authorization control
* functions, this simplifies the implementation of "user permissions".
*/
contract Ownable {
address public owner;
event OwnershipRenounced(address indexed previousOwner);
event OwnershipTransferred(
address indexed previousOwner,
address indexed newOwner
);
/**
* @dev The Ownable constructor sets the original `owner` of the contract to the sender
* account.
*/
constructor() public {
owner = msg.sender;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
/**
* @dev Allows the current owner to relinquish control of the contract.
* @notice Renouncing to ownership will leave the contract without an owner.
* It will not be possible to call the functions with the `onlyOwner`
* modifier anymore.
*/
function renounceOwnership() public onlyOwner {
emit OwnershipRenounced(owner);
owner = address(0);
}
/**
* @dev Allows the current owner to transfer control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function transferOwnership(address _newOwner) public onlyOwner {
_transferOwnership(_newOwner);
}
/**
* @dev Transfers control of the contract to a newOwner.
* @param _newOwner The address to transfer ownership to.
*/
function _transferOwnership(address _newOwner) internal {
require(_newOwner != address(0));
emit OwnershipTransferred(owner, _newOwner);
owner = _newOwner;
}
}
pragma solidity ^0.4.24;
interface PointerInterface {
function getAddress() external view returns (address);
}
pragma solidity ^0.4.24;
import "./ChainlinkClient.sol";
import "./SafeMath.sol";
import "./Ownable.sol";
/**
* @title An example Chainlink contract with aggregation
* @notice Requesters can use this contract as a framework for creating
* requests to multiple Chainlink nodes and running aggregation
* as the contract receives answers.
*/
contract PriceAggregator is ChainlinkClient, Ownable {
using SafeMath for uint256;
struct Answer {
uint256 minimumResponses;
uint256 maxResponses;
uint256[] responses;
}
uint256 public currentAnswer;
uint256 public latestCompletedAnswer;
uint256 public updatedHeight;
uint256 public paymentAmount;
uint256 public minimumResponses;
bytes32[] public jobIds;
address[] public oracles;
uint256 private answerCounter = 1;
mapping(address => bool) public blacklistedRequesters;
mapping(bytes32 => uint256) private requestAnswers;
mapping(uint256 => Answer) private answers;
uint256 constant private MAX_ORACLE_COUNT = 45;
event ResponseReceived(uint256 indexed response, uint256 indexed answerId, address indexed sender);
event AnswerUpdated(uint256 indexed current, uint256 indexed answerId);
/**
* @notice Deploy with the address of the LINK token and arrays of matching
* length containing the addresses of the oracles and their corresponding
* Job IDs.
* @dev Sets the LinkToken address for the network, addresses of the oracles,
* and jobIds in storage.
* @param _link The address of the LINK token
* @param _paymentAmount the amount of LINK to be sent to each oracle for each request
* @param _minimumResponses the minimum number of responses
* before an answer will be calculated
* @param _oracles An array of oracle addresses
* @param _jobIds An array of Job IDs
*/
constructor(
address _link,
uint256 _paymentAmount,
uint256 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
) public Ownable() {
setChainlinkToken(_link);
updateRequestDetails(
_paymentAmount,
_minimumResponses,
_oracles,
_jobIds
);
}
/**
* @notice Creates a Chainlink request for each oracle in the oracles array.
* @dev This example does not include request parameters. Reference any documentation
* associated with the Job IDs used to determine the required parameters per-request.
*/
function requestRateUpdate()
external
ensureAuthorizedRequester()
{
Chainlink.Request memory request;
bytes32 requestId;
uint256 oraclePayment = paymentAmount;
for (uint i = 0; i < oracles.length; i++) {
request = buildChainlinkRequest(jobIds[i], this, this.chainlinkCallback.selector);
requestId = sendChainlinkRequestTo(oracles[i], request, oraclePayment);
requestAnswers[requestId] = answerCounter;
}
answers[answerCounter].minimumResponses = minimumResponses;
answers[answerCounter].maxResponses = oracles.length;
answerCounter = answerCounter.add(1);
}
/**
* @notice Receives the answer from the Chainlink node.
* @dev This function can only be called by the oracle that received the request.
* @param _clRequestId The Chainlink request ID associated with the answer
* @param _response The answer provided by the Chainlink node
*/
function chainlinkCallback(bytes32 _clRequestId, uint256 _response)
external
{
validateChainlinkCallback(_clRequestId);
uint256 answerId = requestAnswers[_clRequestId];
delete requestAnswers[_clRequestId];
answers[answerId].responses.push(_response);
emit ResponseReceived(_response, answerId, msg.sender);
updateLatestAnswer(answerId);
deleteAnswer(answerId);
}
/**
* @notice Called by the owner to permission other addresses to generate new
* requests to oracles.
* @param _requester the address whose permissions are being set
* @param _blacklisted boolean that determines whether the requester is
* blacklisted or not
*/
function setAuthorization(address _requester, bool _blacklisted)
external
onlyOwner()
{
blacklistedRequesters[_requester] = _blacklisted;
}
/**
* @notice Cancels an outstanding Chainlink request.
* The oracle contract requires the request ID and additional metadata to
* validate the cancellation. Only old answers can be cancelled.
* @param _requestId is the identifier for the chainlink request being cancelled
* @param _payment is the amount of LINK paid to the oracle for the request
* @param _expiration is the time when the request expires
*/
function cancelRequest(
bytes32 _requestId,
uint256 _payment,
uint256 _expiration
)
external
ensureAuthorizedRequester()
{
uint256 answerId = requestAnswers[_requestId];
require(answerId < latestCompletedAnswer, "Cannot modify an in-progress answer");
cancelChainlinkRequest(
_requestId,
_payment,
this.chainlinkCallback.selector,
_expiration
);
delete requestAnswers[_requestId];
answers[answerId].responses.push(0);
deleteAnswer(answerId);
}
/**
* @notice Called by the owner to kill the contract. This transfers all LINK
* balance and ETH balance (if there is any) to the owner.
*/
function destroy()
external
onlyOwner()
{
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
transferLINK(owner, link.balanceOf(address(this)));
selfdestruct(owner);
}
/**
* @notice Updates the arrays of oracles and jobIds with new values,
* overwriting the old values.
* @dev Arrays are validated to be equal length.
* @param _paymentAmount the amount of LINK to be sent to each oracle for each request
* @param _minimumResponses the minimum number of responses
* before an answer will be calculated
* @param _oracles An array of oracle addresses
* @param _jobIds An array of Job IDs
*/
function updateRequestDetails(
uint256 _paymentAmount,
uint256 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
)
public
onlyOwner()
validateAnswerRequirements(_minimumResponses, _oracles, _jobIds)
{
paymentAmount = _paymentAmount;
minimumResponses = _minimumResponses;
jobIds = _jobIds;
oracles = _oracles;
}
/**
* @notice Allows the owner of the contract to withdraw any LINK balance
* available on the contract.
* @dev The contract will need to have a LINK balance in order to create requests.
* @param _recipient The address to receive the LINK tokens
* @param _amount The amount of LINK to send from the contract
*/
function transferLINK(address _recipient, uint256 _amount)
public
onlyOwner()
{
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(link.transfer(_recipient, _amount), "LINK transfer failed");
}
/**
* @dev Performs aggregation of the answers received from the Chainlink nodes.
* Assumes that at least half the oracles are honest and so can't contol the
* middle of the ordered responses.
* @param _answerId The answer ID associated with the group of requests
*/
function updateLatestAnswer(uint256 _answerId)
private
ensureMinResponsesReceived(_answerId)
ensureOnlyLatestAnswer(_answerId)
{
uint256 responseLength = answers[_answerId].responses.length;
uint256 middleIndex = responseLength.div(2);
if (responseLength % 2 == 0) {
uint256 median1 = quickselect(answers[_answerId].responses, middleIndex);
uint256 median2 = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
currentAnswer = median1.add(median2) / 2; // signed integers are not supported by SafeMath
} else {
currentAnswer = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
}
latestCompletedAnswer = _answerId;
updatedHeight = block.number;
emit AnswerUpdated(currentAnswer, _answerId);
}
/**
* @dev Returns the kth value of the ordered array
* See: http://www.cs.yale.edu/homes/aspnes/pinewiki/QuickSelect.html
* @param _a The list of elements to pull from
* @param _k The index, 1 based, of the elements you want to pull from when ordered
*/
function quickselect(uint256[] memory _a, uint256 _k)
private
pure
returns (uint256)
{
uint256[] memory a = _a;
uint256 k = _k;
uint256 aLen = a.length;
uint256[] memory a1 = new uint256[](aLen);
uint256[] memory a2 = new uint256[](aLen);
uint256 a1Len;
uint256 a2Len;
uint256 pivot;
uint256 i;
while (true) {
pivot = a[aLen.div(2)];
a1Len = 0;
a2Len = 0;
for (i = 0; i < aLen; i++) {
if (a[i] < pivot) {
a1[a1Len] = a[i];
a1Len++;
} else if (a[i] > pivot) {
a2[a2Len] = a[i];
a2Len++;
}
}
if (k <= a1Len) {
aLen = a1Len;
(a, a1) = swap(a, a1);
} else if (k > (aLen.sub(a2Len))) {
k = k.sub(aLen.sub(a2Len));
aLen = a2Len;
(a, a2) = swap(a, a2);
} else {
return pivot;
}
}
}
/**
* @dev Swaps the pointers to two uint256 arrays in memory
* @param _a The pointer to the first in memory array
* @param _b The pointer to the second in memory array
*/
function swap(uint256[] memory _a, uint256[] memory _b)
private
pure
returns(uint256[] memory, uint256[] memory)
{
return (_b, _a);
}
/**
* @dev Cleans up the answer record if all responses have been received.
* @param _answerId The identifier of the answer to be deleted
*/
function deleteAnswer(uint256 _answerId)
private
ensureAllResponsesReceived(_answerId)
{
delete answers[_answerId];
}
/**
* @dev Prevents taking an action if the minimum number of responses has not
* been received for an answer.
* @param _answerId The the identifier of the answer that keeps track of the responses.
*/
modifier ensureMinResponsesReceived(uint256 _answerId) {
if (answers[_answerId].responses.length >= answers[_answerId].minimumResponses) {
_;
}
}
/**
* @dev Prevents taking an action if not all responses are received for an answer.
* @param _answerId The the identifier of the answer that keeps track of the responses.
*/
modifier ensureAllResponsesReceived(uint256 _answerId) {
if (answers[_answerId].responses.length == answers[_answerId].maxResponses) {
_;
}
}
/**
* @dev Prevents taking an action if a newer answer has been recorded.
* @param _answerId The current answer's identifier.
* Answer IDs are in ascending order.
*/
modifier ensureOnlyLatestAnswer(uint256 _answerId) {
if (latestCompletedAnswer <= _answerId) {
_;
}
}
/**
* @dev Ensures corresponding number of oracles and jobs.
* @param _oracles The list of oracles.
* @param _jobIds The list of jobs.
*/
modifier validateAnswerRequirements(
uint256 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
) {
require(_oracles.length <= MAX_ORACLE_COUNT, "cannot have more than 45 oracles");
require(_oracles.length >= _minimumResponses, "must have at least as many oracles as responses");
require(_oracles.length == _jobIds.length, "must have exactly as many oracles as job IDs");
_;
}
/**
* @dev Reverts if `msg.sender` is blacklisted to make requests.
*/
modifier ensureAuthorizedRequester() {
require(
!blacklistedRequesters[msg.sender] || msg.sender == owner,
"Not an authorized address for creating requests"
);
_;
}
}
pragma solidity ^0.4.24;
import "./ChainlinkClient.sol";
import "./SafeMath.sol";
import "./Ownable.sol";
/**
* @title An example Chainlink contract with aggregation
* @notice Requesters can use this contract as a framework for creating
* requests to multiple Chainlink nodes and running aggregation
* as the contract receives answers.
*/
contract PublicPriceAggregator is ChainlinkClient, Ownable {
using SafeMath for uint256;
struct Answer {
uint256 minimumResponses;
uint256 maxResponses;
uint256[] responses;
}
uint256 public currentAnswer;
uint256 public latestCompletedAnswer;
uint256 public updatedHeight;
uint256 public paymentAmount;
uint256 public minimumResponses;
bytes32[] public jobIds;
address[] public oracles;
uint256 private answerCounter = 1;
mapping(address => bool) public blacklistedRequesters;
mapping(bytes32 => uint256) private requestAnswers;
mapping(uint256 => Answer) private answers;
mapping(address => uint256) public requestTokens;
uint256 constant private MAX_ORACLE_COUNT = 45;
event ResponseReceived(uint256 indexed response, uint256 indexed answerId, address indexed sender);
event AnswerUpdated(uint256 indexed current, uint256 indexed answerId);
/**
* @notice Deploy with the address of the LINK token and arrays of matching
* length containing the addresses of the oracles and their corresponding
* Job IDs.
* @dev Sets the LinkToken address for the network, addresses of the oracles,
* and jobIds in storage.
* @param _link The address of the LINK token
* @param _paymentAmount the amount of LINK to be sent to each oracle for each request
* @param _minimumResponses the minimum number of responses
* before an answer will be calculated
* @param _oracles An array of oracle addresses
* @param _jobIds An array of Job IDs
*/
constructor(
address _link,
uint256 _paymentAmount,
uint256 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
) public Ownable() {
setChainlinkToken(_link);
updateRequestDetails(
_paymentAmount,
_minimumResponses,
_oracles,
_jobIds
);
}
/**
* @notice Creates a Chainlink request for each oracle in the oracles array.
* @dev This example does not include request parameters. Reference any documentation
* associated with the Job IDs used to determine the required parameters per-request.
*/
function requestRateUpdate()
external
ensureAuthorizedRequester()
ensurePayment()
{
Chainlink.Request memory request;
bytes32 requestId;
for (uint i = 0; i < oracles.length; i++) {
request = buildChainlinkRequest(jobIds[i], this, this.chainlinkCallback.selector);
requestId = sendChainlinkRequestTo(oracles[i], request, paymentAmount);
requestAnswers[requestId] = answerCounter;
}
answers[answerCounter].minimumResponses = minimumResponses;
answers[answerCounter].maxResponses = oracles.length;
answerCounter = answerCounter.add(1);
}
/**
* @notice Receives the answer from the Chainlink node.
* @dev This function can only be called by the oracle that received the request.
* @param _clRequestId The Chainlink request ID associated with the answer
* @param _response The answer provided by the Chainlink node
*/
function chainlinkCallback(bytes32 _clRequestId, uint256 _response)
external
{
validateChainlinkCallback(_clRequestId);
uint256 answerId = requestAnswers[_clRequestId];
delete requestAnswers[_clRequestId];
answers[answerId].responses.push(_response);
emit ResponseReceived(_response, answerId, msg.sender);
updateLatestAnswer(answerId);
deleteAnswer(answerId);
}
/**
* @notice Called by the owner to permission other addresses to generate new
* requests to oracles.
* @param _requester the address whose permissions are being set
* @param _blacklisted boolean that determines whether the requester is
* blacklisted or not
*/
function setAuthorization(address _requester, bool _blacklisted)
external
onlyOwner()
{
blacklistedRequesters[_requester] = _blacklisted;
}
/**
* @notice Cancels an outstanding Chainlink request.
* The oracle contract requires the request ID and additional metadata to
* validate the cancellation. Only old answers can be cancelled.
* @param _requestId is the identifier for the chainlink request being cancelled
* @param _payment is the amount of LINK paid to the oracle for the request
* @param _expiration is the time when the request expires
*/
function cancelRequest(
bytes32 _requestId,
uint256 _payment,
uint256 _expiration
)
external
ensureAuthorizedRequester()
{
uint256 answerId = requestAnswers[_requestId];
require(answerId < latestCompletedAnswer, "Cannot modify an in-progress answer");
cancelChainlinkRequest(
_requestId,
_payment,
this.chainlinkCallback.selector,
_expiration
);
delete requestAnswers[_requestId];
answers[answerId].responses.push(0);
deleteAnswer(answerId);
}
/**
* @notice Called by the owner to kill the contract. This transfers all LINK
* balance and ETH balance (if there is any) to the owner.
*/
function destroy()
external
onlyOwner()
{
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
transferLINK(owner, link.balanceOf(address(this)));
selfdestruct(owner);
}
/**
* @notice Updates the arrays of oracles and jobIds with new values,
* overwriting the old values.
* @dev Arrays are validated to be equal length.
* @param _paymentAmount the amount of LINK to be sent to each oracle for each request
* @param _minimumResponses the minimum number of responses
* before an answer will be calculated
* @param _oracles An array of oracle addresses
* @param _jobIds An array of Job IDs
*/
function updateRequestDetails(
uint256 _paymentAmount,
uint256 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
)
public
onlyOwner()
validateAnswerRequirements(_minimumResponses, _oracles, _jobIds)
{
paymentAmount = _paymentAmount;
minimumResponses = _minimumResponses;
jobIds = _jobIds;
oracles = _oracles;
}
/**
* @notice Allows the owner of the contract to withdraw any LINK balance
* available on the contract.
* @dev The contract will need to have a LINK balance in order to create requests.
* @param _recipient The address to receive the LINK tokens
* @param _amount The amount of LINK to send from the contract
*/
function transferLINK(address _recipient, uint256 _amount)
public
onlyOwner()
{
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(link.transfer(_recipient, _amount), "LINK transfer failed");
}
function calculateRequestFee()
public
view
returns (uint256 _linkFee)
{
_linkFee = paymentAmount * oracles.length;
}
/**
* @dev Performs aggregation of the answers received from the Chainlink nodes.
* Assumes that at least half the oracles are honest and so can't contol the
* middle of the ordered responses.
* @param _answerId The answer ID associated with the group of requests
*/
function updateLatestAnswer(uint256 _answerId)
private
ensureMinResponsesReceived(_answerId)
ensureOnlyLatestAnswer(_answerId)
{
uint256 responseLength = answers[_answerId].responses.length;
uint256 middleIndex = responseLength.div(2);
if (responseLength % 2 == 0) {
uint256 median1 = quickselect(answers[_answerId].responses, middleIndex);
uint256 median2 = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
currentAnswer = median1.add(median2) / 2; // signed integers are not supported by SafeMath
} else {
currentAnswer = quickselect(answers[_answerId].responses, middleIndex.add(1)); // quickselect is 1 indexed
}
latestCompletedAnswer = _answerId;
updatedHeight = block.number;
emit AnswerUpdated(currentAnswer, _answerId);
}
/**
* @dev Returns the kth value of the ordered array
* See: http://www.cs.yale.edu/homes/aspnes/pinewiki/QuickSelect.html
* @param _a The list of elements to pull from
* @param _k The index, 1 based, of the elements you want to pull from when ordered
*/
function quickselect(uint256[] memory _a, uint256 _k)
private
pure
returns (uint256)
{
uint256[] memory a = _a;
uint256 k = _k;
uint256 aLen = a.length;
uint256[] memory a1 = new uint256[](aLen);
uint256[] memory a2 = new uint256[](aLen);
uint256 a1Len;
uint256 a2Len;
uint256 pivot;
uint256 i;
while (true) {
pivot = a[aLen.div(2)];
a1Len = 0;
a2Len = 0;
for (i = 0; i < aLen; i++) {
if (a[i] < pivot) {
a1[a1Len] = a[i];
a1Len++;
} else if (a[i] > pivot) {
a2[a2Len] = a[i];
a2Len++;
}
}
if (k <= a1Len) {
aLen = a1Len;
(a, a1) = swap(a, a1);
} else if (k > (aLen.sub(a2Len))) {
k = k.sub(aLen.sub(a2Len));
aLen = a2Len;
(a, a2) = swap(a, a2);
} else {
return pivot;
}
}
}
/**
* @dev Swaps the pointers to two uint256 arrays in memory
* @param _a The pointer to the first in memory array
* @param _b The pointer to the second in memory array
*/
function swap(uint256[] memory _a, uint256[] memory _b)
private
pure
returns(uint256[] memory, uint256[] memory)
{
return (_b, _a);
}
/**
* @dev Cleans up the answer record if all responses have been received.
* @param _answerId The identifier of the answer to be deleted
*/
function deleteAnswer(uint256 _answerId)
private
ensureAllResponsesReceived(_answerId)
{
delete answers[_answerId];
}
/**
* @dev Prevents taking an action if the minimum number of responses has not
* been received for an answer.
* @param _answerId The the identifier of the answer that keeps track of the responses.
*/
modifier ensureMinResponsesReceived(uint256 _answerId) {
if (answers[_answerId].responses.length >= answers[_answerId].minimumResponses) {
_;
}
}
/**
* @dev Prevents taking an action if not all responses are received for an answer.
* @param _answerId The the identifier of the answer that keeps track of the responses.
*/
modifier ensureAllResponsesReceived(uint256 _answerId) {
if (answers[_answerId].responses.length == answers[_answerId].maxResponses) {
_;
}
}
/**
* @dev Prevents taking an action if a newer answer has been recorded.
* @param _answerId The current answer's identifier.
* Answer IDs are in ascending order.
*/
modifier ensureOnlyLatestAnswer(uint256 _answerId) {
if (latestCompletedAnswer <= _answerId) {
_;
}
}
/**
* @dev Ensures corresponding number of oracles and jobs.
* @param _oracles The list of oracles.
* @param _jobIds The list of jobs.
*/
modifier validateAnswerRequirements(
uint256 _minimumResponses,
address[] _oracles,
bytes32[] _jobIds
) {
require(_oracles.length <= MAX_ORACLE_COUNT, "cannot have more than 45 oracles");
require(_oracles.length >= _minimumResponses, "must have at least as many oracles as responses");
require(_oracles.length == _jobIds.length, "must have exactly as many oracles as job IDs");
_;
}
/**
* @dev Reverts if `msg.sender` is blacklisted to make requests.
*/
modifier ensureAuthorizedRequester() {
require(
!blacklistedRequesters[msg.sender] || msg.sender == owner,
"Not an authorized address for creating requests"
);
_;
}
modifier ensurePayment() {
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(
link.transferFrom(msg.sender, address(this), oracles.length * paymentAmount),
"LINK transferFrom failed"
);
_;
}
}
pragma solidity ^0.4.24;
import "./ENS.sol";
/**
* A simple resolver anyone can use; only allows the owner of a node to set its
* address.
*/
contract PublicResolver {
bytes4 constant INTERFACE_META_ID = 0x01ffc9a7;
bytes4 constant ADDR_INTERFACE_ID = 0x3b3b57de;
bytes4 constant CONTENT_INTERFACE_ID = 0xd8389dc5;
bytes4 constant NAME_INTERFACE_ID = 0x691f3431;
bytes4 constant ABI_INTERFACE_ID = 0x2203ab56;
bytes4 constant PUBKEY_INTERFACE_ID = 0xc8690233;
bytes4 constant TEXT_INTERFACE_ID = 0x59d1d43c;
bytes4 constant MULTIHASH_INTERFACE_ID = 0xe89401a1;
event AddrChanged(bytes32 indexed node, address a);
event ContentChanged(bytes32 indexed node, bytes32 hash);
event NameChanged(bytes32 indexed node, string name);
event ABIChanged(bytes32 indexed node, uint256 indexed contentType);
event PubkeyChanged(bytes32 indexed node, bytes32 x, bytes32 y);
event TextChanged(bytes32 indexed node, string indexedKey, string key);
event MultihashChanged(bytes32 indexed node, bytes hash);
struct PublicKey {
bytes32 x;
bytes32 y;
}
struct Record {
address addr;
bytes32 content;
string name;
PublicKey pubkey;
mapping(string=>string) text;
mapping(uint256=>bytes) abis;
bytes multihash;
}
ENS ens;
mapping (bytes32 => Record) records;
modifier only_owner(bytes32 node) {
require(ens.owner(node) == msg.sender);
_;
}
/**
* Constructor.
* @param ensAddr The ENS registrar contract.
*/
constructor(ENS ensAddr) public {
ens = ensAddr;
}
/**
* Sets the address associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param addr The address to set.
*/
function setAddr(bytes32 node, address addr) public only_owner(node) {
records[node].addr = addr;
emit AddrChanged(node, addr);
}
/**
* Sets the content hash associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* Note that this resource type is not standardized, and will likely change
* in future to a resource type based on multihash.
* @param node The node to update.
* @param hash The content hash to set
*/
function setContent(bytes32 node, bytes32 hash) public only_owner(node) {
records[node].content = hash;
emit ContentChanged(node, hash);
}
/**
* Sets the multihash associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param hash The multihash to set
*/
function setMultihash(bytes32 node, bytes hash) public only_owner(node) {
records[node].multihash = hash;
emit MultihashChanged(node, hash);
}
/**
* Sets the name associated with an ENS node, for reverse records.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param name The name to set.
*/
function setName(bytes32 node, string name) public only_owner(node) {
records[node].name = name;
emit NameChanged(node, name);
}
/**
* Sets the ABI associated with an ENS node.
* Nodes may have one ABI of each content type. To remove an ABI, set it to
* the empty string.
* @param node The node to update.
* @param contentType The content type of the ABI
* @param data The ABI data.
*/
function setABI(bytes32 node, uint256 contentType, bytes data) public only_owner(node) {
// Content types must be powers of 2
require(((contentType - 1) & contentType) == 0);
records[node].abis[contentType] = data;
emit ABIChanged(node, contentType);
}
/**
* Sets the SECP256k1 public key associated with an ENS node.
* @param node The ENS node to query
* @param x the X coordinate of the curve point for the public key.
* @param y the Y coordinate of the curve point for the public key.
*/
function setPubkey(bytes32 node, bytes32 x, bytes32 y) public only_owner(node) {
records[node].pubkey = PublicKey(x, y);
emit PubkeyChanged(node, x, y);
}
/**
* Sets the text data associated with an ENS node and key.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param key The key to set.
* @param value The text data value to set.
*/
function setText(bytes32 node, string key, string value) public only_owner(node) {
records[node].text[key] = value;
emit TextChanged(node, key, key);
}
/**
* Returns the text data associated with an ENS node and key.
* @param node The ENS node to query.
* @param key The text data key to query.
* @return The associated text data.
*/
function text(bytes32 node, string key) public view returns (string) {
return records[node].text[key];
}
/**
* Returns the SECP256k1 public key associated with an ENS node.
* Defined in EIP 619.
* @param node The ENS node to query
* @return x, y the X and Y coordinates of the curve point for the public key.
*/
function pubkey(bytes32 node) public view returns (bytes32 x, bytes32 y) {
return (records[node].pubkey.x, records[node].pubkey.y);
}
/**
* Returns the ABI associated with an ENS node.
* Defined in EIP205.
* @param node The ENS node to query
* @param contentTypes A bitwise OR of the ABI formats accepted by the caller.
* @return contentType The content type of the return value
* @return data The ABI data
*/
function ABI(bytes32 node, uint256 contentTypes) public view returns (uint256 contentType, bytes data) {
Record storage record = records[node];
for (contentType = 1; contentType <= contentTypes; contentType <<= 1) {
if ((contentType & contentTypes) != 0 && record.abis[contentType].length > 0) {
data = record.abis[contentType];
return;
}
}
contentType = 0;
}
/**
* Returns the name associated with an ENS node, for reverse records.
* Defined in EIP181.
* @param node The ENS node to query.
* @return The associated name.
*/
function name(bytes32 node) public view returns (string) {
return records[node].name;
}
/**
* Returns the content hash associated with an ENS node.
* Note that this resource type is not standardized, and will likely change
* in future to a resource type based on multihash.
* @param node The ENS node to query.
* @return The associated content hash.
*/
function content(bytes32 node) public view returns (bytes32) {
return records[node].content;
}
/**
* Returns the multihash associated with an ENS node.
* @param node The ENS node to query.
* @return The associated multihash.
*/
function multihash(bytes32 node) public view returns (bytes) {
return records[node].multihash;
}
/**
* Returns the address associated with an ENS node.
* @param node The ENS node to query.
* @return The associated address.
*/
function addr(bytes32 node) public view returns (address) {
return records[node].addr;
}
/**
* Returns true if the resolver implements the interface specified by the provided hash.
* @param interfaceID The ID of the interface to check for.
* @return True if the contract implements the requested interface.
*/
function supportsInterface(bytes4 interfaceID) public pure returns (bool) {
return interfaceID == ADDR_INTERFACE_ID ||
interfaceID == CONTENT_INTERFACE_ID ||
interfaceID == NAME_INTERFACE_ID ||
interfaceID == ABI_INTERFACE_ID ||
interfaceID == PUBKEY_INTERFACE_ID ||
interfaceID == TEXT_INTERFACE_ID ||
interfaceID == MULTIHASH_INTERFACE_ID ||
interfaceID == INTERFACE_META_ID;
}
}
pragma solidity ^0.5.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the `nonReentrant` modifier
* available, which can be aplied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*/
contract ReentrancyGuard {
/// @dev counter to allow mutex lock with only one SSTORE operation
uint256 private _guardCounter;
constructor () internal {
// The counter starts at one to prevent changing it from zero to a non-zero
// value, which is a more expensive operation.
_guardCounter = 1;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_guardCounter += 1;
uint256 localCounter = _guardCounter;
_;
require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
}
}
pragma solidity ^0.5.0;
import "./IERC20.sol";
import "./SafeMath5.sol";
import "./Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using SafeMath for uint256;
using Address for address;
function safeTransfer(IERC20 token, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
function safeApprove(IERC20 token, address spender, uint256 value) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
// solhint-disable-next-line max-line-length
require((value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).add(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
uint256 newAllowance = token.allowance(address(this), spender).sub(value);
callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves.
// A Solidity high level call has three parts:
// 1. The target address is checked to verify it contains contract code
// 2. The call itself is made, and success asserted
// 3. The return value is decoded, which in turn checks the size of the returned data.
// solhint-disable-next-line max-line-length
require(address(token).isContract(), "SafeERC20: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = address(token).call(data);
require(success, "SafeERC20: low-level call failed");
if (returndata.length > 0) { // Return data is optional
// solhint-disable-next-line max-line-length
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}
pragma solidity ^0.4.24;
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
/**
* @dev Multiplies two numbers, throws on overflow.
*/
function mul(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
// Gas optimization: this is cheaper than asserting 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
if (_a == 0) {
return 0;
}
c = _a * _b;
assert(c / _a == _b);
return c;
}
/**
* @dev Integer division of two numbers, truncating the quotient.
*/
function div(uint256 _a, uint256 _b) internal pure returns (uint256) {
// assert(_b > 0); // Solidity automatically throws when dividing by 0
// uint256 c = _a / _b;
// assert(_a == _b * c + _a % _b); // There is no case in which this doesn't hold
return _a / _b;
}
/**
* @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).
*/
function sub(uint256 _a, uint256 _b) internal pure returns (uint256) {
assert(_b <= _a);
return _a - _b;
}
/**
* @dev Adds two numbers, throws on overflow.
*/
function add(uint256 _a, uint256 _b) internal pure returns (uint256 c) {
c = _a + _b;
assert(c >= _a);
return c;
}
}
pragma solidity ^0.5.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
uint256 c = a - b;
return c;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) {
return 0;
}
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers. Reverts on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
// Solidity only automatically asserts when dividing by 0
require(b > 0, "SafeMath: division by zero");
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* Reverts when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
require(b != 0, "SafeMath: modulo by zero");
return a % b;
}
}
pragma solidity ^0.4.24;
library SignedSafeMath {
/**
* @dev Adds two int256s and makes sure the result doesn't overflow. Signed
* integers aren't supported by the SafeMath library, thus this method
* @param _a The first number to be added
* @param _a The second number to be added
*/
function add(int256 _a, int256 _b)
internal
pure
returns (int256)
{
int256 c = _a + _b;
require((_b >= 0 && c >= _a) || (_b < 0 && c < _a), "SignedSafeMath: addition overflow");
return c;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment