Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x61022060 | 19904245 | 627 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
RedstonePriceFeed
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 1000 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.17;
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {RedstoneConsumerNumericBase} from
"@redstone-finance/evm-connector/contracts/core/RedstoneConsumerNumericBase.sol";
import {PriceFeedType} from "@gearbox-protocol/sdk-gov/contracts/PriceFeedType.sol";
import {IUpdatablePriceFeed} from "@gearbox-protocol/core-v2/contracts/interfaces/IPriceFeed.sol";
import {IncorrectPriceException} from "@gearbox-protocol/core-v3/contracts/interfaces/IExceptions.sol";
/// @dev Max period that the payload can be backward in time relative to the block
uint256 constant MAX_DATA_TIMESTAMP_DELAY_SECONDS = 10 minutes;
/// @dev Max period that the payload can be forward in time relative to the block
uint256 constant MAX_DATA_TIMESTAMP_AHEAD_SECONDS = 1 minutes;
/// @dev Max number of authorized signers
uint256 constant MAX_SIGNERS = 10;
interface IRedstonePriceFeedExceptions {
/// @notice Thrown when trying to construct a price feed with incorrect signers threshold
error IncorrectSignersThresholdException();
/// @notice Thrown when the provided set of signers is smaller than the threshold
error NotEnoughSignersException();
/// @notice Thrown when the provided set of signers contains duplicates
error DuplicateSignersException();
/// @notice Thrown when attempting to push an update with the payload that is older than the last
/// update payload, or too far from the current block timestamp
error RedstonePayloadTimestampIncorrect();
/// @notice Thrown when data package timestamp is not equal to expected payload timestamp
error DataPackageTimestampIncorrect();
}
interface IRedstonePriceFeedEvents {
/// @notice Emitted when a successful price update is pushed
/// @param price New USD price of the token with 8 decimals
event UpdatePrice(uint256 price);
}
/// @title Redstone price feed
contract RedstonePriceFeed is
IUpdatablePriceFeed,
IRedstonePriceFeedExceptions,
IRedstonePriceFeedEvents,
RedstoneConsumerNumericBase
{
using SafeCast for uint256;
PriceFeedType public constant override priceFeedType = PriceFeedType.REDSTONE_ORACLE;
uint256 public constant override version = 3_00;
uint8 public constant override decimals = 8;
bool public constant override skipPriceCheck = false;
bool public constant override updatable = true;
/// @notice Token for which the prices are provided
address public immutable token;
/// @notice ID of the asset in Redstone's payload
bytes32 public immutable dataFeedId;
address public immutable signerAddress0;
address public immutable signerAddress1;
address public immutable signerAddress2;
address public immutable signerAddress3;
address public immutable signerAddress4;
address public immutable signerAddress5;
address public immutable signerAddress6;
address public immutable signerAddress7;
address public immutable signerAddress8;
address public immutable signerAddress9;
/// @dev Minimal number of unique signatures from authorized signers required to validate a payload
uint8 internal immutable _signersThreshold;
/// @notice The last stored price value
uint128 public lastPrice;
/// @notice The timestamp of the last update's payload
uint40 public lastPayloadTimestamp;
constructor(address _token, bytes32 _dataFeedId, address[MAX_SIGNERS] memory _signers, uint8 signersThreshold) {
if (signersThreshold == 0 || signersThreshold > MAX_SIGNERS) revert IncorrectSignersThresholdException();
unchecked {
uint256 numSigners;
for (uint256 i; i < MAX_SIGNERS; ++i) {
if (_signers[i] == address(0)) continue;
for (uint256 j = i + 1; j < MAX_SIGNERS; ++j) {
if (_signers[j] == _signers[i]) revert DuplicateSignersException();
}
++numSigners;
}
if (numSigners < signersThreshold) revert NotEnoughSignersException();
}
token = _token;
dataFeedId = _dataFeedId; // U:[RPF-1]
signerAddress0 = _signers[0];
signerAddress1 = _signers[1];
signerAddress2 = _signers[2];
signerAddress3 = _signers[3];
signerAddress4 = _signers[4];
signerAddress5 = _signers[5];
signerAddress6 = _signers[6];
signerAddress7 = _signers[7];
signerAddress8 = _signers[8];
signerAddress9 = _signers[9];
_signersThreshold = signersThreshold; // U:[RPF-1]
}
/// @notice Price feed description
function description() external view override returns (string memory) {
return string(abi.encodePacked(ERC20(token).symbol(), " / USD Redstone price feed")); // U:[RPF-1]
}
/// @notice Returns the USD price of the token with 8 decimals and the last update timestamp
function latestRoundData() external view override returns (uint80, int256, uint256, uint256, uint80) {
return (0, int256(uint256(lastPrice)), 0, lastPayloadTimestamp, 0); // U:[RPF-2]
}
/// @notice Saves validated price retrieved from the passed Redstone payload
/// @param data A data blob with with 2 parts:
/// - A timestamp expected to be in all Redstone data packages
/// - Redstone payload with price update
function updatePrice(bytes calldata data) external override {
(uint256 expectedPayloadTimestamp,) = abi.decode(data, (uint256, bytes));
// We want to minimize price update execution, in case, e.g., when several users submit
// the same price update in a short span of time. So only updates with a larger payload timestamp
// are fully validated and applied
if (expectedPayloadTimestamp <= lastPayloadTimestamp) return; // U:[RPF-4]
// We validate and set the payload timestamp here. Data packages' timestamps being equal
// to the expected timestamp is checked in `validateTimestamp()`, which is called
// from inside `getOracleNumericValueFromTxMsg`
_validateExpectedPayloadTimestamp(expectedPayloadTimestamp);
lastPayloadTimestamp = uint40(expectedPayloadTimestamp); // U:[RPF-2,5]
uint256 priceValue = getOracleNumericValueFromTxMsg(dataFeedId); // U:[RPF-7]
if (priceValue == 0) revert IncorrectPriceException(); // U:[RPF-8]
if (priceValue != lastPrice) {
lastPrice = priceValue.toUint128(); // U:[RPF-2,5]
emit UpdatePrice(priceValue); // U:[RPF-2,5]
}
}
/// @notice Returns the number of unique signatures required to validate a payload
function getUniqueSignersThreshold() public view virtual override returns (uint8) {
return _signersThreshold;
}
/// @notice Returns the index of the provided signer or reverts if the address is not a signer
function getAuthorisedSignerIndex(address signerAddress) public view virtual override returns (uint8) {
if (signerAddress == address(0)) revert SignerNotAuthorised(signerAddress);
if (signerAddress == signerAddress0) return 0;
if (signerAddress == signerAddress1) return 1;
if (signerAddress == signerAddress2) return 2;
if (signerAddress == signerAddress3) return 3;
if (signerAddress == signerAddress4) return 4;
if (signerAddress == signerAddress5) return 5;
if (signerAddress == signerAddress6) return 6;
if (signerAddress == signerAddress7) return 7;
if (signerAddress == signerAddress8) return 8;
if (signerAddress == signerAddress9) return 9;
revert SignerNotAuthorised(signerAddress); // U:[RPF-6]
}
/// @notice Validates that a timestamp in a data package is valid
/// @dev Sanity checks on the timestamp are performed earlier in the update,
/// when the lastPayloadTimestamp is being set
/// @param receivedTimestampMilliseconds Timestamp in the data package, in milliseconds
function validateTimestamp(uint256 receivedTimestampMilliseconds) public view override {
uint256 receivedTimestampSeconds = receivedTimestampMilliseconds / 1000;
if (receivedTimestampSeconds != lastPayloadTimestamp) {
revert DataPackageTimestampIncorrect(); // U:[RPF-3]
}
}
/// @dev Validates that the expected payload timestamp is not older than the last payload's,
/// and not too far from the current block's
/// @param expectedPayloadTimestamp Timestamp expected to be in all of the incoming payload's packages
function _validateExpectedPayloadTimestamp(uint256 expectedPayloadTimestamp) internal view {
if ((block.timestamp < expectedPayloadTimestamp)) {
if ((expectedPayloadTimestamp - block.timestamp) > MAX_DATA_TIMESTAMP_AHEAD_SECONDS) {
revert RedstonePayloadTimestampIncorrect(); // U:[RPF-9]
}
} else if ((block.timestamp - expectedPayloadTimestamp) > MAX_DATA_TIMESTAMP_DELAY_SECONDS) {
revert RedstonePayloadTimestampIncorrect(); // U:[RPF-9]
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* The default value of {decimals} is 18. To change this, you should override
* this function so it returns a different value.
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the default value returned by this function, unless
* it's overridden.
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address to, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_transfer(owner, to, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
* `transferFrom`. This is semantically equivalent to an infinite approval.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* NOTE: Does not update the allowance if the current allowance
* is the maximum `uint256`.
*
* Requirements:
*
* - `from` and `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
* - the caller must have allowance for ``from``'s tokens of at least
* `amount`.
*/
function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
address spender = _msgSender();
_spendAllowance(from, spender, amount);
_transfer(from, to, amount);
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
address owner = _msgSender();
_approve(owner, spender, allowance(owner, spender) + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
address owner = _msgSender();
uint256 currentAllowance = allowance(owner, spender);
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(owner, spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `from` to `to`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `from` must have a balance of at least `amount`.
*/
function _transfer(address from, address to, uint256 amount) internal virtual {
require(from != address(0), "ERC20: transfer from the zero address");
require(to != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
// Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
// decrementing then incrementing.
_balances[to] += amount;
}
emit Transfer(from, to, amount);
_afterTokenTransfer(from, to, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
unchecked {
// Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
_balances[account] += amount;
}
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
// Overflow not possible: amount <= accountBalance <= totalSupply.
_totalSupply -= amount;
}
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(address owner, address spender, uint256 amount) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Updates `owner` s allowance for `spender` based on spent `amount`.
*
* Does not update the allowance amount in case of infinite allowance.
* Revert if not enough allowance is available.
*
* Might emit an {Approval} event.
*/
function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
uint256 currentAllowance = allowance(owner, spender);
if (currentAllowance != type(uint256).max) {
require(currentAllowance >= amount, "ERC20: insufficient allowance");
unchecked {
_approve(owner, spender, currentAllowance - amount);
}
}
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such 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.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
import "./RedstoneConsumerBase.sol";
/**
* @title The base contract for Redstone consumers' contracts that allows to
* securely calculate numeric redstone oracle values
* @author The Redstone Oracles team
* @dev This contract can extend other contracts to allow them
* securely fetch Redstone oracle data from transactions calldata
*/
abstract contract RedstoneConsumerNumericBase is RedstoneConsumerBase {
/**
* @dev This function can be used in a consumer contract to securely extract an
* oracle value for a given data feed id. Security is achieved by
* signatures verification, timestamp validation, and aggregating values
* from different authorised signers into a single numeric value. If any of the
* required conditions do not match, the function will revert.
* Note! This function expects that tx calldata contains redstone payload in the end
* Learn more about redstone payload here: https://github.com/redstone-finance/redstone-oracles-monorepo/tree/main/packages/evm-connector#readme
* @param dataFeedId bytes32 value that uniquely identifies the data feed
* @return Extracted and verified numeric oracle value for the given data feed id
*/
function getOracleNumericValueFromTxMsg(bytes32 dataFeedId)
internal
view
virtual
returns (uint256)
{
bytes32[] memory dataFeedIds = new bytes32[](1);
dataFeedIds[0] = dataFeedId;
return getOracleNumericValuesFromTxMsg(dataFeedIds)[0];
}
/**
* @dev This function can be used in a consumer contract to securely extract several
* numeric oracle values for a given array of data feed ids. Security is achieved by
* signatures verification, timestamp validation, and aggregating values
* from different authorised signers into a single numeric value. If any of the
* required conditions do not match, the function will revert.
* Note! This function expects that tx calldata contains redstone payload in the end
* Learn more about redstone payload here: https://github.com/redstone-finance/redstone-oracles-monorepo/tree/main/packages/evm-connector#readme
* @param dataFeedIds An array of unique data feed identifiers
* @return An array of the extracted and verified oracle values in the same order
* as they are requested in the dataFeedIds array
*/
function getOracleNumericValuesFromTxMsg(bytes32[] memory dataFeedIds)
internal
view
virtual
returns (uint256[] memory)
{
return _securelyExtractOracleValuesFromTxMsg(dataFeedIds);
}
/**
* @dev This function works similarly to the `getOracleNumericValuesFromTxMsg` with the
* only difference that it allows to request oracle data for an array of data feeds
* that may contain duplicates
*
* @param dataFeedIdsWithDuplicates An array of data feed identifiers (duplicates are allowed)
* @return An array of the extracted and verified oracle values in the same order
* as they are requested in the dataFeedIdsWithDuplicates array
*/
function getOracleNumericValuesWithDuplicatesFromTxMsg(bytes32[] memory dataFeedIdsWithDuplicates) internal view returns (uint256[] memory) {
// Building an array without duplicates
bytes32[] memory dataFeedIdsWithoutDuplicates = new bytes32[](dataFeedIdsWithDuplicates.length);
bool alreadyIncluded;
uint256 uniqueDataFeedIdsCount = 0;
for (uint256 indexWithDup = 0; indexWithDup < dataFeedIdsWithDuplicates.length; indexWithDup++) {
// Checking if current element is already included in `dataFeedIdsWithoutDuplicates`
alreadyIncluded = false;
for (uint256 indexWithoutDup = 0; indexWithoutDup < uniqueDataFeedIdsCount; indexWithoutDup++) {
if (dataFeedIdsWithoutDuplicates[indexWithoutDup] == dataFeedIdsWithDuplicates[indexWithDup]) {
alreadyIncluded = true;
break;
}
}
// Adding if not included
if (!alreadyIncluded) {
dataFeedIdsWithoutDuplicates[uniqueDataFeedIdsCount] = dataFeedIdsWithDuplicates[indexWithDup];
uniqueDataFeedIdsCount++;
}
}
// Overriding dataFeedIdsWithoutDuplicates.length
// Equivalent to: dataFeedIdsWithoutDuplicates.length = uniqueDataFeedIdsCount;
assembly {
mstore(dataFeedIdsWithoutDuplicates, uniqueDataFeedIdsCount)
}
// Requesting oracle values (without duplicates)
uint256[] memory valuesWithoutDuplicates = getOracleNumericValuesFromTxMsg(dataFeedIdsWithoutDuplicates);
// Preparing result values array
uint256[] memory valuesWithDuplicates = new uint256[](dataFeedIdsWithDuplicates.length);
for (uint256 indexWithDup = 0; indexWithDup < dataFeedIdsWithDuplicates.length; indexWithDup++) {
for (uint256 indexWithoutDup = 0; indexWithoutDup < dataFeedIdsWithoutDuplicates.length; indexWithoutDup++) {
if (dataFeedIdsWithDuplicates[indexWithDup] == dataFeedIdsWithoutDuplicates[indexWithoutDup]) {
valuesWithDuplicates[indexWithDup] = valuesWithoutDuplicates[indexWithoutDup];
break;
}
}
}
return valuesWithDuplicates;
}
}// SPDX-License-Identifier: UNLICENSED
// Gearbox. Generalized leverage protocol that allows to take leverage and then use it across other DeFi protocols and platforms in a composable way.
// (c) Gearbox Foundation, 2023
pragma solidity ^0.8.17;
enum PriceFeedType {
CHAINLINK_ORACLE,
YEARN_ORACLE,
CURVE_2LP_ORACLE,
CURVE_3LP_ORACLE,
CURVE_4LP_ORACLE,
ZERO_ORACLE,
WSTETH_ORACLE,
BOUNDED_ORACLE,
COMPOSITE_ORACLE,
WRAPPED_AAVE_V2_ORACLE,
COMPOUND_V2_ORACLE,
BALANCER_STABLE_LP_ORACLE,
BALANCER_WEIGHTED_LP_ORACLE,
CURVE_CRYPTO_ORACLE,
THE_SAME_AS,
REDSTONE_ORACLE,
ERC4626_VAULT_ORACLE,
NETWORK_DEPENDENT,
CURVE_USD_ORACLE,
PYTH_ORACLE
}// SPDX-License-Identifier: MIT
// Gearbox Protocol. Generalized leverage for DeFi protocols
// (c) Gearbox Foundation, 2023.
pragma solidity ^0.8.0;
import { PriceFeedType } from "@gearbox-protocol/sdk-gov/contracts/PriceFeedType.sol";
/// @title Price feed interface
interface IPriceFeed {
function priceFeedType() external view returns (PriceFeedType);
function version() external view returns (uint256);
function decimals() external view returns (uint8);
function description() external view returns (string memory);
function skipPriceCheck() external view returns (bool);
function latestRoundData()
external
view
returns (uint80, int256 answer, uint256, uint256 updatedAt, uint80);
}
/// @title Updatable price feed interface
interface IUpdatablePriceFeed is IPriceFeed {
function updatable() external view returns (bool);
function updatePrice(bytes calldata data) external;
}// SPDX-License-Identifier: MIT // Gearbox Protocol. Generalized leverage for DeFi protocols // (c) Gearbox Foundation, 2023. pragma solidity ^0.8.17; // ------- // // GENERAL // // ------- // /// @notice Thrown on attempting to set an important address to zero address error ZeroAddressException(); /// @notice Thrown when attempting to pass a zero amount to a funding-related operation error AmountCantBeZeroException(); /// @notice Thrown on incorrect input parameter error IncorrectParameterException(); /// @notice Thrown when balance is insufficient to perform an operation error InsufficientBalanceException(); /// @notice Thrown if parameter is out of range error ValueOutOfRangeException(); /// @notice Thrown when trying to send ETH to a contract that is not allowed to receive ETH directly error ReceiveIsNotAllowedException(); /// @notice Thrown on attempting to set an EOA as an important contract in the system error AddressIsNotContractException(address); /// @notice Thrown on attempting to receive a token that is not a collateral token or was forbidden error TokenNotAllowedException(); /// @notice Thrown on attempting to add a token that is already in a collateral list error TokenAlreadyAddedException(); /// @notice Thrown when attempting to use quota-related logic for a token that is not quoted in quota keeper error TokenIsNotQuotedException(); /// @notice Thrown on attempting to interact with an address that is not a valid target contract error TargetContractNotAllowedException(); /// @notice Thrown if function is not implemented error NotImplementedException(); // ------------------ // // CONTRACTS REGISTER // // ------------------ // /// @notice Thrown when an address is expected to be a registered credit manager, but is not error RegisteredCreditManagerOnlyException(); /// @notice Thrown when an address is expected to be a registered pool, but is not error RegisteredPoolOnlyException(); // ---------------- // // ADDRESS PROVIDER // // ---------------- // /// @notice Reverts if address key isn't found in address provider error AddressNotFoundException(); // ----------------- // // POOL, PQK, GAUGES // // ----------------- // /// @notice Thrown by pool-adjacent contracts when a credit manager being connected has a wrong pool address error IncompatibleCreditManagerException(); /// @notice Thrown when attempting to set an incompatible successor staking contract error IncompatibleSuccessorException(); /// @notice Thrown when attempting to vote in a non-approved contract error VotingContractNotAllowedException(); /// @notice Thrown when attempting to unvote more votes than there are error InsufficientVotesException(); /// @notice Thrown when attempting to borrow more than the second point on a two-point curve error BorrowingMoreThanU2ForbiddenException(); /// @notice Thrown when a credit manager attempts to borrow more than its limit in the current block, or in general error CreditManagerCantBorrowException(); /// @notice Thrown when attempting to connect a quota keeper to an incompatible pool error IncompatiblePoolQuotaKeeperException(); /// @notice Thrown when the quota is outside of min/max bounds error QuotaIsOutOfBoundsException(); // -------------- // // CREDIT MANAGER // // -------------- // /// @notice Thrown on failing a full collateral check after multicall error NotEnoughCollateralException(); /// @notice Thrown if an attempt to approve a collateral token to adapter's target contract fails error AllowanceFailedException(); /// @notice Thrown on attempting to perform an action for a credit account that does not exist error CreditAccountDoesNotExistException(); /// @notice Thrown on configurator attempting to add more than 255 collateral tokens error TooManyTokensException(); /// @notice Thrown if more than the maximum number of tokens were enabled on a credit account error TooManyEnabledTokensException(); /// @notice Thrown when attempting to execute a protocol interaction without active credit account set error ActiveCreditAccountNotSetException(); /// @notice Thrown when trying to update credit account's debt more than once in the same block error DebtUpdatedTwiceInOneBlockException(); /// @notice Thrown when trying to repay all debt while having active quotas error DebtToZeroWithActiveQuotasException(); /// @notice Thrown when a zero-debt account attempts to update quota error UpdateQuotaOnZeroDebtAccountException(); /// @notice Thrown when attempting to close an account with non-zero debt error CloseAccountWithNonZeroDebtException(); /// @notice Thrown when value of funds remaining on the account after liquidation is insufficient error InsufficientRemainingFundsException(); /// @notice Thrown when Credit Facade tries to write over a non-zero active Credit Account error ActiveCreditAccountOverridenException(); // ------------------- // // CREDIT CONFIGURATOR // // ------------------- // /// @notice Thrown on attempting to use a non-ERC20 contract or an EOA as a token error IncorrectTokenContractException(); /// @notice Thrown if the newly set LT if zero or greater than the underlying's LT error IncorrectLiquidationThresholdException(); /// @notice Thrown if borrowing limits are incorrect: minLimit > maxLimit or maxLimit > blockLimit error IncorrectLimitsException(); /// @notice Thrown if the new expiration date is less than the current expiration date or current timestamp error IncorrectExpirationDateException(); /// @notice Thrown if a contract returns a wrong credit manager or reverts when trying to retrieve it error IncompatibleContractException(); /// @notice Thrown if attempting to forbid an adapter that is not registered in the credit manager error AdapterIsNotRegisteredException(); // ------------- // // CREDIT FACADE // // ------------- // /// @notice Thrown when attempting to perform an action that is forbidden in whitelisted mode error ForbiddenInWhitelistedModeException(); /// @notice Thrown if credit facade is not expirable, and attempted aciton requires expirability error NotAllowedWhenNotExpirableException(); /// @notice Thrown if a selector that doesn't match any allowed function is passed to the credit facade in a multicall error UnknownMethodException(); /// @notice Thrown when trying to close an account with enabled tokens error CloseAccountWithEnabledTokensException(); /// @notice Thrown if a liquidator tries to liquidate an account with a health factor above 1 error CreditAccountNotLiquidatableException(); /// @notice Thrown if too much new debt was taken within a single block error BorrowedBlockLimitException(); /// @notice Thrown if the new debt principal for a credit account falls outside of borrowing limits error BorrowAmountOutOfLimitsException(); /// @notice Thrown if a user attempts to open an account via an expired credit facade error NotAllowedAfterExpirationException(); /// @notice Thrown if expected balances are attempted to be set twice without performing a slippage check error ExpectedBalancesAlreadySetException(); /// @notice Thrown if attempting to perform a slippage check when excepted balances are not set error ExpectedBalancesNotSetException(); /// @notice Thrown if balance of at least one token is less than expected during a slippage check error BalanceLessThanExpectedException(); /// @notice Thrown when trying to perform an action that is forbidden when credit account has enabled forbidden tokens error ForbiddenTokensException(); /// @notice Thrown when new forbidden tokens are enabled during the multicall error ForbiddenTokenEnabledException(); /// @notice Thrown when enabled forbidden token balance is increased during the multicall error ForbiddenTokenBalanceIncreasedException(); /// @notice Thrown when the remaining token balance is increased during the liquidation error RemainingTokenBalanceIncreasedException(); /// @notice Thrown if `botMulticall` is called by an address that is not approved by account owner or is forbidden error NotApprovedBotException(); /// @notice Thrown when attempting to perform a multicall action with no permission for it error NoPermissionException(uint256 permission); /// @notice Thrown when attempting to give a bot unexpected permissions error UnexpectedPermissionsException(); /// @notice Thrown when a custom HF parameter lower than 10000 is passed into the full collateral check error CustomHealthFactorTooLowException(); /// @notice Thrown when submitted collateral hint is not a valid token mask error InvalidCollateralHintException(); // ------ // // ACCESS // // ------ // /// @notice Thrown on attempting to call an access restricted function not as credit account owner error CallerNotCreditAccountOwnerException(); /// @notice Thrown on attempting to call an access restricted function not as configurator error CallerNotConfiguratorException(); /// @notice Thrown on attempting to call an access-restructed function not as account factory error CallerNotAccountFactoryException(); /// @notice Thrown on attempting to call an access restricted function not as credit manager error CallerNotCreditManagerException(); /// @notice Thrown on attempting to call an access restricted function not as credit facade error CallerNotCreditFacadeException(); /// @notice Thrown on attempting to call an access restricted function not as controller or configurator error CallerNotControllerException(); /// @notice Thrown on attempting to pause a contract without pausable admin rights error CallerNotPausableAdminException(); /// @notice Thrown on attempting to unpause a contract without unpausable admin rights error CallerNotUnpausableAdminException(); /// @notice Thrown on attempting to call an access restricted function not as gauge error CallerNotGaugeException(); /// @notice Thrown on attempting to call an access restricted function not as quota keeper error CallerNotPoolQuotaKeeperException(); /// @notice Thrown on attempting to call an access restricted function not as voter error CallerNotVoterException(); /// @notice Thrown on attempting to call an access restricted function not as allowed adapter error CallerNotAdapterException(); /// @notice Thrown on attempting to call an access restricted function not as migrator error CallerNotMigratorException(); /// @notice Thrown when an address that is not the designated executor attempts to execute a transaction error CallerNotExecutorException(); /// @notice Thrown on attempting to call an access restricted function not as veto admin error CallerNotVetoAdminException(); // ------------------- // // CONTROLLER TIMELOCK // // ------------------- // /// @notice Thrown when the new parameter values do not satisfy required conditions error ParameterChecksFailedException(); /// @notice Thrown when attempting to execute a non-queued transaction error TxNotQueuedException(); /// @notice Thrown when attempting to execute a transaction that is either immature or stale error TxExecutedOutsideTimeWindowException(); /// @notice Thrown when execution of a transaction fails error TxExecutionRevertedException(); /// @notice Thrown when the value of a parameter on execution is different from the value on queue error ParameterChangedAfterQueuedTxException(); // -------- // // BOT LIST // // -------- // /// @notice Thrown when attempting to set non-zero permissions for a forbidden or special bot error InvalidBotException(); // --------------- // // ACCOUNT FACTORY // // --------------- // /// @notice Thrown when trying to deploy second master credit account for a credit manager error MasterCreditAccountAlreadyDeployedException(); /// @notice Thrown when trying to rescue funds from a credit account that is currently in use error CreditAccountIsInUseException(); // ------------ // // PRICE ORACLE // // ------------ // /// @notice Thrown on attempting to set a token price feed to an address that is not a correct price feed error IncorrectPriceFeedException(); /// @notice Thrown on attempting to interact with a price feed for a token not added to the price oracle error PriceFeedDoesNotExistException(); /// @notice Thrown when price feed returns incorrect price for a token error IncorrectPriceException(); /// @notice Thrown when token's price feed becomes stale error StalePriceException();
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @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);
/**
* @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 `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, 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.
*
* IMPORTANT: 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.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 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.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./RedstoneConstants.sol";
import "./RedstoneDefaultsLib.sol";
import "./CalldataExtractor.sol";
import "../libs/BitmapLib.sol";
import "../libs/SignatureLib.sol";
/**
* @title The base contract with the main Redstone logic
* @author The Redstone Oracles team
* @dev Do not use this contract directly in consumer contracts, take a
* look at `RedstoneConsumerNumericBase` and `RedstoneConsumerBytesBase` instead
*/
abstract contract RedstoneConsumerBase is CalldataExtractor {
using SafeMath for uint256;
error GetDataServiceIdNotImplemented();
/* ========== VIRTUAL FUNCTIONS (MAY BE OVERRIDDEN IN CHILD CONTRACTS) ========== */
/**
* @dev This function must be implemented by the child consumer contract.
* It should return dataServiceId which DataServiceWrapper will use if not provided explicitly .
* If not overridden, value will always have to be provided explicitly in DataServiceWrapper.
* @return dataServiceId being consumed by contract
*/
function getDataServiceId() public view virtual returns (string memory) {
revert GetDataServiceIdNotImplemented();
}
/**
* @dev This function must be implemented by the child consumer contract.
* It should return a unique index for a given signer address if the signer
* is authorised, otherwise it should revert
* @param receivedSigner The address of a signer, recovered from ECDSA signature
* @return Unique index for a signer in the range [0..255]
*/
function getAuthorisedSignerIndex(address receivedSigner) public view virtual returns (uint8);
/**
* @dev This function may be overridden by the child consumer contract.
* It should validate the timestamp against the current time (block.timestamp)
* It should revert with a helpful message if the timestamp is not valid
* @param receivedTimestampMilliseconds Timestamp extracted from calldata
*/
function validateTimestamp(uint256 receivedTimestampMilliseconds) public view virtual {
RedstoneDefaultsLib.validateTimestamp(receivedTimestampMilliseconds);
}
/**
* @dev This function should be overridden by the child consumer contract.
* @return The minimum required value of unique authorised signers
*/
function getUniqueSignersThreshold() public view virtual returns (uint8) {
return 1;
}
/**
* @dev This function may be overridden by the child consumer contract.
* It should aggregate values from different signers to a single uint value.
* By default, it calculates the median value
* @param values An array of uint256 values from different signers
* @return Result of the aggregation in the form of a single number
*/
function aggregateValues(uint256[] memory values) public view virtual returns (uint256) {
return RedstoneDefaultsLib.aggregateValues(values);
}
/* ========== FUNCTIONS WITH IMPLEMENTATION (CAN NOT BE OVERRIDDEN) ========== */
/**
* @dev This is an internal helpful function for secure extraction oracle values
* from the tx calldata. Security is achieved by signatures verification, timestamp
* validation, and aggregating values from different authorised signers into a
* single numeric value. If any of the required conditions (e.g. too old timestamp or
* insufficient number of authorised signers) do not match, the function will revert.
*
* Note! You should not call this function in a consumer contract. You can use
* `getOracleNumericValuesFromTxMsg` or `getOracleNumericValueFromTxMsg` instead.
*
* @param dataFeedIds An array of unique data feed identifiers
* @return An array of the extracted and verified oracle values in the same order
* as they are requested in dataFeedIds array
*/
function _securelyExtractOracleValuesFromTxMsg(bytes32[] memory dataFeedIds)
internal
view
returns (uint256[] memory)
{
// Initializing helpful variables and allocating memory
uint256[] memory uniqueSignerCountForDataFeedIds = new uint256[](dataFeedIds.length);
uint256[] memory signersBitmapForDataFeedIds = new uint256[](dataFeedIds.length);
uint256[][] memory valuesForDataFeeds = new uint256[][](dataFeedIds.length);
for (uint256 i = 0; i < dataFeedIds.length; i++) {
// The line below is commented because newly allocated arrays are filled with zeros
// But we left it for better readability
// signersBitmapForDataFeedIds[i] = 0; // <- setting to an empty bitmap
valuesForDataFeeds[i] = new uint256[](getUniqueSignersThreshold());
}
// Extracting the number of data packages from calldata
uint256 calldataNegativeOffset = _extractByteSizeOfUnsignedMetadata();
uint256 dataPackagesCount = _extractDataPackagesCountFromCalldata(calldataNegativeOffset);
calldataNegativeOffset += DATA_PACKAGES_COUNT_BS;
// Saving current free memory pointer
uint256 freeMemPtr;
assembly {
freeMemPtr := mload(FREE_MEMORY_PTR)
}
// Data packages extraction in a loop
for (uint256 dataPackageIndex = 0; dataPackageIndex < dataPackagesCount; dataPackageIndex++) {
// Extract data package details and update calldata offset
uint256 dataPackageByteSize = _extractDataPackage(
dataFeedIds,
uniqueSignerCountForDataFeedIds,
signersBitmapForDataFeedIds,
valuesForDataFeeds,
calldataNegativeOffset
);
calldataNegativeOffset += dataPackageByteSize;
// Shifting memory pointer back to the "safe" value
assembly {
mstore(FREE_MEMORY_PTR, freeMemPtr)
}
}
// Validating numbers of unique signers and calculating aggregated values for each dataFeedId
return _getAggregatedValues(valuesForDataFeeds, uniqueSignerCountForDataFeedIds);
}
/**
* @dev This is a private helpful function, which extracts data for a data package based
* on the given negative calldata offset, verifies them, and in the case of successful
* verification updates the corresponding data package values in memory
*
* @param dataFeedIds an array of unique data feed identifiers
* @param uniqueSignerCountForDataFeedIds an array with the numbers of unique signers
* for each data feed
* @param signersBitmapForDataFeedIds an array of signer bitmaps for data feeds
* @param valuesForDataFeeds 2-dimensional array, valuesForDataFeeds[i][j] contains
* j-th value for the i-th data feed
* @param calldataNegativeOffset negative calldata offset for the given data package
*
* @return An array of the aggregated values
*/
function _extractDataPackage(
bytes32[] memory dataFeedIds,
uint256[] memory uniqueSignerCountForDataFeedIds,
uint256[] memory signersBitmapForDataFeedIds,
uint256[][] memory valuesForDataFeeds,
uint256 calldataNegativeOffset
) private view returns (uint256) {
uint256 signerIndex;
(
uint256 dataPointsCount,
uint256 eachDataPointValueByteSize
) = _extractDataPointsDetailsForDataPackage(calldataNegativeOffset);
// We use scopes to resolve problem with too deep stack
{
uint48 extractedTimestamp;
address signerAddress;
bytes32 signedHash;
bytes memory signedMessage;
uint256 signedMessageBytesCount;
signedMessageBytesCount = dataPointsCount.mul(eachDataPointValueByteSize + DATA_POINT_SYMBOL_BS)
+ DATA_PACKAGE_WITHOUT_DATA_POINTS_AND_SIG_BS; //DATA_POINT_VALUE_BYTE_SIZE_BS + TIMESTAMP_BS + DATA_POINTS_COUNT_BS
uint256 timestampCalldataOffset = msg.data.length.sub(
calldataNegativeOffset + TIMESTAMP_NEGATIVE_OFFSET_IN_DATA_PACKAGE_WITH_STANDARD_SLOT_BS);
uint256 signedMessageCalldataOffset = msg.data.length.sub(
calldataNegativeOffset + SIG_BS + signedMessageBytesCount);
assembly {
// Extracting the signed message
signedMessage := extractBytesFromCalldata(
signedMessageCalldataOffset,
signedMessageBytesCount
)
// Hashing the signed message
signedHash := keccak256(add(signedMessage, BYTES_ARR_LEN_VAR_BS), signedMessageBytesCount)
// Extracting timestamp
extractedTimestamp := calldataload(timestampCalldataOffset)
function initByteArray(bytesCount) -> ptr {
ptr := mload(FREE_MEMORY_PTR)
mstore(ptr, bytesCount)
ptr := add(ptr, BYTES_ARR_LEN_VAR_BS)
mstore(FREE_MEMORY_PTR, add(ptr, bytesCount))
}
function extractBytesFromCalldata(offset, bytesCount) -> extractedBytes {
let extractedBytesStartPtr := initByteArray(bytesCount)
calldatacopy(
extractedBytesStartPtr,
offset,
bytesCount
)
extractedBytes := sub(extractedBytesStartPtr, BYTES_ARR_LEN_VAR_BS)
}
}
// Validating timestamp
validateTimestamp(extractedTimestamp);
// Verifying the off-chain signature against on-chain hashed data
signerAddress = SignatureLib.recoverSignerAddress(
signedHash,
calldataNegativeOffset + SIG_BS
);
signerIndex = getAuthorisedSignerIndex(signerAddress);
}
// Updating helpful arrays
{
bytes32 dataPointDataFeedId;
uint256 dataPointValue;
for (uint256 dataPointIndex = 0; dataPointIndex < dataPointsCount; dataPointIndex++) {
// Extracting data feed id and value for the current data point
(dataPointDataFeedId, dataPointValue) = _extractDataPointValueAndDataFeedId(
calldataNegativeOffset,
eachDataPointValueByteSize,
dataPointIndex
);
for (
uint256 dataFeedIdIndex = 0;
dataFeedIdIndex < dataFeedIds.length;
dataFeedIdIndex++
) {
if (dataPointDataFeedId == dataFeedIds[dataFeedIdIndex]) {
uint256 bitmapSignersForDataFeedId = signersBitmapForDataFeedIds[dataFeedIdIndex];
if (
!BitmapLib.getBitFromBitmap(bitmapSignersForDataFeedId, signerIndex) && /* current signer was not counted for current dataFeedId */
uniqueSignerCountForDataFeedIds[dataFeedIdIndex] < getUniqueSignersThreshold()
) {
// Increase unique signer counter
uniqueSignerCountForDataFeedIds[dataFeedIdIndex]++;
// Add new value
valuesForDataFeeds[dataFeedIdIndex][
uniqueSignerCountForDataFeedIds[dataFeedIdIndex] - 1
] = dataPointValue;
// Update signers bitmap
signersBitmapForDataFeedIds[dataFeedIdIndex] = BitmapLib.setBitInBitmap(
bitmapSignersForDataFeedId,
signerIndex
);
}
// Breaking, as there couldn't be several indexes for the same feed ID
break;
}
}
}
}
// Return total data package byte size
return
DATA_PACKAGE_WITHOUT_DATA_POINTS_BS +
(eachDataPointValueByteSize + DATA_POINT_SYMBOL_BS) *
dataPointsCount;
}
/**
* @dev This is a private helpful function, which aggregates values from different
* authorised signers for the given arrays of values for each data feed
*
* @param valuesForDataFeeds 2-dimensional array, valuesForDataFeeds[i][j] contains
* j-th value for the i-th data feed
* @param uniqueSignerCountForDataFeedIds an array with the numbers of unique signers
* for each data feed
*
* @return An array of the aggregated values
*/
function _getAggregatedValues(
uint256[][] memory valuesForDataFeeds,
uint256[] memory uniqueSignerCountForDataFeedIds
) private view returns (uint256[] memory) {
uint256[] memory aggregatedValues = new uint256[](valuesForDataFeeds.length);
uint256 uniqueSignersThreshold = getUniqueSignersThreshold();
for (uint256 dataFeedIndex = 0; dataFeedIndex < valuesForDataFeeds.length; dataFeedIndex++) {
if (uniqueSignerCountForDataFeedIds[dataFeedIndex] < uniqueSignersThreshold) {
revert InsufficientNumberOfUniqueSigners(
uniqueSignerCountForDataFeedIds[dataFeedIndex],
uniqueSignersThreshold);
}
uint256 aggregatedValueForDataFeedId = aggregateValues(valuesForDataFeeds[dataFeedIndex]);
aggregatedValues[dataFeedIndex] = aggregatedValueForDataFeedId;
}
return aggregatedValues;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/SafeMath.sol)
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is generally not needed starting with Solidity 0.8, since the compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// 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 (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @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) {
return a + b;
}
/**
* @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) {
return a - b;
}
/**
* @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) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting 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) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message 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, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* 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, string memory errorMessage) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
/**
* @title The base contract with helpful constants
* @author The Redstone Oracles team
* @dev It mainly contains redstone-related values, which improve readability
* of other contracts (e.g. CalldataExtractor and RedstoneConsumerBase)
*/
contract RedstoneConstants {
// === Abbreviations ===
// BS - Bytes size
// PTR - Pointer (memory location)
// SIG - Signature
// Solidity and YUL constants
uint256 internal constant STANDARD_SLOT_BS = 32;
uint256 internal constant FREE_MEMORY_PTR = 0x40;
uint256 internal constant BYTES_ARR_LEN_VAR_BS = 32;
uint256 internal constant FUNCTION_SIGNATURE_BS = 4;
uint256 internal constant REVERT_MSG_OFFSET = 68; // Revert message structure described here: https://ethereum.stackexchange.com/a/66173/106364
uint256 internal constant STRING_ERR_MESSAGE_MASK = 0x08c379a000000000000000000000000000000000000000000000000000000000;
// RedStone protocol consts
uint256 internal constant SIG_BS = 65;
uint256 internal constant TIMESTAMP_BS = 6;
uint256 internal constant DATA_PACKAGES_COUNT_BS = 2;
uint256 internal constant DATA_POINTS_COUNT_BS = 3;
uint256 internal constant DATA_POINT_VALUE_BYTE_SIZE_BS = 4;
uint256 internal constant DATA_POINT_SYMBOL_BS = 32;
uint256 internal constant DEFAULT_DATA_POINT_VALUE_BS = 32;
uint256 internal constant UNSIGNED_METADATA_BYTE_SIZE_BS = 3;
uint256 internal constant REDSTONE_MARKER_BS = 9; // byte size of 0x000002ed57011e0000
uint256 internal constant REDSTONE_MARKER_MASK = 0x0000000000000000000000000000000000000000000000000002ed57011e0000;
// Derived values (based on consts)
uint256 internal constant TIMESTAMP_NEGATIVE_OFFSET_IN_DATA_PACKAGE_WITH_STANDARD_SLOT_BS = 104; // SIG_BS + DATA_POINTS_COUNT_BS + DATA_POINT_VALUE_BYTE_SIZE_BS + STANDARD_SLOT_BS
uint256 internal constant DATA_PACKAGE_WITHOUT_DATA_POINTS_BS = 78; // DATA_POINT_VALUE_BYTE_SIZE_BS + TIMESTAMP_BS + DATA_POINTS_COUNT_BS + SIG_BS
uint256 internal constant DATA_PACKAGE_WITHOUT_DATA_POINTS_AND_SIG_BS = 13; // DATA_POINT_VALUE_BYTE_SIZE_BS + TIMESTAMP_BS + DATA_POINTS_COUNT_BS
uint256 internal constant REDSTONE_MARKER_BS_PLUS_STANDARD_SLOT_BS = 41; // REDSTONE_MARKER_BS + STANDARD_SLOT_BS
// Error messages
error CalldataOverOrUnderFlow();
error IncorrectUnsignedMetadataSize();
error InsufficientNumberOfUniqueSigners(uint256 receivedSignersCount, uint256 requiredSignersCount);
error EachSignerMustProvideTheSameValue();
error EmptyCalldataPointersArr();
error InvalidCalldataPointer();
error CalldataMustHaveValidPayload();
error SignerNotAuthorised(address receivedSigner);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
import "../libs/NumericArrayLib.sol";
/**
* @title Default implementations of virtual redstone consumer base functions
* @author The Redstone Oracles team
*/
library RedstoneDefaultsLib {
uint256 constant DEFAULT_MAX_DATA_TIMESTAMP_DELAY_SECONDS = 3 minutes;
uint256 constant DEFAULT_MAX_DATA_TIMESTAMP_AHEAD_SECONDS = 1 minutes;
error TimestampFromTooLongFuture(uint256 receivedTimestampSeconds, uint256 blockTimestamp);
error TimestampIsTooOld(uint256 receivedTimestampSeconds, uint256 blockTimestamp);
function validateTimestamp(uint256 receivedTimestampMilliseconds) internal view {
// Getting data timestamp from future seems quite unlikely
// But we've already spent too much time with different cases
// Where block.timestamp was less than dataPackage.timestamp.
// Some blockchains may case this problem as well.
// That's why we add MAX_BLOCK_TIMESTAMP_DELAY
// and allow data "from future" but with a small delay
uint256 receivedTimestampSeconds = receivedTimestampMilliseconds / 1000;
if (block.timestamp < receivedTimestampSeconds) {
if ((receivedTimestampSeconds - block.timestamp) > DEFAULT_MAX_DATA_TIMESTAMP_AHEAD_SECONDS) {
revert TimestampFromTooLongFuture(receivedTimestampSeconds, block.timestamp);
}
} else if ((block.timestamp - receivedTimestampSeconds) > DEFAULT_MAX_DATA_TIMESTAMP_DELAY_SECONDS) {
revert TimestampIsTooOld(receivedTimestampSeconds, block.timestamp);
}
}
function aggregateValues(uint256[] memory values) internal pure returns (uint256) {
return NumericArrayLib.pickMedian(values);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "./RedstoneConstants.sol";
/**
* @title The base contract with the main logic of data extraction from calldata
* @author The Redstone Oracles team
* @dev This contract was created to reuse the same logic in the RedstoneConsumerBase
* and the ProxyConnector contracts
*/
contract CalldataExtractor is RedstoneConstants {
using SafeMath for uint256;
error DataPackageTimestampMustNotBeZero();
error DataPackageTimestampsMustBeEqual();
error RedstonePayloadMustHaveAtLeastOneDataPackage();
function extractTimestampsAndAssertAllAreEqual() public pure returns (uint256 extractedTimestamp) {
uint256 calldataNegativeOffset = _extractByteSizeOfUnsignedMetadata();
uint256 dataPackagesCount = _extractDataPackagesCountFromCalldata(calldataNegativeOffset);
if (dataPackagesCount == 0) {
revert RedstonePayloadMustHaveAtLeastOneDataPackage();
}
calldataNegativeOffset += DATA_PACKAGES_COUNT_BS;
for (uint256 dataPackageIndex = 0; dataPackageIndex < dataPackagesCount; dataPackageIndex++) {
uint256 dataPackageByteSize = _getDataPackageByteSize(calldataNegativeOffset);
// Extracting timestamp for the current data package
uint48 dataPackageTimestamp; // uint48, because timestamp uses 6 bytes
uint256 timestampNegativeOffset = (calldataNegativeOffset + TIMESTAMP_NEGATIVE_OFFSET_IN_DATA_PACKAGE_WITH_STANDARD_SLOT_BS);
uint256 timestampOffset = msg.data.length - timestampNegativeOffset;
assembly {
dataPackageTimestamp := calldataload(timestampOffset)
}
if (dataPackageTimestamp == 0) {
revert DataPackageTimestampMustNotBeZero();
}
if (extractedTimestamp == 0) {
extractedTimestamp = dataPackageTimestamp;
} else if (dataPackageTimestamp != extractedTimestamp) {
revert DataPackageTimestampsMustBeEqual();
}
calldataNegativeOffset += dataPackageByteSize;
}
}
function _getDataPackageByteSize(uint256 calldataNegativeOffset) internal pure returns (uint256) {
(
uint256 dataPointsCount,
uint256 eachDataPointValueByteSize
) = _extractDataPointsDetailsForDataPackage(calldataNegativeOffset);
return
dataPointsCount *
(DATA_POINT_SYMBOL_BS + eachDataPointValueByteSize) +
DATA_PACKAGE_WITHOUT_DATA_POINTS_BS;
}
function _extractByteSizeOfUnsignedMetadata() internal pure returns (uint256) {
// Checking if the calldata ends with the RedStone marker
bool hasValidRedstoneMarker;
assembly {
let calldataLast32Bytes := calldataload(sub(calldatasize(), STANDARD_SLOT_BS))
hasValidRedstoneMarker := eq(
REDSTONE_MARKER_MASK,
and(calldataLast32Bytes, REDSTONE_MARKER_MASK)
)
}
if (!hasValidRedstoneMarker) {
revert CalldataMustHaveValidPayload();
}
// Using uint24, because unsigned metadata byte size number has 3 bytes
uint24 unsignedMetadataByteSize;
if (REDSTONE_MARKER_BS_PLUS_STANDARD_SLOT_BS > msg.data.length) {
revert CalldataOverOrUnderFlow();
}
assembly {
unsignedMetadataByteSize := calldataload(
sub(calldatasize(), REDSTONE_MARKER_BS_PLUS_STANDARD_SLOT_BS)
)
}
uint256 calldataNegativeOffset = unsignedMetadataByteSize
+ UNSIGNED_METADATA_BYTE_SIZE_BS
+ REDSTONE_MARKER_BS;
if (calldataNegativeOffset + DATA_PACKAGES_COUNT_BS > msg.data.length) {
revert IncorrectUnsignedMetadataSize();
}
return calldataNegativeOffset;
}
// We return uint16, because unsigned metadata byte size number has 2 bytes
function _extractDataPackagesCountFromCalldata(uint256 calldataNegativeOffset)
internal
pure
returns (uint16 dataPackagesCount)
{
uint256 calldataNegativeOffsetWithStandardSlot = calldataNegativeOffset + STANDARD_SLOT_BS;
if (calldataNegativeOffsetWithStandardSlot > msg.data.length) {
revert CalldataOverOrUnderFlow();
}
assembly {
dataPackagesCount := calldataload(
sub(calldatasize(), calldataNegativeOffsetWithStandardSlot)
)
}
return dataPackagesCount;
}
function _extractDataPointValueAndDataFeedId(
uint256 calldataNegativeOffsetForDataPackage,
uint256 defaultDataPointValueByteSize,
uint256 dataPointIndex
) internal pure virtual returns (bytes32 dataPointDataFeedId, uint256 dataPointValue) {
uint256 negativeOffsetToDataPoints = calldataNegativeOffsetForDataPackage + DATA_PACKAGE_WITHOUT_DATA_POINTS_BS;
uint256 dataPointNegativeOffset = negativeOffsetToDataPoints.add(
(1 + dataPointIndex).mul((defaultDataPointValueByteSize + DATA_POINT_SYMBOL_BS))
);
uint256 dataPointCalldataOffset = msg.data.length.sub(dataPointNegativeOffset);
assembly {
dataPointDataFeedId := calldataload(dataPointCalldataOffset)
dataPointValue := calldataload(add(dataPointCalldataOffset, DATA_POINT_SYMBOL_BS))
}
}
function _extractDataPointsDetailsForDataPackage(uint256 calldataNegativeOffsetForDataPackage)
internal
pure
returns (uint256 dataPointsCount, uint256 eachDataPointValueByteSize)
{
// Using uint24, because data points count byte size number has 3 bytes
uint24 dataPointsCount_;
// Using uint32, because data point value byte size has 4 bytes
uint32 eachDataPointValueByteSize_;
// Extract data points count
uint256 negativeCalldataOffset = calldataNegativeOffsetForDataPackage + SIG_BS;
uint256 calldataOffset = msg.data.length.sub(negativeCalldataOffset + STANDARD_SLOT_BS);
assembly {
dataPointsCount_ := calldataload(calldataOffset)
}
// Extract each data point value size
calldataOffset = calldataOffset.sub(DATA_POINTS_COUNT_BS);
assembly {
eachDataPointValueByteSize_ := calldataload(calldataOffset)
}
// Prepare returned values
dataPointsCount = dataPointsCount_;
eachDataPointValueByteSize = eachDataPointValueByteSize_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
library BitmapLib {
function setBitInBitmap(uint256 bitmap, uint256 bitIndex) internal pure returns (uint256) {
return bitmap | (1 << bitIndex);
}
function getBitFromBitmap(uint256 bitmap, uint256 bitIndex) internal pure returns (bool) {
uint256 bitAtIndex = bitmap & (1 << bitIndex);
return bitAtIndex > 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
library SignatureLib {
uint256 constant ECDSA_SIG_R_BS = 32;
uint256 constant ECDSA_SIG_S_BS = 32;
function recoverSignerAddress(bytes32 signedHash, uint256 signatureCalldataNegativeOffset)
internal
pure
returns (address)
{
bytes32 r;
bytes32 s;
uint8 v;
assembly {
let signatureCalldataStartPos := sub(calldatasize(), signatureCalldataNegativeOffset)
r := calldataload(signatureCalldataStartPos)
signatureCalldataStartPos := add(signatureCalldataStartPos, ECDSA_SIG_R_BS)
s := calldataload(signatureCalldataStartPos)
signatureCalldataStartPos := add(signatureCalldataStartPos, ECDSA_SIG_S_BS)
v := byte(0, calldataload(signatureCalldataStartPos)) // last byte of the signature memory array
}
return ecrecover(signedHash, v, r, s);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
library NumericArrayLib {
// This function sort array in memory using bubble sort algorithm,
// which performs even better than quick sort for small arrays
uint256 constant BYTES_ARR_LEN_VAR_BS = 32;
uint256 constant UINT256_VALUE_BS = 32;
error CanNotPickMedianOfEmptyArray();
// This function modifies the array
function pickMedian(uint256[] memory arr) internal pure returns (uint256) {
if (arr.length == 0) {
revert CanNotPickMedianOfEmptyArray();
}
sort(arr);
uint256 middleIndex = arr.length / 2;
if (arr.length % 2 == 0) {
uint256 sum = SafeMath.add(arr[middleIndex - 1], arr[middleIndex]);
return sum / 2;
} else {
return arr[middleIndex];
}
}
function sort(uint256[] memory arr) internal pure {
assembly {
let arrLength := mload(arr)
let valuesPtr := add(arr, BYTES_ARR_LEN_VAR_BS)
let endPtr := add(valuesPtr, mul(arrLength, UINT256_VALUE_BS))
for {
let arrIPtr := valuesPtr
} lt(arrIPtr, endPtr) {
arrIPtr := add(arrIPtr, UINT256_VALUE_BS) // arrIPtr += 32
} {
for {
let arrJPtr := valuesPtr
} lt(arrJPtr, arrIPtr) {
arrJPtr := add(arrJPtr, UINT256_VALUE_BS) // arrJPtr += 32
} {
let arrI := mload(arrIPtr)
let arrJ := mload(arrJPtr)
if lt(arrI, arrJ) {
mstore(arrIPtr, arrJ)
mstore(arrJPtr, arrI)
}
}
}
}
}
}{
"remappings": [
"@1inch/=node_modules/@1inch/",
"@arbitrum/=node_modules/@arbitrum/",
"@chainlink/=node_modules/@chainlink/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@gearbox-protocol/=node_modules/@gearbox-protocol/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@redstone-finance/=node_modules/@redstone-finance/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-std/=lib/forge-std/src/"
],
"optimizer": {
"enabled": true,
"runs": 1000
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"bytes32","name":"_dataFeedId","type":"bytes32"},{"internalType":"address[10]","name":"_signers","type":"address[10]"},{"internalType":"uint8","name":"signersThreshold","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CalldataMustHaveValidPayload","type":"error"},{"inputs":[],"name":"CalldataOverOrUnderFlow","type":"error"},{"inputs":[],"name":"CanNotPickMedianOfEmptyArray","type":"error"},{"inputs":[],"name":"DataPackageTimestampIncorrect","type":"error"},{"inputs":[],"name":"DataPackageTimestampMustNotBeZero","type":"error"},{"inputs":[],"name":"DataPackageTimestampsMustBeEqual","type":"error"},{"inputs":[],"name":"DuplicateSignersException","type":"error"},{"inputs":[],"name":"EachSignerMustProvideTheSameValue","type":"error"},{"inputs":[],"name":"EmptyCalldataPointersArr","type":"error"},{"inputs":[],"name":"GetDataServiceIdNotImplemented","type":"error"},{"inputs":[],"name":"IncorrectPriceException","type":"error"},{"inputs":[],"name":"IncorrectSignersThresholdException","type":"error"},{"inputs":[],"name":"IncorrectUnsignedMetadataSize","type":"error"},{"inputs":[{"internalType":"uint256","name":"receivedSignersCount","type":"uint256"},{"internalType":"uint256","name":"requiredSignersCount","type":"uint256"}],"name":"InsufficientNumberOfUniqueSigners","type":"error"},{"inputs":[],"name":"InvalidCalldataPointer","type":"error"},{"inputs":[],"name":"NotEnoughSignersException","type":"error"},{"inputs":[],"name":"RedstonePayloadMustHaveAtLeastOneDataPackage","type":"error"},{"inputs":[],"name":"RedstonePayloadTimestampIncorrect","type":"error"},{"inputs":[{"internalType":"address","name":"receivedSigner","type":"address"}],"name":"SignerNotAuthorised","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"price","type":"uint256"}],"name":"UpdatePrice","type":"event"},{"inputs":[{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"aggregateValues","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"dataFeedId","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"description","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"extractTimestampsAndAssertAllAreEqual","outputs":[{"internalType":"uint256","name":"extractedTimestamp","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"signerAddress","type":"address"}],"name":"getAuthorisedSignerIndex","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDataServiceId","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUniqueSignersThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPayloadTimestamp","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPrice","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestRoundData","outputs":[{"internalType":"uint80","name":"","type":"uint80"},{"internalType":"int256","name":"","type":"int256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint80","name":"","type":"uint80"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"priceFeedType","outputs":[{"internalType":"enum PriceFeedType","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress0","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress1","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress2","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress3","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress4","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress5","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress6","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress7","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress8","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress9","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"skipPriceCheck","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"updatable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"data","type":"bytes"}],"name":"updatePrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"receivedTimestampMilliseconds","type":"uint256"}],"name":"validateTimestamp","outputs":[],"stateMutability":"view","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]Contract Creation Code
6102206040523480156200001257600080fd5b506040516200205638038062002056833981016040819052620000359162000227565b60ff81161580620000495750600a8160ff16115b156200006857604051630d211b8f60e31b815260040160405180910390fd5b6000805b600a8110156200012f5760008482600a81106200008d576200008d620002e6565b60200201516001600160a01b0316146200012657600181015b600a8110156200011e578482600a8110620000c557620000c5620002e6565b60200201516001600160a01b03168582600a8110620000e857620000e8620002e6565b60200201516001600160a01b031603620001155760405163495df29160e11b815260040160405180910390fd5b600101620000a6565b508160010191505b6001016200006c565b508160ff168110156200015557604051630416f49d60e21b815260040160405180910390fd5b506001600160a01b03938416608090815260a09384528251851660c09081526020840151861660e0908152604085015187166101009081526060860151881661012090815293860151881661014052958501518716610160529084015186166101805283015185166101a0529282015184166101c0529101519091166101e05260ff1661020052620002fc565b80516001600160a01b0381168114620001fa57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b805160ff81168114620001fa57600080fd5b6000806000806101a085870312156200023f57600080fd5b6200024a85620001e2565b9350602080860151935086605f8701126200026457600080fd5b60405161014081016001600160401b03811182821017156200028a576200028a620001ff565b60405280610180880189811115620002a157600080fd5b604089015b81811015620002c857620002ba81620001e2565b8352918401918401620002a6565b50829550620002d78162000215565b94505050505092959194509250565b634e487b7160e01b600052603260045260246000fd5b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051611c5462000402600039600081816104d9015281816111830152818161145c01526115f701526000818161042501526107f50152600081816102ed01526107b401526000818161024f01526107730152600081816103eb015261073201526000818161049a01526106f101526000818161036101526106b0015260008181610210015261066f0152600081816103c4015261062e01526000818161032501526105ed01526000818161038801526105ac0152600081816102900152610ada01526000818161050201526109bf0152611c546000f3fe608060405234801561001057600080fd5b50600436106101c45760003560e01c80638736ec47116100f9578063d62ada1111610097578063f50b2efe11610071578063f50b2efe146104c4578063f90c4924146104d7578063fc0c546a146104fd578063feaf968c1461052457600080fd5b8063d62ada111461047d578063dcdacf8914610495578063e75aeec8146104bc57600080fd5b8063b24ebfcc116100d3578063b24ebfcc1461040d578063bc48da9e14610420578063bdbe420414610447578063c274583a1461047557600080fd5b80638736ec47146103aa5780638dba0538146103bf5780639e0153d4146103e657600080fd5b80634ee1a1e6116101665780635decfe37116101405780635decfe37146103205780637284e416146103475780637ed0185f1461035c578063816f444a1461038357600080fd5b80634ee1a1e6146102e857806354fd4d501461030f57806355a547d51461031857600080fd5b8063313ce567116101a2578063313ce56714610271578063370c826b1461028b5780633ce142f5146102c05780633fd0875f146102d357600080fd5b8063053f14da146101c957806309c032ba1461020b5780631ac23b3d1461024a575b600080fd5b6000546101e5906fffffffffffffffffffffffffffffffff1681565b6040516fffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6102327f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610202565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b610279600881565b60405160ff9091168152602001610202565b6102b27f000000000000000000000000000000000000000000000000000000000000000081565b604051908152602001610202565b6102796102ce3660046117e0565b610571565b6102db600f81565b6040516102029190611809565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b6102b261012c81565b6102b2610858565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b61034f6109bb565b6040516102029190611855565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b6103bd6103b8366004611888565b610a67565b005b6102327f000000000000000000000000000000000000000000000000000000000000000081565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b6102b261041b366004611941565b610bd9565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b60005461045f90600160801b900464ffffffffff1681565b60405164ffffffffff9091168152602001610202565b61034f610bea565b610485600081565b6040519015158152602001610202565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b610485600181565b6103bd6104d23660046119db565b610c1e565b7f0000000000000000000000000000000000000000000000000000000000000000610279565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b60008054604080518381526fffffffffffffffffffffffffffffffff83166020820152908101839052600160801b90910464ffffffffff166060820152608081019190915260a001610202565b60006001600160a01b0382166105aa576040516303b1166f60e61b81526001600160a01b03831660048201526024015b60405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316036105eb57506000919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361062c57506001919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361066d57506002919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316036106ae57506003919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316036106ef57506004919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361073057506005919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361077157506006919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316036107b257506007919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316036107f357506008919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361083457506009919050565b6040516303b1166f60e61b81526001600160a01b03831660048201526024016105a1565b600080610863610c7c565b9050600061087082610d5c565b61ffff169050806000036108b0576040517f8552ff3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108bb600283611a0a565b915060005b818110156109b55760006108d384610d96565b90506000806108e3606887611a0a565b905060006108f18236611a1d565b9050803592508265ffffffffffff16600003610939576040517f336dc9d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b87600003610951578265ffffffffffff169750610992565b878365ffffffffffff1614610992576040517fd9d1f46500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61099c8488611a0a565b96505050505080806109ad90611a30565b9150506108c0565b50505090565b60607f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610a1b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a439190810190611a71565b604051602001610a539190611aed565b604051602081830303815290604052905090565b6000610a7582840184611b2e565b50600054909150600160801b900464ffffffffff168111610a9557505050565b610a9e81610dd2565b600080547fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff16600160801b64ffffffffff841602178155610afe7f0000000000000000000000000000000000000000000000000000000000000000610e2e565b905080600003610b3a576040517f53b798e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546fffffffffffffffffffffffffffffffff168114610bd357610b5e81610e9e565b600080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff929092169190911790556040518181527f1a15ab7124a4e1ce00837351261771caf1691cd7d85ed3a0ac3157a1ee1a38059060200160405180910390a15b50505050565b6000610be482610f44565b92915050565b60606040517f608b530700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610c2c6103e883611bc9565b600054909150600160801b900464ffffffffff168114610c78576040517f13f5f29000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60006602ed57011e0000601f1936013581161480610cc6576040517fe7764c9e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660291115610cea57604051632bcb7bc560e11b815260040160405180910390fd5b5060281936013560006009610d05600362ffffff8516611a0a565b610d0f9190611a0a565b905036610d1d600283611a0a565b1115610d55576040517fc30a7bd700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9392505050565b600080610d6a602084611a0a565b905036811115610d8d57604051632bcb7bc560e11b815260040160405180910390fd5b36033592915050565b6000806000610da484610f4f565b9092509050604e610db6826020611a0a565b610dc09084611bdd565b610dca9190611a0a565b949350505050565b80421015610e2157603c610de64283611a1d565b1115610e1e576040517f36764ab900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b610258610de68242611a1d565b604080516001808252818301909252600091829190602080830190803683370190505090508281600081518110610e6757610e67611bf4565b602002602001018181525050610e7c81610fa6565b600081518110610e8e57610e8e611bf4565b6020026020010151915050919050565b60006fffffffffffffffffffffffffffffffff821115610f40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201527f323820626974730000000000000000000000000000000000000000000000000060648201526084016105a1565b5090565b6000610be482610fb1565b600080808080610f60604187611a0a565b90506000610f79610f72602084611a0a565b3690611085565b803594509050610f8a816003611085565b62ffffff9490941697933563ffffffff16965092945050505050565b6060610be482611091565b60008151600003610fee576040517f9e198af900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ff78261129d565b6000600283516110079190611bc9565b9050600283516110179190611c0a565b6000036110735760006110668461102f600185611a1d565b8151811061103f5761103f611bf4565b602002602001015185848151811061105957611059611bf4565b60200260200101516112e5565b9050610dca600282611bc9565b828181518110610e8e57610e8e611bf4565b6000610d558284611a1d565b60606000825167ffffffffffffffff8111156110af576110af6118fa565b6040519080825280602002602001820160405280156110d8578160200160208202803683370190505b5090506000835167ffffffffffffffff8111156110f7576110f76118fa565b604051908082528060200260200182016040528015611120578160200160208202803683370190505b5090506000845167ffffffffffffffff81111561113f5761113f6118fa565b60405190808252806020026020018201604052801561117257816020015b606081526020019060019003908161115d5790505b50905060005b8551811015611217577f000000000000000000000000000000000000000000000000000000000000000060ff1667ffffffffffffffff8111156111bd576111bd6118fa565b6040519080825280602002602001820160405280156111e6578160200160208202803683370190505b508282815181106111f9576111f9611bf4565b6020026020010181905250808061120f90611a30565b915050611178565b506000611222610c7c565b9050600061122f82610d5c565b61ffff169050611240600283611a0a565b60405190925060005b828110156112865760006112608a898989896112f1565b905061126c8186611a0a565b94508260405250808061127e90611a30565b915050611249565b5061129184876115a9565b98975050505050505050565b8051602082016020820281019150805b82811015610bd357815b818110156112dc5781518151808210156112d2578084528183525b50506020016112b7565b506020016112ad565b6000610d558284611a0a565b60008060008061130085610f4f565b909250905060008080606081600d61132361131c602089611a0a565b89906116fd565b61132d9190611a0a565b9050600061133f610f7260688d611a0a565b9050600061135c8361135260418f611a0a565b610f729190611a0a565b9050611368838261137b565b935082602085012094508135965061139f565b60408051838152602081850181019092526000910183838237601f19019392505050565b6113b08765ffffffffffff16610c1e565b6113c4856113bf60418f611a0a565b611709565b95506113cf86610571565b60ff1699505050505050505060008060005b84811015611576576113f4888583611781565b909350915060005b8c51811015611563578c818151811061141757611417611bf4565b602002602001015184036115515760008b828151811061143957611439611bf4565b6020026020010151905061145281896001901b16151590565b15801561149a57507f000000000000000000000000000000000000000000000000000000000000000060ff168d838151811061149057611490611bf4565b6020026020010151105b1561154b578c82815181106114b1576114b1611bf4565b6020026020010180518091906114c690611a30565b81525050838b83815181106114dd576114dd611bf4565b602002602001015160018f85815181106114f9576114f9611bf4565b602002602001015161150b9190611a1d565b8151811061151b5761151b611bf4565b60209081029190910101526001881b81178c838151811061153e5761153e611bf4565b6020026020010181815250505b50611563565b8061155b81611a30565b9150506113fc565b508061156e81611a30565b9150506113e1565b505050816020826115879190611a0a565b6115919190611bdd565b61159c90604e611a0a565b9998505050505050505050565b60606000835167ffffffffffffffff8111156115c7576115c76118fa565b6040519080825280602002602001820160405280156115f0578160200160208202803683370190505b50905060ff7f00000000000000000000000000000000000000000000000000000000000000001660005b85518110156116f3578185828151811061163657611636611bf4565b6020026020010151101561169c5784818151811061165657611656611bf4565b6020026020010151826040517f2b13aef50000000000000000000000000000000000000000000000000000000081526004016105a1929190918252602082015260400190565b60006116c08783815181106116b3576116b3611bf4565b6020026020010151610bd9565b9050808483815181106116d5576116d5611bf4565b602090810291909101015250806116eb81611a30565b91505061161a565b5090949350505050565b6000610d558284611bdd565b60408051600080825260208083018085528690523685900380850135831a948401859052803560608501819052910135608084018190529193909260019060a0016020604051602081039080840390855afa15801561176c573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b60008080611790604e87611a0a565b905060006117bd6117b66117a5602089611a0a565b6117b0886001611a0a565b906116fd565b83906112e5565b905060006117cb3683611085565b80359960209091013598509650505050505050565b6000602082840312156117f257600080fd5b81356001600160a01b0381168114610d5557600080fd5b602081016014831061182b57634e487b7160e01b600052602160045260246000fd5b91905290565b60005b8381101561184c578181015183820152602001611834565b50506000910152565b6020815260008251806020840152611874816040850160208701611831565b601f01601f19169190910160400192915050565b6000806020838503121561189b57600080fd5b823567ffffffffffffffff808211156118b357600080fd5b818501915085601f8301126118c757600080fd5b8135818111156118d657600080fd5b8660208285010111156118e857600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611939576119396118fa565b604052919050565b6000602080838503121561195457600080fd5b823567ffffffffffffffff8082111561196c57600080fd5b818501915085601f83011261198057600080fd5b813581811115611992576119926118fa565b8060051b91506119a3848301611910565b81815291830184019184810190888411156119bd57600080fd5b938501935b83851015611291578435825293850193908501906119c2565b6000602082840312156119ed57600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610be457610be46119f4565b81810381811115610be457610be46119f4565b600060018201611a4257611a426119f4565b5060010190565b600067ffffffffffffffff821115611a6357611a636118fa565b50601f01601f191660200190565b600060208284031215611a8357600080fd5b815167ffffffffffffffff811115611a9a57600080fd5b8201601f81018413611aab57600080fd5b8051611abe611ab982611a49565b611910565b818152856020838501011115611ad357600080fd5b611ae4826020830160208601611831565b95945050505050565b60008251611aff818460208701611831565b7f202f205553442052656473746f6e652070726963652066656564000000000000920191825250601a01919050565b60008060408385031215611b4157600080fd5b82359150602083013567ffffffffffffffff811115611b5f57600080fd5b8301601f81018513611b7057600080fd5b8035611b7e611ab982611a49565b818152866020838501011115611b9357600080fd5b816020840160208301376000602083830101528093505050509250929050565b634e487b7160e01b600052601260045260246000fd5b600082611bd857611bd8611bb3565b500490565b8082028115828204841417610be457610be46119f4565b634e487b7160e01b600052603260045260246000fd5b600082611c1957611c19611bb3565b50069056fea2646970667358221220a958d95f72884e6e508404b6ab7562ac71f1361f6f327f7ea158588dc6920d3b64736f6c63430008110033000000000000000000000000a1290d69c65a6fe4df752f95823fae25cb99e5a772734554485f46554e44414d454e54414c0000000000000000000000000000000000000000000000000000008bb8f32df04c8b654987daaed53d6b6091e3b774000000000000000000000000deb22f54738d54976c4c0fe5ce6d408e40d8849900000000000000000000000051ce04be4b3e32572c4ec9135221d0691ba7d202000000000000000000000000dd682daec5a90dd295d14da4b0bec9281017b5be0000000000000000000000009c5ae89c4af6aa32ce58588dbaf90d18a855b6de000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101c45760003560e01c80638736ec47116100f9578063d62ada1111610097578063f50b2efe11610071578063f50b2efe146104c4578063f90c4924146104d7578063fc0c546a146104fd578063feaf968c1461052457600080fd5b8063d62ada111461047d578063dcdacf8914610495578063e75aeec8146104bc57600080fd5b8063b24ebfcc116100d3578063b24ebfcc1461040d578063bc48da9e14610420578063bdbe420414610447578063c274583a1461047557600080fd5b80638736ec47146103aa5780638dba0538146103bf5780639e0153d4146103e657600080fd5b80634ee1a1e6116101665780635decfe37116101405780635decfe37146103205780637284e416146103475780637ed0185f1461035c578063816f444a1461038357600080fd5b80634ee1a1e6146102e857806354fd4d501461030f57806355a547d51461031857600080fd5b8063313ce567116101a2578063313ce56714610271578063370c826b1461028b5780633ce142f5146102c05780633fd0875f146102d357600080fd5b8063053f14da146101c957806309c032ba1461020b5780631ac23b3d1461024a575b600080fd5b6000546101e5906fffffffffffffffffffffffffffffffff1681565b6040516fffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b6102327f000000000000000000000000dd682daec5a90dd295d14da4b0bec9281017b5be81565b6040516001600160a01b039091168152602001610202565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b610279600881565b60405160ff9091168152602001610202565b6102b27f72734554485f46554e44414d454e54414c00000000000000000000000000000081565b604051908152602001610202565b6102796102ce3660046117e0565b610571565b6102db600f81565b6040516102029190611809565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b6102b261012c81565b6102b2610858565b6102327f000000000000000000000000deb22f54738d54976c4c0fe5ce6d408e40d8849981565b61034f6109bb565b6040516102029190611855565b6102327f0000000000000000000000009c5ae89c4af6aa32ce58588dbaf90d18a855b6de81565b6102327f0000000000000000000000008bb8f32df04c8b654987daaed53d6b6091e3b77481565b6103bd6103b8366004611888565b610a67565b005b6102327f00000000000000000000000051ce04be4b3e32572c4ec9135221d0691ba7d20281565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b6102b261041b366004611941565b610bd9565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b60005461045f90600160801b900464ffffffffff1681565b60405164ffffffffff9091168152602001610202565b61034f610bea565b610485600081565b6040519015158152602001610202565b6102327f000000000000000000000000000000000000000000000000000000000000000081565b610485600181565b6103bd6104d23660046119db565b610c1e565b7f0000000000000000000000000000000000000000000000000000000000000005610279565b6102327f000000000000000000000000a1290d69c65a6fe4df752f95823fae25cb99e5a781565b60008054604080518381526fffffffffffffffffffffffffffffffff83166020820152908101839052600160801b90910464ffffffffff166060820152608081019190915260a001610202565b60006001600160a01b0382166105aa576040516303b1166f60e61b81526001600160a01b03831660048201526024015b60405180910390fd5b7f0000000000000000000000008bb8f32df04c8b654987daaed53d6b6091e3b7746001600160a01b0316826001600160a01b0316036105eb57506000919050565b7f000000000000000000000000deb22f54738d54976c4c0fe5ce6d408e40d884996001600160a01b0316826001600160a01b03160361062c57506001919050565b7f00000000000000000000000051ce04be4b3e32572c4ec9135221d0691ba7d2026001600160a01b0316826001600160a01b03160361066d57506002919050565b7f000000000000000000000000dd682daec5a90dd295d14da4b0bec9281017b5be6001600160a01b0316826001600160a01b0316036106ae57506003919050565b7f0000000000000000000000009c5ae89c4af6aa32ce58588dbaf90d18a855b6de6001600160a01b0316826001600160a01b0316036106ef57506004919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361073057506005919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361077157506006919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316036107b257506007919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b0316036107f357506008919050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316826001600160a01b03160361083457506009919050565b6040516303b1166f60e61b81526001600160a01b03831660048201526024016105a1565b600080610863610c7c565b9050600061087082610d5c565b61ffff169050806000036108b0576040517f8552ff3c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6108bb600283611a0a565b915060005b818110156109b55760006108d384610d96565b90506000806108e3606887611a0a565b905060006108f18236611a1d565b9050803592508265ffffffffffff16600003610939576040517f336dc9d000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b87600003610951578265ffffffffffff169750610992565b878365ffffffffffff1614610992576040517fd9d1f46500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b61099c8488611a0a565b96505050505080806109ad90611a30565b9150506108c0565b50505090565b60607f000000000000000000000000a1290d69c65a6fe4df752f95823fae25cb99e5a76001600160a01b03166395d89b416040518163ffffffff1660e01b8152600401600060405180830381865afa158015610a1b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052610a439190810190611a71565b604051602001610a539190611aed565b604051602081830303815290604052905090565b6000610a7582840184611b2e565b50600054909150600160801b900464ffffffffff168111610a9557505050565b610a9e81610dd2565b600080547fffffffffffffffffffffff0000000000ffffffffffffffffffffffffffffffff16600160801b64ffffffffff841602178155610afe7f72734554485f46554e44414d454e54414c000000000000000000000000000000610e2e565b905080600003610b3a576040517f53b798e200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000546fffffffffffffffffffffffffffffffff168114610bd357610b5e81610e9e565b600080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff929092169190911790556040518181527f1a15ab7124a4e1ce00837351261771caf1691cd7d85ed3a0ac3157a1ee1a38059060200160405180910390a15b50505050565b6000610be482610f44565b92915050565b60606040517f608b530700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000610c2c6103e883611bc9565b600054909150600160801b900464ffffffffff168114610c78576040517f13f5f29000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5050565b60006602ed57011e0000601f1936013581161480610cc6576040517fe7764c9e00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60003660291115610cea57604051632bcb7bc560e11b815260040160405180910390fd5b5060281936013560006009610d05600362ffffff8516611a0a565b610d0f9190611a0a565b905036610d1d600283611a0a565b1115610d55576040517fc30a7bd700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b9392505050565b600080610d6a602084611a0a565b905036811115610d8d57604051632bcb7bc560e11b815260040160405180910390fd5b36033592915050565b6000806000610da484610f4f565b9092509050604e610db6826020611a0a565b610dc09084611bdd565b610dca9190611a0a565b949350505050565b80421015610e2157603c610de64283611a1d565b1115610e1e576040517f36764ab900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b610258610de68242611a1d565b604080516001808252818301909252600091829190602080830190803683370190505090508281600081518110610e6757610e67611bf4565b602002602001018181525050610e7c81610fa6565b600081518110610e8e57610e8e611bf4565b6020026020010151915050919050565b60006fffffffffffffffffffffffffffffffff821115610f40576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203160448201527f323820626974730000000000000000000000000000000000000000000000000060648201526084016105a1565b5090565b6000610be482610fb1565b600080808080610f60604187611a0a565b90506000610f79610f72602084611a0a565b3690611085565b803594509050610f8a816003611085565b62ffffff9490941697933563ffffffff16965092945050505050565b6060610be482611091565b60008151600003610fee576040517f9e198af900000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610ff78261129d565b6000600283516110079190611bc9565b9050600283516110179190611c0a565b6000036110735760006110668461102f600185611a1d565b8151811061103f5761103f611bf4565b602002602001015185848151811061105957611059611bf4565b60200260200101516112e5565b9050610dca600282611bc9565b828181518110610e8e57610e8e611bf4565b6000610d558284611a1d565b60606000825167ffffffffffffffff8111156110af576110af6118fa565b6040519080825280602002602001820160405280156110d8578160200160208202803683370190505b5090506000835167ffffffffffffffff8111156110f7576110f76118fa565b604051908082528060200260200182016040528015611120578160200160208202803683370190505b5090506000845167ffffffffffffffff81111561113f5761113f6118fa565b60405190808252806020026020018201604052801561117257816020015b606081526020019060019003908161115d5790505b50905060005b8551811015611217577f000000000000000000000000000000000000000000000000000000000000000560ff1667ffffffffffffffff8111156111bd576111bd6118fa565b6040519080825280602002602001820160405280156111e6578160200160208202803683370190505b508282815181106111f9576111f9611bf4565b6020026020010181905250808061120f90611a30565b915050611178565b506000611222610c7c565b9050600061122f82610d5c565b61ffff169050611240600283611a0a565b60405190925060005b828110156112865760006112608a898989896112f1565b905061126c8186611a0a565b94508260405250808061127e90611a30565b915050611249565b5061129184876115a9565b98975050505050505050565b8051602082016020820281019150805b82811015610bd357815b818110156112dc5781518151808210156112d2578084528183525b50506020016112b7565b506020016112ad565b6000610d558284611a0a565b60008060008061130085610f4f565b909250905060008080606081600d61132361131c602089611a0a565b89906116fd565b61132d9190611a0a565b9050600061133f610f7260688d611a0a565b9050600061135c8361135260418f611a0a565b610f729190611a0a565b9050611368838261137b565b935082602085012094508135965061139f565b60408051838152602081850181019092526000910183838237601f19019392505050565b6113b08765ffffffffffff16610c1e565b6113c4856113bf60418f611a0a565b611709565b95506113cf86610571565b60ff1699505050505050505060008060005b84811015611576576113f4888583611781565b909350915060005b8c51811015611563578c818151811061141757611417611bf4565b602002602001015184036115515760008b828151811061143957611439611bf4565b6020026020010151905061145281896001901b16151590565b15801561149a57507f000000000000000000000000000000000000000000000000000000000000000560ff168d838151811061149057611490611bf4565b6020026020010151105b1561154b578c82815181106114b1576114b1611bf4565b6020026020010180518091906114c690611a30565b81525050838b83815181106114dd576114dd611bf4565b602002602001015160018f85815181106114f9576114f9611bf4565b602002602001015161150b9190611a1d565b8151811061151b5761151b611bf4565b60209081029190910101526001881b81178c838151811061153e5761153e611bf4565b6020026020010181815250505b50611563565b8061155b81611a30565b9150506113fc565b508061156e81611a30565b9150506113e1565b505050816020826115879190611a0a565b6115919190611bdd565b61159c90604e611a0a565b9998505050505050505050565b60606000835167ffffffffffffffff8111156115c7576115c76118fa565b6040519080825280602002602001820160405280156115f0578160200160208202803683370190505b50905060ff7f00000000000000000000000000000000000000000000000000000000000000051660005b85518110156116f3578185828151811061163657611636611bf4565b6020026020010151101561169c5784818151811061165657611656611bf4565b6020026020010151826040517f2b13aef50000000000000000000000000000000000000000000000000000000081526004016105a1929190918252602082015260400190565b60006116c08783815181106116b3576116b3611bf4565b6020026020010151610bd9565b9050808483815181106116d5576116d5611bf4565b602090810291909101015250806116eb81611a30565b91505061161a565b5090949350505050565b6000610d558284611bdd565b60408051600080825260208083018085528690523685900380850135831a948401859052803560608501819052910135608084018190529193909260019060a0016020604051602081039080840390855afa15801561176c573d6000803e3d6000fd5b5050604051601f190151979650505050505050565b60008080611790604e87611a0a565b905060006117bd6117b66117a5602089611a0a565b6117b0886001611a0a565b906116fd565b83906112e5565b905060006117cb3683611085565b80359960209091013598509650505050505050565b6000602082840312156117f257600080fd5b81356001600160a01b0381168114610d5557600080fd5b602081016014831061182b57634e487b7160e01b600052602160045260246000fd5b91905290565b60005b8381101561184c578181015183820152602001611834565b50506000910152565b6020815260008251806020840152611874816040850160208701611831565b601f01601f19169190910160400192915050565b6000806020838503121561189b57600080fd5b823567ffffffffffffffff808211156118b357600080fd5b818501915085601f8301126118c757600080fd5b8135818111156118d657600080fd5b8660208285010111156118e857600080fd5b60209290920196919550909350505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715611939576119396118fa565b604052919050565b6000602080838503121561195457600080fd5b823567ffffffffffffffff8082111561196c57600080fd5b818501915085601f83011261198057600080fd5b813581811115611992576119926118fa565b8060051b91506119a3848301611910565b81815291830184019184810190888411156119bd57600080fd5b938501935b83851015611291578435825293850193908501906119c2565b6000602082840312156119ed57600080fd5b5035919050565b634e487b7160e01b600052601160045260246000fd5b80820180821115610be457610be46119f4565b81810381811115610be457610be46119f4565b600060018201611a4257611a426119f4565b5060010190565b600067ffffffffffffffff821115611a6357611a636118fa565b50601f01601f191660200190565b600060208284031215611a8357600080fd5b815167ffffffffffffffff811115611a9a57600080fd5b8201601f81018413611aab57600080fd5b8051611abe611ab982611a49565b611910565b818152856020838501011115611ad357600080fd5b611ae4826020830160208601611831565b95945050505050565b60008251611aff818460208701611831565b7f202f205553442052656473746f6e652070726963652066656564000000000000920191825250601a01919050565b60008060408385031215611b4157600080fd5b82359150602083013567ffffffffffffffff811115611b5f57600080fd5b8301601f81018513611b7057600080fd5b8035611b7e611ab982611a49565b818152866020838501011115611b9357600080fd5b816020840160208301376000602083830101528093505050509250929050565b634e487b7160e01b600052601260045260246000fd5b600082611bd857611bd8611bb3565b500490565b8082028115828204841417610be457610be46119f4565b634e487b7160e01b600052603260045260246000fd5b600082611c1957611c19611bb3565b50069056fea2646970667358221220a958d95f72884e6e508404b6ab7562ac71f1361f6f327f7ea158588dc6920d3b64736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a1290d69c65a6fe4df752f95823fae25cb99e5a772734554485f46554e44414d454e54414c0000000000000000000000000000000000000000000000000000008bb8f32df04c8b654987daaed53d6b6091e3b774000000000000000000000000deb22f54738d54976c4c0fe5ce6d408e40d8849900000000000000000000000051ce04be4b3e32572c4ec9135221d0691ba7d202000000000000000000000000dd682daec5a90dd295d14da4b0bec9281017b5be0000000000000000000000009c5ae89c4af6aa32ce58588dbaf90d18a855b6de000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005
-----Decoded View---------------
Arg [0] : _token (address): 0xA1290d69c65A6Fe4DF752f95823fae25cB99e5A7
Arg [1] : _dataFeedId (bytes32): 0x72734554485f46554e44414d454e54414c000000000000000000000000000000
Arg [2] : _signers (address[10]): 0x8BB8F32Df04c8b654987DAaeD53D6B6091e3B774,0xdEB22f54738d54976C4c0fe5ce6d408E40d88499,0x51Ce04Be4b3E32572C4Ec9135221d0691Ba7d202,0xDD682daEC5A90dD295d14DA4b0bec9281017b5bE,0x9c5AE89C4Af6aA32cE58588DBaF90d18a855B6de,0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000,0x0000000000000000000000000000000000000000
Arg [3] : signersThreshold (uint8): 5
-----Encoded View---------------
13 Constructor Arguments found :
Arg [0] : 000000000000000000000000a1290d69c65a6fe4df752f95823fae25cb99e5a7
Arg [1] : 72734554485f46554e44414d454e54414c000000000000000000000000000000
Arg [2] : 0000000000000000000000008bb8f32df04c8b654987daaed53d6b6091e3b774
Arg [3] : 000000000000000000000000deb22f54738d54976c4c0fe5ce6d408e40d88499
Arg [4] : 00000000000000000000000051ce04be4b3e32572c4ec9135221d0691ba7d202
Arg [5] : 000000000000000000000000dd682daec5a90dd295d14da4b0bec9281017b5be
Arg [6] : 0000000000000000000000009c5ae89c4af6aa32ce58588dbaf90d18a855b6de
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000005
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.