Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Latest 1 from a total of 1 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Approve All | 4454270 | 852 days ago | IN | 0 ETH | 0.00012252 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Loading...
Loading
Contract Name:
AllocationExchange
Compiler Version
v0.7.6+commit.7338295f
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/cryptography/ECDSA.sol";
import "@openzeppelin/contracts/utils/Address.sol";
import "../governance/Governed.sol";
import "../staking/IStaking.sol";
import "../token/IGraphToken.sol";
/**
* @title Allocation Exchange
* @dev This contract holds tokens that anyone with a voucher signed by the
* authority can redeem. The contract validates if the voucher presented is valid
* and then sends tokens to the Staking contract by calling the collect() function
* passing the voucher allocationID. The contract enforces that only one voucher for
* an allocationID can be redeemed.
* Only governance can change the authority.
*/
contract AllocationExchange is Governed {
// An allocation voucher represents a signed message that allows
// redeeming an amount of funds from this contract and collect
// them as part of an allocation
struct AllocationVoucher {
address allocationID;
uint256 amount;
bytes signature; // 65 bytes
}
// -- Constants --
uint256 private constant MAX_UINT256 = 2**256 - 1;
uint256 private constant SIGNATURE_LENGTH = 65;
// -- State --
IStaking private immutable staking;
IGraphToken private immutable graphToken;
mapping(address => bool) public authority;
mapping(address => bool) public allocationsRedeemed;
// -- Events
event AuthoritySet(address indexed account, bool authorized);
event AllocationRedeemed(address indexed allocationID, uint256 amount);
event TokensWithdrawn(address indexed to, uint256 amount);
// -- Functions
/**
* @notice Contract constructor.
* @param _graphToken Address of the GRT token
* @param _staking Address of the protocol Staking contract
* @param _governor Account capable of withdrawing funds and setting the authority
* @param _authority Account that can sign the vouchers that this contract will redeem
*/
constructor(
IGraphToken _graphToken,
IStaking _staking,
address _governor,
address _authority
) {
require(_governor != address(0), "Exchange: governor must be set");
Governed._initialize(_governor);
graphToken = _graphToken;
staking = _staking;
_setAuthority(_authority, true);
}
/**
* @notice Approve the staking contract to pull any amount of tokens from this contract.
* @dev Increased gas efficiency instead of approving on each voucher redeem
*/
function approveAll() external {
graphToken.approve(address(staking), MAX_UINT256);
}
/**
* @notice Withdraw tokens held in the contract.
* @dev Only the governor can withdraw
* @param _to Destination to send the tokens
* @param _amount Amount of tokens to withdraw
*/
function withdraw(address _to, uint256 _amount) external onlyGovernor {
require(_to != address(0), "Exchange: empty destination");
require(_amount != 0, "Exchange: empty amount");
require(graphToken.transfer(_to, _amount), "Exchange: cannot transfer");
emit TokensWithdrawn(_to, _amount);
}
/**
* @notice Set the authority allowed to sign vouchers.
* @dev Only the governor can set the authority
* @param _authority Address of the signing authority
* @param _authorized True if the authority is authorized to sign vouchers, false to unset
*/
function setAuthority(address _authority, bool _authorized) external onlyGovernor {
_setAuthority(_authority, _authorized);
}
/**
* @notice Set the authority allowed to sign vouchers.
* @param _authority Address of the signing authority
* @param _authorized True if the authority is authorized to sign vouchers, false to unset
*/
function _setAuthority(address _authority, bool _authorized) private {
require(_authority != address(0), "Exchange: empty authority");
// This will help catch some operational errors but not all.
// The validation will fail under the following conditions:
// - a contract in construction
// - an address where a contract will be created
// - an address where a contract lived, but was destroyed
require(!Address.isContract(_authority), "Exchange: authority must be EOA");
authority[_authority] = _authorized;
emit AuthoritySet(_authority, _authorized);
}
/**
* @notice Redeem a voucher signed by the authority. No voucher double spending is allowed.
* @dev The voucher must be signed using an Ethereum signed message
* @param _voucher Voucher data
*/
function redeem(AllocationVoucher memory _voucher) external {
_redeem(_voucher);
}
/**
* @notice Redeem multiple vouchers.
* @dev Each voucher must be signed using an Ethereum signed message
* @param _vouchers An array of vouchers
*/
function redeemMany(AllocationVoucher[] memory _vouchers) external {
for (uint256 i = 0; i < _vouchers.length; i++) {
_redeem(_vouchers[i]);
}
}
/**
* @notice Redeem a voucher signed by the authority. No voucher double spending is allowed.
* @dev The voucher must be signed using an Ethereum signed message
* @param _voucher Voucher data
*/
function _redeem(AllocationVoucher memory _voucher) private {
require(_voucher.amount > 0, "Exchange: zero tokens voucher");
require(_voucher.signature.length == SIGNATURE_LENGTH, "Exchange: invalid signature");
// Already redeemed check
require(
!allocationsRedeemed[_voucher.allocationID],
"Exchange: allocation already redeemed"
);
// Signature check
bytes32 messageHash = keccak256(abi.encodePacked(_voucher.allocationID, _voucher.amount));
address voucherSigner = ECDSA.recover(messageHash, _voucher.signature);
require(authority[voucherSigner], "Exchange: invalid signer");
// Mark allocation as collected
allocationsRedeemed[_voucher.allocationID] = true;
// Make the staking contract collect funds from this contract
// The Staking contract will validate if the allocation is valid
staking.collect(_voucher.amount, _voucher.allocationID);
emit AllocationRedeemed(_voucher.allocationID, _voucher.amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
*
* These functions can be used to verify that a message was signed by the holder
* of the private keys of a given address.
*/
library ECDSA {
/**
* @dev Returns the address that signed a hashed message (`hash`) with
* `signature`. This address can then be used for verification purposes.
*
* The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
* this function rejects them by requiring the `s` value to be in the lower
* half order, and the `v` value to be either 27 or 28.
*
* IMPORTANT: `hash` _must_ be the result of a hash operation for the
* verification to be secure: it is possible to craft signatures that
* recover to arbitrary addresses for non-hashed data. A safe way to ensure
* this is by receiving a hash of the original message (which may otherwise
* be too long), and then calling {toEthSignedMessageHash} on it.
*/
function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
// Check the signature length
if (signature.length != 65) {
revert("ECDSA: invalid signature length");
}
// Divide the signature in r, s and v variables
bytes32 r;
bytes32 s;
uint8 v;
// ecrecover takes the signature parameters, and the only way to get them
// currently is to use assembly.
// solhint-disable-next-line no-inline-assembly
assembly {
r := mload(add(signature, 0x20))
s := mload(add(signature, 0x40))
v := byte(0, mload(add(signature, 0x60)))
}
return recover(hash, v, r, s);
}
/**
* @dev Overload of {ECDSA-recover-bytes32-bytes-} that receives the `v`,
* `r` and `s` signature fields separately.
*/
function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
// EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
// unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
// the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
// signatures from current libraries generate a unique signature with an s-value in the lower half order.
//
// If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
// with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
// vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
// these malleable signatures as well.
require(uint256(s) <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, "ECDSA: invalid signature 's' value");
require(v == 27 || v == 28, "ECDSA: invalid signature 'v' value");
// If the signature is valid (and not malleable), return the signer address
address signer = ecrecover(hash, v, r, s);
require(signer != address(0), "ECDSA: invalid signature");
return signer;
}
/**
* @dev Returns an Ethereum Signed Message, created from a `hash`. This
* replicates the behavior of the
* https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign[`eth_sign`]
* JSON-RPC method.
*
* See {recover}.
*/
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
// 32 is the length in bytes of hash,
// enforced by the type signature above
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.2 <0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
// solhint-disable-next-line no-inline-assembly
assembly { size := extcodesize(account) }
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
// solhint-disable-next-line avoid-low-level-calls, avoid-call-value
(bool success, ) = recipient.call{ value: amount }("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain`call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.call{ value: value }(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.staticcall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory returndata) = target.delegatecall(data);
return _verifyCallResult(success, returndata, errorMessage);
}
function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
if (success) {
return returndata;
} else {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
// solhint-disable-next-line no-inline-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.7.6;
/**
* @title Graph Governance contract
* @dev All contracts that will be owned by a Governor entity should extend this contract.
*/
abstract contract Governed {
// -- State --
/// Address of the governor
address public governor;
/// Address of the new governor that is pending acceptance
address public pendingGovernor;
// -- Events --
/// Emitted when a new owner/governor has been set, but is pending acceptance
event NewPendingOwnership(address indexed from, address indexed to);
/// Emitted when a new owner/governor has accepted their role
event NewOwnership(address indexed from, address indexed to);
/**
* @dev Check if the caller is the governor.
*/
modifier onlyGovernor() {
require(msg.sender == governor, "Only Governor can call");
_;
}
/**
* @dev Initialize the governor for this contract
* @param _initGovernor Address of the governor
*/
function _initialize(address _initGovernor) internal {
governor = _initGovernor;
}
/**
* @notice Admin function to begin change of governor. The `_newGovernor` must call
* `acceptOwnership` to finalize the transfer.
* @param _newGovernor Address of new `governor`
*/
function transferOwnership(address _newGovernor) external onlyGovernor {
require(_newGovernor != address(0), "Governor must be set");
address oldPendingGovernor = pendingGovernor;
pendingGovernor = _newGovernor;
emit NewPendingOwnership(oldPendingGovernor, pendingGovernor);
}
/**
* @notice Admin function for pending governor to accept role and update governor.
* This function must called by the pending governor.
*/
function acceptOwnership() external {
address oldPendingGovernor = pendingGovernor;
require(
oldPendingGovernor != address(0) && msg.sender == oldPendingGovernor,
"Caller must be pending governor"
);
address oldGovernor = governor;
governor = oldPendingGovernor;
pendingGovernor = address(0);
emit NewOwnership(oldGovernor, governor);
emit NewPendingOwnership(oldPendingGovernor, pendingGovernor);
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.12 <0.8.0;
pragma abicoder v2;
import { IStakingBase } from "./IStakingBase.sol";
import { IStakingExtension } from "./IStakingExtension.sol";
import { IMulticall } from "../base/IMulticall.sol";
import { IManaged } from "../governance/IManaged.sol";
/**
* @title Interface for the Staking contract
* @notice This is the interface that should be used when interacting with the Staking contract.
* @dev Note that Staking doesn't actually inherit this interface. This is because of
* the custom setup of the Staking contract where part of the functionality is implemented
* in a separate contract (StakingExtension) to which calls are delegated through the fallback function.
*/
interface IStaking is IStakingBase, IStakingExtension, IMulticall, IManaged {
// Nothing to see here
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.7.6;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IGraphToken is IERC20 {
// -- Mint and Burn --
function burn(uint256 amount) external;
function burnFrom(address _from, uint256 amount) external;
function mint(address _to, uint256 _amount) external;
// -- Mint Admin --
function addMinter(address _account) external;
function removeMinter(address _account) external;
function renounceMinter() external;
function isMinter(address _account) external view returns (bool);
// -- Permit --
function permit(
address _owner,
address _spender,
uint256 _value,
uint256 _deadline,
uint8 _v,
bytes32 _r,
bytes32 _s
) external;
// -- Allowance --
function increaseAllowance(address spender, uint256 addedValue) external returns (bool);
function decreaseAllowance(address spender, uint256 subtractedValue) external returns (bool);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.12 <0.8.0;
pragma abicoder v2;
import { IStakingData } from "./IStakingData.sol";
/**
* @title Base interface for the Staking contract.
* @dev This interface includes only what's implemented in the base Staking contract.
* It does not include the L1 and L2 specific functionality. It also does not include
* several functions that are implemented in the StakingExtension contract, and are called
* via delegatecall through the fallback function. See IStaking.sol for an interface
* that includes the full functionality.
*/
interface IStakingBase is IStakingData {
/**
* @dev Emitted when `indexer` stakes `tokens` amount.
*/
event StakeDeposited(address indexed indexer, uint256 tokens);
/**
* @dev Emitted when `indexer` unstaked and locked `tokens` amount until `until` block.
*/
event StakeLocked(address indexed indexer, uint256 tokens, uint256 until);
/**
* @dev Emitted when `indexer` withdrew `tokens` staked.
*/
event StakeWithdrawn(address indexed indexer, uint256 tokens);
/**
* @dev Emitted when `indexer` allocated `tokens` amount to `subgraphDeploymentID`
* during `epoch`.
* `allocationID` indexer derived address used to identify the allocation.
* `metadata` additional information related to the allocation.
*/
event AllocationCreated(
address indexed indexer,
bytes32 indexed subgraphDeploymentID,
uint256 epoch,
uint256 tokens,
address indexed allocationID,
bytes32 metadata
);
/**
* @dev Emitted when `indexer` close an allocation in `epoch` for `allocationID`.
* An amount of `tokens` get unallocated from `subgraphDeploymentID`.
* This event also emits the POI (proof of indexing) submitted by the indexer.
* `isPublic` is true if the sender was someone other than the indexer.
*/
event AllocationClosed(
address indexed indexer,
bytes32 indexed subgraphDeploymentID,
uint256 epoch,
uint256 tokens,
address indexed allocationID,
address sender,
bytes32 poi,
bool isPublic
);
/**
* @dev Emitted when `indexer` collects a rebate on `subgraphDeploymentID` for `allocationID`.
* `epoch` is the protocol epoch the rebate was collected on
* The rebate is for `tokens` amount which are being provided by `assetHolder`; `queryFees`
* is the amount up for rebate after `curationFees` are distributed and `protocolTax` is burnt.
* `queryRebates` is the amount distributed to the `indexer` with `delegationFees` collected
* and sent to the delegation pool.
*/
event RebateCollected(
address assetHolder,
address indexed indexer,
bytes32 indexed subgraphDeploymentID,
address indexed allocationID,
uint256 epoch,
uint256 tokens,
uint256 protocolTax,
uint256 curationFees,
uint256 queryFees,
uint256 queryRebates,
uint256 delegationRewards
);
/**
* @dev Emitted when `indexer` update the delegation parameters for its delegation pool.
*/
event DelegationParametersUpdated(
address indexed indexer,
uint32 indexingRewardCut,
uint32 queryFeeCut,
uint32 cooldownBlocks
);
/**
* @dev Emitted when `caller` set `assetHolder` address as `allowed` to send funds
* to staking contract.
*/
event AssetHolderUpdate(address indexed caller, address indexed assetHolder, bool allowed);
/**
* @dev Emitted when `indexer` set `operator` access.
*/
event SetOperator(address indexed indexer, address indexed operator, bool allowed);
/**
* @dev Emitted when `indexer` set an address to receive rewards.
*/
event SetRewardsDestination(address indexed indexer, address indexed destination);
/**
* @dev Emitted when `extensionImpl` was set as the address of the StakingExtension contract
* to which extended functionality is delegated.
*/
event ExtensionImplementationSet(address indexed extensionImpl);
/**
* @dev Possible states an allocation can be.
* States:
* - Null = indexer == address(0)
* - Active = not Null && tokens > 0
* - Closed = Active && closedAtEpoch != 0
*/
enum AllocationState {
Null,
Active,
Closed
}
/**
* @notice Initialize this contract.
* @param _controller Address of the controller that manages this contract
* @param _minimumIndexerStake Minimum amount of tokens that an indexer must stake
* @param _thawingPeriod Number of blocks that tokens get locked after unstaking
* @param _protocolPercentage Percentage of query fees that are burned as protocol fee (in PPM)
* @param _curationPercentage Percentage of query fees that are given to curators (in PPM)
* @param _maxAllocationEpochs The maximum number of epochs that an allocation can be active
* @param _delegationUnbondingPeriod The period in epochs that tokens get locked after undelegating
* @param _delegationRatio The ratio between an indexer's own stake and the delegation they can use
* @param _rebatesParameters Alpha and lambda parameters for rebates function
* @param _extensionImpl Address of the StakingExtension implementation
*/
function initialize(
address _controller,
uint256 _minimumIndexerStake,
uint32 _thawingPeriod,
uint32 _protocolPercentage,
uint32 _curationPercentage,
uint32 _maxAllocationEpochs,
uint32 _delegationUnbondingPeriod,
uint32 _delegationRatio,
RebatesParameters calldata _rebatesParameters,
address _extensionImpl
) external;
/**
* @notice Set the address of the StakingExtension implementation.
* @dev This function can only be called by the governor.
* @param _extensionImpl Address of the StakingExtension implementation
*/
function setExtensionImpl(address _extensionImpl) external;
/**
* @notice Set the address of the counterpart (L1 or L2) staking contract.
* @dev This function can only be called by the governor.
* @param _counterpart Address of the counterpart staking contract in the other chain, without any aliasing.
*/
function setCounterpartStakingAddress(address _counterpart) external;
/**
* @notice Set the minimum stake needed to be an Indexer
* @dev This function can only be called by the governor.
* @param _minimumIndexerStake Minimum amount of tokens that an indexer must stake
*/
function setMinimumIndexerStake(uint256 _minimumIndexerStake) external;
/**
* @notice Set the number of blocks that tokens get locked after unstaking
* @dev This function can only be called by the governor.
* @param _thawingPeriod Number of blocks that tokens get locked after unstaking
*/
function setThawingPeriod(uint32 _thawingPeriod) external;
/**
* @notice Set the curation percentage of query fees sent to curators.
* @dev This function can only be called by the governor.
* @param _percentage Percentage of query fees sent to curators
*/
function setCurationPercentage(uint32 _percentage) external;
/**
* @notice Set a protocol percentage to burn when collecting query fees.
* @dev This function can only be called by the governor.
* @param _percentage Percentage of query fees to burn as protocol fee
*/
function setProtocolPercentage(uint32 _percentage) external;
/**
* @notice Set the max time allowed for indexers to allocate on a subgraph
* before others are allowed to close the allocation.
* @dev This function can only be called by the governor.
* @param _maxAllocationEpochs Allocation duration limit in epochs
*/
function setMaxAllocationEpochs(uint32 _maxAllocationEpochs) external;
/**
* @notice Set the rebate parameters
* @dev This function can only be called by the governor.
* @param _alphaNumerator Numerator of `alpha`
* @param _alphaDenominator Denominator of `alpha`
* @param _lambdaNumerator Numerator of `lambda`
* @param _lambdaDenominator Denominator of `lambda`
*/
function setRebateParameters(
uint32 _alphaNumerator,
uint32 _alphaDenominator,
uint32 _lambdaNumerator,
uint32 _lambdaDenominator
) external;
/**
* @notice Set an address as allowed asset holder.
* @dev This function can only be called by the governor.
* @param _assetHolder Address of allowed source for state channel funds
* @param _allowed True if asset holder is allowed
*/
function setAssetHolder(address _assetHolder, bool _allowed) external;
/**
* @notice Authorize or unauthorize an address to be an operator for the caller.
* @param _operator Address to authorize or unauthorize
* @param _allowed Whether the operator is authorized or not
*/
function setOperator(address _operator, bool _allowed) external;
/**
* @notice Deposit tokens on the indexer's stake.
* The amount staked must be over the minimumIndexerStake.
* @param _tokens Amount of tokens to stake
*/
function stake(uint256 _tokens) external;
/**
* @notice Deposit tokens on the Indexer stake, on behalf of the Indexer.
* The amount staked must be over the minimumIndexerStake.
* @param _indexer Address of the indexer
* @param _tokens Amount of tokens to stake
*/
function stakeTo(address _indexer, uint256 _tokens) external;
/**
* @notice Unstake tokens from the indexer stake, lock them until the thawing period expires.
* @dev NOTE: The function accepts an amount greater than the currently staked tokens.
* If that happens, it will try to unstake the max amount of tokens it can.
* The reason for this behaviour is to avoid time conditions while the transaction
* is in flight.
* @param _tokens Amount of tokens to unstake
*/
function unstake(uint256 _tokens) external;
/**
* @notice Withdraw indexer tokens once the thawing period has passed.
*/
function withdraw() external;
/**
* @notice Set the destination where to send rewards for an indexer.
* @param _destination Rewards destination address. If set to zero, rewards will be restaked
*/
function setRewardsDestination(address _destination) external;
/**
* @notice Set the delegation parameters for the caller.
* @param _indexingRewardCut Percentage of indexing rewards left for the indexer
* @param _queryFeeCut Percentage of query fees left for the indexer
* @param _cooldownBlocks Period that need to pass to update delegation parameters
*/
function setDelegationParameters(
uint32 _indexingRewardCut,
uint32 _queryFeeCut,
uint32 _cooldownBlocks
) external;
/**
* @notice Allocate available tokens to a subgraph deployment.
* @param _subgraphDeploymentID ID of the SubgraphDeployment where tokens will be allocated
* @param _tokens Amount of tokens to allocate
* @param _allocationID The allocation identifier
* @param _metadata IPFS hash for additional information about the allocation
* @param _proof A 65-bytes Ethereum signed message of `keccak256(indexerAddress,allocationID)`
*/
function allocate(
bytes32 _subgraphDeploymentID,
uint256 _tokens,
address _allocationID,
bytes32 _metadata,
bytes calldata _proof
) external;
/**
* @notice Allocate available tokens to a subgraph deployment from and indexer's stake.
* The caller must be the indexer or the indexer's operator.
* @param _indexer Indexer address to allocate funds from.
* @param _subgraphDeploymentID ID of the SubgraphDeployment where tokens will be allocated
* @param _tokens Amount of tokens to allocate
* @param _allocationID The allocation identifier
* @param _metadata IPFS hash for additional information about the allocation
* @param _proof A 65-bytes Ethereum signed message of `keccak256(indexerAddress,allocationID)`
*/
function allocateFrom(
address _indexer,
bytes32 _subgraphDeploymentID,
uint256 _tokens,
address _allocationID,
bytes32 _metadata,
bytes calldata _proof
) external;
/**
* @notice Close an allocation and free the staked tokens.
* To be eligible for rewards a proof of indexing must be presented.
* Presenting a bad proof is subject to slashable condition.
* To opt out of rewards set _poi to 0x0
* @param _allocationID The allocation identifier
* @param _poi Proof of indexing submitted for the allocated period
*/
function closeAllocation(address _allocationID, bytes32 _poi) external;
/**
* @notice Collect query fees from state channels and assign them to an allocation.
* Funds received are only accepted from a valid sender.
* @dev To avoid reverting on the withdrawal from channel flow this function will:
* 1) Accept calls with zero tokens.
* 2) Accept calls after an allocation passed the dispute period, in that case, all
* the received tokens are burned.
* @param _tokens Amount of tokens to collect
* @param _allocationID Allocation where the tokens will be assigned
*/
function collect(uint256 _tokens, address _allocationID) external;
/**
* @notice Return true if operator is allowed for indexer.
* @param _operator Address of the operator
* @param _indexer Address of the indexer
* @return True if operator is allowed for indexer, false otherwise
*/
function isOperator(address _operator, address _indexer) external view returns (bool);
/**
* @notice Getter that returns if an indexer has any stake.
* @param _indexer Address of the indexer
* @return True if indexer has staked tokens
*/
function hasStake(address _indexer) external view returns (bool);
/**
* @notice Get the total amount of tokens staked by the indexer.
* @param _indexer Address of the indexer
* @return Amount of tokens staked by the indexer
*/
function getIndexerStakedTokens(address _indexer) external view returns (uint256);
/**
* @notice Get the total amount of tokens available to use in allocations.
* This considers the indexer stake and delegated tokens according to delegation ratio
* @param _indexer Address of the indexer
* @return Amount of tokens available to allocate including delegation
*/
function getIndexerCapacity(address _indexer) external view returns (uint256);
/**
* @notice Return the allocation by ID.
* @param _allocationID Address used as allocation identifier
* @return Allocation data
*/
function getAllocation(address _allocationID) external view returns (Allocation memory);
/**
* @notice Return the current state of an allocation
* @param _allocationID Allocation identifier
* @return AllocationState enum with the state of the allocation
*/
function getAllocationState(address _allocationID) external view returns (AllocationState);
/**
* @notice Return if allocationID is used.
* @param _allocationID Address used as signer by the indexer for an allocation
* @return True if allocationID already used
*/
function isAllocation(address _allocationID) external view returns (bool);
/**
* @notice Return the total amount of tokens allocated to subgraph.
* @param _subgraphDeploymentID Deployment ID for the subgraph
* @return Total tokens allocated to subgraph
*/
function getSubgraphAllocatedTokens(bytes32 _subgraphDeploymentID)
external
view
returns (uint256);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.12 <0.8.0;
pragma abicoder v2;
import { IStakingData } from "./IStakingData.sol";
import { Stakes } from "./libs/Stakes.sol";
/**
* @title Interface for the StakingExtension contract
* @dev This interface defines the events and functions implemented
* in the StakingExtension contract, which is used to extend the functionality
* of the Staking contract while keeping it within the 24kB mainnet size limit.
* In particular, this interface includes delegation functions and various storage
* getters.
*/
interface IStakingExtension is IStakingData {
/**
* @dev DelegationPool struct as returned by delegationPools(), since
* the original DelegationPool in IStakingData.sol contains a nested mapping.
*/
struct DelegationPoolReturn {
uint32 cooldownBlocks; // Blocks to wait before updating parameters
uint32 indexingRewardCut; // in PPM
uint32 queryFeeCut; // in PPM
uint256 updatedAtBlock; // Block when the pool was last updated
uint256 tokens; // Total tokens as pool reserves
uint256 shares; // Total shares minted in the pool
}
/**
* @dev Emitted when `delegator` delegated `tokens` to the `indexer`, the delegator
* gets `shares` for the delegation pool proportionally to the tokens staked.
*/
event StakeDelegated(
address indexed indexer,
address indexed delegator,
uint256 tokens,
uint256 shares
);
/**
* @dev Emitted when `delegator` undelegated `tokens` from `indexer`.
* Tokens get locked for withdrawal after a period of time.
*/
event StakeDelegatedLocked(
address indexed indexer,
address indexed delegator,
uint256 tokens,
uint256 shares,
uint256 until
);
/**
* @dev Emitted when `delegator` withdrew delegated `tokens` from `indexer`.
*/
event StakeDelegatedWithdrawn(
address indexed indexer,
address indexed delegator,
uint256 tokens
);
/**
* @dev Emitted when `indexer` was slashed for a total of `tokens` amount.
* Tracks `reward` amount of tokens given to `beneficiary`.
*/
event StakeSlashed(
address indexed indexer,
uint256 tokens,
uint256 reward,
address beneficiary
);
/**
* @dev Emitted when `caller` set `slasher` address as `allowed` to slash stakes.
*/
event SlasherUpdate(address indexed caller, address indexed slasher, bool allowed);
/**
* @notice Set the delegation ratio.
* If set to 10 it means the indexer can use up to 10x the indexer staked amount
* from their delegated tokens
* @dev This function is only callable by the governor
* @param _delegationRatio Delegation capacity multiplier
*/
function setDelegationRatio(uint32 _delegationRatio) external;
/**
* @notice Set the minimum time in blocks an indexer needs to wait to change delegation parameters.
* Indexers can set a custom amount time for their own cooldown, but it must be greater than this.
* @dev This function is only callable by the governor
* @param _blocks Number of blocks to set the delegation parameters cooldown period
*/
function setDelegationParametersCooldown(uint32 _blocks) external;
/**
* @notice Set the time, in epochs, a Delegator needs to wait to withdraw tokens after undelegating.
* @dev This function is only callable by the governor
* @param _delegationUnbondingPeriod Period in epochs to wait for token withdrawals after undelegating
*/
function setDelegationUnbondingPeriod(uint32 _delegationUnbondingPeriod) external;
/**
* @notice Set a delegation tax percentage to burn when delegated funds are deposited.
* @dev This function is only callable by the governor
* @param _percentage Percentage of delegated tokens to burn as delegation tax, expressed in parts per million
*/
function setDelegationTaxPercentage(uint32 _percentage) external;
/**
* @notice Set or unset an address as allowed slasher.
* @dev This function can only be called by the governor.
* @param _slasher Address of the party allowed to slash indexers
* @param _allowed True if slasher is allowed
*/
function setSlasher(address _slasher, bool _allowed) external;
/**
* @notice Delegate tokens to an indexer.
* @param _indexer Address of the indexer to which tokens are delegated
* @param _tokens Amount of tokens to delegate
* @return Amount of shares issued from the delegation pool
*/
function delegate(address _indexer, uint256 _tokens) external returns (uint256);
/**
* @notice Undelegate tokens from an indexer. Tokens will be locked for the unbonding period.
* @param _indexer Address of the indexer to which tokens had been delegated
* @param _shares Amount of shares to return and undelegate tokens
* @return Amount of tokens returned for the shares of the delegation pool
*/
function undelegate(address _indexer, uint256 _shares) external returns (uint256);
/**
* @notice Withdraw undelegated tokens once the unbonding period has passed, and optionally
* re-delegate to a new indexer.
* @param _indexer Withdraw available tokens delegated to indexer
* @param _newIndexer Re-delegate to indexer address if non-zero, withdraw if zero address
*/
function withdrawDelegated(address _indexer, address _newIndexer) external returns (uint256);
/**
* @notice Slash the indexer stake. Delegated tokens are not subject to slashing.
* @dev Can only be called by the slasher role.
* @param _indexer Address of indexer to slash
* @param _tokens Amount of tokens to slash from the indexer stake
* @param _reward Amount of reward tokens to send to a beneficiary
* @param _beneficiary Address of a beneficiary to receive a reward for the slashing
*/
function slash(
address _indexer,
uint256 _tokens,
uint256 _reward,
address _beneficiary
) external;
/**
* @notice Return the delegation from a delegator to an indexer.
* @param _indexer Address of the indexer where funds have been delegated
* @param _delegator Address of the delegator
* @return Delegation data
*/
function getDelegation(address _indexer, address _delegator)
external
view
returns (Delegation memory);
/**
* @notice Return whether the delegator has delegated to the indexer.
* @param _indexer Address of the indexer where funds have been delegated
* @param _delegator Address of the delegator
* @return True if delegator has tokens delegated to the indexer
*/
function isDelegator(address _indexer, address _delegator) external view returns (bool);
/**
* @notice Returns amount of delegated tokens ready to be withdrawn after unbonding period.
* @param _delegation Delegation of tokens from delegator to indexer
* @return Amount of tokens to withdraw
*/
function getWithdraweableDelegatedTokens(Delegation memory _delegation)
external
view
returns (uint256);
/**
* @notice Getter for the delegationRatio, i.e. the delegation capacity multiplier:
* If delegation ratio is 100, and an Indexer has staked 5 GRT,
* then they can use up to 500 GRT from the delegated stake
* @return Delegation ratio
*/
function delegationRatio() external view returns (uint32);
/**
* @notice Getter for delegationParametersCooldown:
* Minimum time in blocks an indexer needs to wait to change delegation parameters
* @return Delegation parameters cooldown in blocks
*/
function delegationParametersCooldown() external view returns (uint32);
/**
* @notice Getter for delegationUnbondingPeriod:
* Time in epochs a delegator needs to wait to withdraw delegated stake
* @return Delegation unbonding period in epochs
*/
function delegationUnbondingPeriod() external view returns (uint32);
/**
* @notice Getter for delegationTaxPercentage:
* Percentage of tokens to tax a delegation deposit, expressed in parts per million
* @return Delegation tax percentage in parts per million
*/
function delegationTaxPercentage() external view returns (uint32);
/**
* @notice Getter for delegationPools[_indexer]:
* gets the delegation pool structure for a particular indexer.
* @param _indexer Address of the indexer for which to query the delegation pool
* @return Delegation pool as a DelegationPoolReturn struct
*/
function delegationPools(address _indexer) external view returns (DelegationPoolReturn memory);
/**
* @notice Getter for operatorAuth[_indexer][_maybeOperator]:
* returns true if the operator is authorized to operate on behalf of the indexer.
* @param _indexer The indexer address for which to query authorization
* @param _maybeOperator The address that may or may not be an operator
* @return True if the operator is authorized to operate on behalf of the indexer
*/
function operatorAuth(address _indexer, address _maybeOperator) external view returns (bool);
/**
* @notice Getter for rewardsDestination[_indexer]:
* returns the address where the indexer's rewards are sent.
* @param _indexer The indexer address for which to query the rewards destination
* @return The address where the indexer's rewards are sent, zero if none is set in which case rewards are re-staked
*/
function rewardsDestination(address _indexer) external view returns (address);
/**
* @notice Getter for assetHolders[_maybeAssetHolder]:
* returns true if the address is an asset holder, i.e. an entity that can collect
* query fees into the Staking contract.
* @param _maybeAssetHolder The address that may or may not be an asset holder
* @return True if the address is an asset holder
*/
function assetHolders(address _maybeAssetHolder) external view returns (bool);
/**
* @notice Getter for subgraphAllocations[_subgraphDeploymentId]:
* returns the amount of tokens allocated to a subgraph deployment.
* @param _subgraphDeploymentId The subgraph deployment for which to query the allocations
* @return The amount of tokens allocated to the subgraph deployment
*/
function subgraphAllocations(bytes32 _subgraphDeploymentId) external view returns (uint256);
/**
* @notice Getter for slashers[_maybeSlasher]:
* returns true if the address is a slasher, i.e. an entity that can slash indexers
* @param _maybeSlasher Address for which to check the slasher role
* @return True if the address is a slasher
*/
function slashers(address _maybeSlasher) external view returns (bool);
/**
* @notice Getter for minimumIndexerStake: the minimum
* amount of GRT that an indexer needs to stake.
* @return Minimum indexer stake in GRT
*/
function minimumIndexerStake() external view returns (uint256);
/**
* @notice Getter for thawingPeriod: the time in blocks an
* indexer needs to wait to unstake tokens.
* @return Thawing period in blocks
*/
function thawingPeriod() external view returns (uint32);
/**
* @notice Getter for curationPercentage: the percentage of
* query fees that are distributed to curators.
* @return Curation percentage in parts per million
*/
function curationPercentage() external view returns (uint32);
/**
* @notice Getter for protocolPercentage: the percentage of
* query fees that are burned as protocol fees.
* @return Protocol percentage in parts per million
*/
function protocolPercentage() external view returns (uint32);
/**
* @notice Getter for maxAllocationEpochs: the maximum time in epochs
* that an allocation can be open before anyone is allowed to close it. This
* also caps the effective allocation when sending the allocation's query fees
* to the rebate pool.
* @return Maximum allocation period in epochs
*/
function maxAllocationEpochs() external view returns (uint32);
/**
* @notice Getter for the numerator of the rebates alpha parameter
* @return Alpha numerator
*/
function alphaNumerator() external view returns (uint32);
/**
* @notice Getter for the denominator of the rebates alpha parameter
* @return Alpha denominator
*/
function alphaDenominator() external view returns (uint32);
/**
* @notice Getter for the numerator of the rebates lambda parameter
* @return Lambda numerator
*/
function lambdaNumerator() external view returns (uint32);
/**
* @notice Getter for the denominator of the rebates lambda parameter
* @return Lambda denominator
*/
function lambdaDenominator() external view returns (uint32);
/**
* @notice Getter for stakes[_indexer]:
* gets the stake information for an indexer as a Stakes.Indexer struct.
* @param _indexer Indexer address for which to query the stake information
* @return Stake information for the specified indexer, as a Stakes.Indexer struct
*/
function stakes(address _indexer) external view returns (Stakes.Indexer memory);
/**
* @notice Getter for allocations[_allocationID]:
* gets an allocation's information as an IStakingData.Allocation struct.
* @param _allocationID Allocation ID for which to query the allocation information
* @return The specified allocation, as an IStakingData.Allocation struct
*/
function allocations(address _allocationID)
external
view
returns (IStakingData.Allocation memory);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.7.6;
pragma abicoder v2;
/**
* @title Multicall interface
* @notice Enables calling multiple methods in a single call to the contract
*/
interface IMulticall {
/**
* @notice Call multiple functions in the current contract and return the data from all of them if they all succeed
* @param data The encoded function data for each of the calls to make to this contract
* @return results The results from each of the calls passed in via data
*/
function multicall(bytes[] calldata data) external returns (bytes[] memory results);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.7.6;
import { IController } from "./IController.sol";
/**
* @title Managed Interface
* @dev Interface for contracts that can be managed by a controller.
*/
interface IManaged {
/**
* @notice Set the controller that manages this contract
* @dev Only the current controller can set a new controller
* @param _controller Address of the new controller
*/
function setController(address _controller) external;
/**
* @notice Sync protocol contract addresses from the Controller registry
* @dev This function will cache all the contracts using the latest addresses.
* Anyone can call the function whenever a Proxy contract change in the
* controller to ensure the protocol is using the latest version.
*/
function syncAllContracts() external;
/**
* @notice Get the Controller that manages this contract
* @return The Controller as an IController interface
*/
function controller() external view returns (IController);
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.12 <0.8.0;
/**
* @title Staking Data interface
* @dev This interface defines some structures used by the Staking contract.
*/
interface IStakingData {
/**
* @dev Allocate GRT tokens for the purpose of serving queries of a subgraph deployment
* An allocation is created in the allocate() function and closed in closeAllocation()
*/
struct Allocation {
address indexer;
bytes32 subgraphDeploymentID;
uint256 tokens; // Tokens allocated to a SubgraphDeployment
uint256 createdAtEpoch; // Epoch when it was created
uint256 closedAtEpoch; // Epoch when it was closed
uint256 collectedFees; // Collected fees for the allocation
uint256 __DEPRECATED_effectiveAllocation; // Effective allocation when closed
uint256 accRewardsPerAllocatedToken; // Snapshot used for reward calc
uint256 distributedRebates; // Collected rebates that have been rebated
}
// -- Delegation Data --
/**
* @dev Delegation pool information. One per indexer.
*/
struct DelegationPool {
uint32 cooldownBlocks; // Blocks to wait before updating parameters
uint32 indexingRewardCut; // in PPM
uint32 queryFeeCut; // in PPM
uint256 updatedAtBlock; // Block when the pool was last updated
uint256 tokens; // Total tokens as pool reserves
uint256 shares; // Total shares minted in the pool
mapping(address => Delegation) delegators; // Mapping of delegator => Delegation
}
/**
* @dev Individual delegation data of a delegator in a pool.
*/
struct Delegation {
uint256 shares; // Shares owned by a delegator in the pool
uint256 tokensLocked; // Tokens locked for undelegation
uint256 tokensLockedUntil; // Block when locked tokens can be withdrawn
}
/**
* @dev Rebates parameters. Used to avoid stack too deep errors in Staking initialize function.
*/
struct RebatesParameters {
uint32 alphaNumerator;
uint32 alphaDenominator;
uint32 lambdaNumerator;
uint32 lambdaDenominator;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.7.6;
pragma abicoder v2;
import "@openzeppelin/contracts/math/SafeMath.sol";
import "./MathUtils.sol";
/**
* @title A collection of data structures and functions to manage the Indexer Stake state.
* Used for low-level state changes, require() conditions should be evaluated
* at the caller function scope.
*/
library Stakes {
using SafeMath for uint256;
using Stakes for Stakes.Indexer;
struct Indexer {
uint256 tokensStaked; // Tokens on the indexer stake (staked by the indexer)
uint256 tokensAllocated; // Tokens used in allocations
uint256 tokensLocked; // Tokens locked for withdrawal subject to thawing period
uint256 tokensLockedUntil; // Block when locked tokens can be withdrawn
}
/**
* @dev Deposit tokens to the indexer stake.
* @param stake Stake data
* @param _tokens Amount of tokens to deposit
*/
function deposit(Stakes.Indexer storage stake, uint256 _tokens) internal {
stake.tokensStaked = stake.tokensStaked.add(_tokens);
}
/**
* @dev Release tokens from the indexer stake.
* @param stake Stake data
* @param _tokens Amount of tokens to release
*/
function release(Stakes.Indexer storage stake, uint256 _tokens) internal {
stake.tokensStaked = stake.tokensStaked.sub(_tokens);
}
/**
* @dev Allocate tokens from the main stack to a SubgraphDeployment.
* @param stake Stake data
* @param _tokens Amount of tokens to allocate
*/
function allocate(Stakes.Indexer storage stake, uint256 _tokens) internal {
stake.tokensAllocated = stake.tokensAllocated.add(_tokens);
}
/**
* @dev Unallocate tokens from a SubgraphDeployment back to the main stack.
* @param stake Stake data
* @param _tokens Amount of tokens to unallocate
*/
function unallocate(Stakes.Indexer storage stake, uint256 _tokens) internal {
stake.tokensAllocated = stake.tokensAllocated.sub(_tokens);
}
/**
* @dev Lock tokens until a thawing period pass.
* @param stake Stake data
* @param _tokens Amount of tokens to unstake
* @param _period Period in blocks that need to pass before withdrawal
*/
function lockTokens(
Stakes.Indexer storage stake,
uint256 _tokens,
uint256 _period
) internal {
// Take into account period averaging for multiple unstake requests
uint256 lockingPeriod = _period;
if (stake.tokensLocked > 0) {
lockingPeriod = MathUtils.weightedAverage(
MathUtils.diffOrZero(stake.tokensLockedUntil, block.number), // Remaining thawing period
stake.tokensLocked, // Weighted by remaining unstaked tokens
_period, // Thawing period
_tokens // Weighted by new tokens to unstake
);
}
// Update balances
stake.tokensLocked = stake.tokensLocked.add(_tokens);
stake.tokensLockedUntil = block.number.add(lockingPeriod);
}
/**
* @dev Unlock tokens.
* @param stake Stake data
* @param _tokens Amount of tokens to unkock
*/
function unlockTokens(Stakes.Indexer storage stake, uint256 _tokens) internal {
stake.tokensLocked = stake.tokensLocked.sub(_tokens);
if (stake.tokensLocked == 0) {
stake.tokensLockedUntil = 0;
}
}
/**
* @dev Take all tokens out from the locked stake for withdrawal.
* @param stake Stake data
* @return Amount of tokens being withdrawn
*/
function withdrawTokens(Stakes.Indexer storage stake) internal returns (uint256) {
// Calculate tokens that can be released
uint256 tokensToWithdraw = stake.tokensWithdrawable();
if (tokensToWithdraw > 0) {
// Reset locked tokens
stake.unlockTokens(tokensToWithdraw);
// Decrease indexer stake
stake.release(tokensToWithdraw);
}
return tokensToWithdraw;
}
/**
* @dev Return the amount of tokens used in allocations and locked for withdrawal.
* @param stake Stake data
* @return Token amount
*/
function tokensUsed(Stakes.Indexer memory stake) internal pure returns (uint256) {
return stake.tokensAllocated.add(stake.tokensLocked);
}
/**
* @dev Return the amount of tokens staked not considering the ones that are already going
* through the thawing period or are ready for withdrawal. We call it secure stake because
* it is not subject to change by a withdraw call from the indexer.
* @param stake Stake data
* @return Token amount
*/
function tokensSecureStake(Stakes.Indexer memory stake) internal pure returns (uint256) {
return stake.tokensStaked.sub(stake.tokensLocked);
}
/**
* @dev Tokens free balance on the indexer stake that can be used for any purpose.
* Any token that is allocated cannot be used as well as tokens that are going through the
* thawing period or are withdrawable
* Calc: tokensStaked - tokensAllocated - tokensLocked
* @param stake Stake data
* @return Token amount
*/
function tokensAvailable(Stakes.Indexer memory stake) internal pure returns (uint256) {
return stake.tokensAvailableWithDelegation(0);
}
/**
* @dev Tokens free balance on the indexer stake that can be used for allocations.
* This function accepts a parameter for extra delegated capacity that takes into
* account delegated tokens
* @param stake Stake data
* @param _delegatedCapacity Amount of tokens used from delegators to calculate availability
* @return Token amount
*/
function tokensAvailableWithDelegation(Stakes.Indexer memory stake, uint256 _delegatedCapacity)
internal
pure
returns (uint256)
{
uint256 tokensCapacity = stake.tokensStaked.add(_delegatedCapacity);
uint256 _tokensUsed = stake.tokensUsed();
// If more tokens are used than the current capacity, the indexer is overallocated.
// This means the indexer doesn't have available capacity to create new allocations.
// We can reach this state when the indexer has funds allocated and then any
// of these conditions happen:
// - The delegationCapacity ratio is reduced.
// - The indexer stake is slashed.
// - A delegator removes enough stake.
if (_tokensUsed > tokensCapacity) {
// Indexer stake is over allocated: return 0 to avoid stake to be used until
// the overallocation is restored by staking more tokens, unallocating tokens
// or using more delegated funds
return 0;
}
return tokensCapacity.sub(_tokensUsed);
}
/**
* @dev Tokens available for withdrawal after thawing period.
* @param stake Stake data
* @return Token amount
*/
function tokensWithdrawable(Stakes.Indexer memory stake) internal view returns (uint256) {
// No tokens to withdraw before locking period
if (stake.tokensLockedUntil == 0 || block.number < stake.tokensLockedUntil) {
return 0;
}
return stake.tokensLocked;
}
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Wrappers over Solidity's arithmetic operations with added overflow
* checks.
*
* Arithmetic operations in Solidity wrap on overflow. This can easily result
* in bugs, because programmers usually assume that an overflow raises an
* error, which is the standard behavior in high level programming languages.
* `SafeMath` restores this intuition by reverting the transaction when an
* operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
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) {
// 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) {
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) {
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) {
uint256 c = a + b;
require(c >= a, "SafeMath: addition overflow");
return c;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
require(b <= a, "SafeMath: subtraction overflow");
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) {
if (a == 0) return 0;
uint256 c = a * b;
require(c / a == b, "SafeMath: multiplication overflow");
return c;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
require(b > 0, "SafeMath: division by zero");
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) {
require(b > 0, "SafeMath: modulo by zero");
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) {
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.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryDiv}.
*
* 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) {
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) {
require(b > 0, errorMessage);
return a % b;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity ^0.7.6;
import "@openzeppelin/contracts/math/SafeMath.sol";
/**
* @title MathUtils Library
* @notice A collection of functions to perform math operations
*/
library MathUtils {
using SafeMath for uint256;
/**
* @dev Calculates the weighted average of two values pondering each of these
* values based on configured weights. The contribution of each value N is
* weightN/(weightA + weightB).
* @param valueA The amount for value A
* @param weightA The weight to use for value A
* @param valueB The amount for value B
* @param weightB The weight to use for value B
*/
function weightedAverage(
uint256 valueA,
uint256 weightA,
uint256 valueB,
uint256 weightB
) internal pure returns (uint256) {
return valueA.mul(weightA).add(valueB.mul(weightB)).div(weightA.add(weightB));
}
/**
* @dev Returns the minimum of two numbers.
*/
function min(uint256 x, uint256 y) internal pure returns (uint256) {
return x <= y ? x : y;
}
/**
* @dev Returns the difference between two numbers or zero if negative.
*/
function diffOrZero(uint256 x, uint256 y) internal pure returns (uint256) {
return (x > y) ? x.sub(y) : 0;
}
}// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.6.12 <0.8.0;
interface IController {
function getGovernor() external view returns (address);
// -- Registry --
function setContractProxy(bytes32 _id, address _contractAddress) external;
function unsetContractProxy(bytes32 _id) external;
function updateController(bytes32 _id, address _controller) external;
function getContractProxy(bytes32 _id) external view returns (address);
// -- Pausing --
function setPartialPaused(bool _partialPaused) external;
function setPaused(bool _paused) external;
function setPauseGuardian(address _newPauseGuardian) external;
function paused() external view returns (bool);
function partialPaused() external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* 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 `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract ABI
API[{"inputs":[{"internalType":"contract IGraphToken","name":"_graphToken","type":"address"},{"internalType":"contract IStaking","name":"_staking","type":"address"},{"internalType":"address","name":"_governor","type":"address"},{"internalType":"address","name":"_authority","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"allocationID","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"AllocationRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"bool","name":"authorized","type":"bool"}],"name":"AuthoritySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"NewOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"NewPendingOwnership","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"TokensWithdrawn","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"allocationsRedeemed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"approveAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authority","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"governor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingGovernor","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"allocationID","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct AllocationExchange.AllocationVoucher","name":"_voucher","type":"tuple"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"allocationID","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct AllocationExchange.AllocationVoucher[]","name":"_vouchers","type":"tuple[]"}],"name":"redeemMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_authority","type":"address"},{"internalType":"bool","name":"_authorized","type":"bool"}],"name":"setAuthority","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newGovernor","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60c06040523480156200001157600080fd5b50604051620013f7380380620013f7833981016040819052620000349162000196565b6001600160a01b038216620000665760405162461bcd60e51b81526004016200005d906200023f565b60405180910390fd5b6200007c82620000ad60201b620006d51760201c565b6001600160601b0319606085811b821660a05284901b16608052620000a3816001620000cf565b50505050620002c6565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b6001600160a01b038216620000f85760405162461bcd60e51b81526004016200005d9062000276565b6200010e826200019060201b620006f71760201c565b156200012e5760405162461bcd60e51b81526004016200005d9062000208565b6001600160a01b03821660008181526002602052604090819020805460ff1916841515179055517f58ff942169d73f3abad652db95845088969180d650967f57f035bf5c5c9319de9062000184908490620001fd565b60405180910390a25050565b3b151590565b60008060008060808587031215620001ac578384fd5b8451620001b981620002ad565b6020860151909450620001cc81620002ad565b6040860151909350620001df81620002ad565b6060860151909250620001f281620002ad565b939692955090935050565b901515815260200190565b6020808252601f908201527f45786368616e67653a20617574686f72697479206d75737420626520454f4100604082015260600190565b6020808252601e908201527f45786368616e67653a20676f7665726e6f72206d757374206265207365740000604082015260600190565b60208082526019908201527f45786368616e67653a20656d70747920617574686f7269747900000000000000604082015260600190565b6001600160a01b0381168114620002c357600080fd5b50565b60805160601c60a05160601c6110fd620002fa600039806101b352806105eb5250806101e052806108e152506110fd6000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063b5f0d35c11610071578063b5f0d35c14610111578063cd2b1af814610124578063dfc224b414610137578063e3056a341461014a578063f2fde38b14610152578063f3fef3a314610165576100a9565b80630c340a24146100ae578063185f182d146100cc578063380d0c08146100ec5780637104dd03146100f657806379ba509714610109575b600080fd5b6100b6610178565b6040516100c39190610e03565b60405180910390f35b6100df6100da366004610c71565b610187565b6040516100c39190610e30565b6100f461019c565b005b6100df610104366004610c71565b610261565b6100f4610276565b6100f461011f366004610c92565b610384565b6100f4610132366004610cf1565b6103ea565b6100f4610145366004610da6565b61041a565b6100b6610423565b6100f4610160366004610c71565b610432565b6100f4610173366004610cc8565b610530565b6000546001600160a01b031681565b60036020526000908152604090205460ff1681565b60405163095ea7b360e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b39061020c907f00000000000000000000000000000000000000000000000000000000000000009060001990600401610e17565b602060405180830381600087803b15801561022657600080fd5b505af115801561023a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025e9190610d8a565b50565b60026020526000908152604090205460ff1681565b6001546001600160a01b031680158015906102995750336001600160a01b038216145b6102ea576040805162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206d7573742062652070656e64696e6720676f7665726e6f7200604482015290519081900360640190fd5b600080546001600160a01b038381166001600160a01b031980841691909117808555600180549092169091556040519282169391169183917f0ac6deed30eef60090c749850e10f2fa469e3e25fec1d1bef2853003f6e6f18f91a36001546040516001600160a01b03918216918416907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b6000546001600160a01b031633146103dc576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6103e68282610701565b5050565b60005b81518110156103e65761041282828151811061040557fe5b60200260200101516107a1565b6001016103ed565b61025e816107a1565b6001546001600160a01b031681565b6000546001600160a01b0316331461048a576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6001600160a01b0381166104dc576040805162461bcd60e51b815260206004820152601460248201527311dbdd995c9b9bdc881b5d5cdd081899481cd95d60621b604482015290519081900360640190fd5b600180546001600160a01b038381166001600160a01b03198316179283905560405191811692169082907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b6000546001600160a01b03163314610588576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6001600160a01b0382166105b75760405162461bcd60e51b81526004016105ae90610e3b565b60405180910390fd5b806105d45760405162461bcd60e51b81526004016105ae90611001565b60405163a9059cbb60e01b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906106229085908590600401610e17565b602060405180830381600087803b15801561063c57600080fd5b505af1158015610650573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106749190610d8a565b6106905760405162461bcd60e51b81526004016105ae90610eee565b816001600160a01b03167f6352c5382c4a4578e712449ca65e83cdb392d045dfcf1cad9615189db2da244b826040516106c99190611031565b60405180910390a25050565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b803b15155b919050565b6001600160a01b0382166107275760405162461bcd60e51b81526004016105ae90610fca565b610730826106f7565b1561074d5760405162461bcd60e51b81526004016105ae90610e72565b6001600160a01b03821660008181526002602052604090819020805460ff1916841515179055517f58ff942169d73f3abad652db95845088969180d650967f57f035bf5c5c9319de906106c9908490610e30565b60008160200151116107c55760405162461bcd60e51b81526004016105ae90610f25565b6041816040015151146107ea5760405162461bcd60e51b81526004016105ae90610f93565b80516001600160a01b031660009081526003602052604090205460ff16156108245760405162461bcd60e51b81526004016105ae90610ea9565b600081600001518260200151604051602001610841929190610de1565b6040516020818303038152906040528051906020012090506000610869828460400151610997565b6001600160a01b03811660009081526002602052604090205490915060ff166108a45760405162461bcd60e51b81526004016105ae90610f5c565b82516001600160a01b03908116600090815260036020908152604091829020805460ff191660011790558501518551915163469e080560e11b81527f000000000000000000000000000000000000000000000000000000000000000090931692638d3c100a92610917929160040161103a565b600060405180830381600087803b15801561093157600080fd5b505af1158015610945573d6000803e3d6000fd5b5050505082600001516001600160a01b03167fe86f6a4e34293c4b00e73d2a8b6237e4ab10bb4849b1495a1a8b45d3a59d8118846020015160405161098a9190611031565b60405180910390a2505050565b600081516041146109ef576040805162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015290519081900360640190fd5b60208201516040830151606084015160001a610a0d86828585610a17565b9695505050505050565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115610a785760405162461bcd60e51b81526004018080602001828103825260228152602001806110846022913960400191505060405180910390fd5b8360ff16601b1480610a8d57508360ff16601c145b610ac85760405162461bcd60e51b81526004018080602001828103825260228152602001806110a66022913960400191505060405180910390fd5b600060018686868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610b24573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610b8c576040805162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015290519081900360640190fd5b95945050505050565b80356001600160a01b03811681146106fc57600080fd5b600060608284031215610bbd578081fd5b6040516060810167ffffffffffffffff8282108183111715610bdb57fe5b81604052829350610beb85610b95565b8352602091508185013582840152604085013581811115610c0b57600080fd5b8501601f81018713610c1c57600080fd5b803582811115610c2857fe5b610c3a601f8201601f19168501611051565b92508083528784828401011115610c5057600080fd5b80848301858501376000848285010152505080604084015250505092915050565b600060208284031215610c82578081fd5b610c8b82610b95565b9392505050565b60008060408385031215610ca4578081fd5b610cad83610b95565b91506020830135610cbd81611075565b809150509250929050565b60008060408385031215610cda578182fd5b610ce383610b95565b946020939093013593505050565b60006020808385031215610d03578182fd5b823567ffffffffffffffff80821115610d1a578384fd5b818501915085601f830112610d2d578384fd5b813581811115610d3957fe5b610d468485830201611051565b8181528481019250838501865b83811015610d7c57610d6a8a888435890101610bac565b85529386019390860190600101610d53565b509098975050505050505050565b600060208284031215610d9b578081fd5b8151610c8b81611075565b600060208284031215610db7578081fd5b813567ffffffffffffffff811115610dcd578182fd5b610dd984828501610bac565b949350505050565b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b6020808252601b908201527f45786368616e67653a20656d7074792064657374696e6174696f6e0000000000604082015260600190565b6020808252601f908201527f45786368616e67653a20617574686f72697479206d75737420626520454f4100604082015260600190565b60208082526025908201527f45786368616e67653a20616c6c6f636174696f6e20616c72656164792072656460408201526419595b595960da1b606082015260800190565b60208082526019908201527f45786368616e67653a2063616e6e6f74207472616e7366657200000000000000604082015260600190565b6020808252601d908201527f45786368616e67653a207a65726f20746f6b656e7320766f7563686572000000604082015260600190565b60208082526018908201527f45786368616e67653a20696e76616c6964207369676e65720000000000000000604082015260600190565b6020808252601b908201527f45786368616e67653a20696e76616c6964207369676e61747572650000000000604082015260600190565b60208082526019908201527f45786368616e67653a20656d70747920617574686f7269747900000000000000604082015260600190565b602080825260169082015275115e18da185b99d94e88195b5c1d1e48185b5bdd5b9d60521b604082015260600190565b90815260200190565b9182526001600160a01b0316602082015260400190565b60405181810167ffffffffffffffff8111828210171561106d57fe5b604052919050565b801515811461025e57600080fdfe45434453413a20696e76616c6964207369676e6174757265202773272076616c756545434453413a20696e76616c6964207369676e6174757265202776272076616c7565a2646970667358221220adf687941e58cd874b16a79113cd35119bfa5d3dc4066fb158b6a13b750a307e64736f6c63430007060033000000000000000000000000ca59cceb39be1808d7aa607153f4a5062daf3a8300000000000000000000000014e9b07dc56a0b03ac8a58453b5cccb289d6ec900000000000000000000000004ebf30832ec2db76ae228d5d239083b59f530d1f000000000000000000000000840daec5df962d49cf2efd789c4e40a7b7e0117d
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100a95760003560e01c8063b5f0d35c11610071578063b5f0d35c14610111578063cd2b1af814610124578063dfc224b414610137578063e3056a341461014a578063f2fde38b14610152578063f3fef3a314610165576100a9565b80630c340a24146100ae578063185f182d146100cc578063380d0c08146100ec5780637104dd03146100f657806379ba509714610109575b600080fd5b6100b6610178565b6040516100c39190610e03565b60405180910390f35b6100df6100da366004610c71565b610187565b6040516100c39190610e30565b6100f461019c565b005b6100df610104366004610c71565b610261565b6100f4610276565b6100f461011f366004610c92565b610384565b6100f4610132366004610cf1565b6103ea565b6100f4610145366004610da6565b61041a565b6100b6610423565b6100f4610160366004610c71565b610432565b6100f4610173366004610cc8565b610530565b6000546001600160a01b031681565b60036020526000908152604090205460ff1681565b60405163095ea7b360e01b81526001600160a01b037f000000000000000000000000ca59cceb39be1808d7aa607153f4a5062daf3a83169063095ea7b39061020c907f00000000000000000000000014e9b07dc56a0b03ac8a58453b5cccb289d6ec909060001990600401610e17565b602060405180830381600087803b15801561022657600080fd5b505af115801561023a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061025e9190610d8a565b50565b60026020526000908152604090205460ff1681565b6001546001600160a01b031680158015906102995750336001600160a01b038216145b6102ea576040805162461bcd60e51b815260206004820152601f60248201527f43616c6c6572206d7573742062652070656e64696e6720676f7665726e6f7200604482015290519081900360640190fd5b600080546001600160a01b038381166001600160a01b031980841691909117808555600180549092169091556040519282169391169183917f0ac6deed30eef60090c749850e10f2fa469e3e25fec1d1bef2853003f6e6f18f91a36001546040516001600160a01b03918216918416907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b6000546001600160a01b031633146103dc576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6103e68282610701565b5050565b60005b81518110156103e65761041282828151811061040557fe5b60200260200101516107a1565b6001016103ed565b61025e816107a1565b6001546001600160a01b031681565b6000546001600160a01b0316331461048a576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6001600160a01b0381166104dc576040805162461bcd60e51b815260206004820152601460248201527311dbdd995c9b9bdc881b5d5cdd081899481cd95d60621b604482015290519081900360640190fd5b600180546001600160a01b038381166001600160a01b03198316179283905560405191811692169082907f76563ad561b7036ae716b9b25cb521b21463240f104c97e12f25877f2235f33d90600090a35050565b6000546001600160a01b03163314610588576040805162461bcd60e51b815260206004820152601660248201527513db9b1e4811dbdd995c9b9bdc8818d85b8818d85b1b60521b604482015290519081900360640190fd5b6001600160a01b0382166105b75760405162461bcd60e51b81526004016105ae90610e3b565b60405180910390fd5b806105d45760405162461bcd60e51b81526004016105ae90611001565b60405163a9059cbb60e01b81526001600160a01b037f000000000000000000000000ca59cceb39be1808d7aa607153f4a5062daf3a83169063a9059cbb906106229085908590600401610e17565b602060405180830381600087803b15801561063c57600080fd5b505af1158015610650573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106749190610d8a565b6106905760405162461bcd60e51b81526004016105ae90610eee565b816001600160a01b03167f6352c5382c4a4578e712449ca65e83cdb392d045dfcf1cad9615189db2da244b826040516106c99190611031565b60405180910390a25050565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b803b15155b919050565b6001600160a01b0382166107275760405162461bcd60e51b81526004016105ae90610fca565b610730826106f7565b1561074d5760405162461bcd60e51b81526004016105ae90610e72565b6001600160a01b03821660008181526002602052604090819020805460ff1916841515179055517f58ff942169d73f3abad652db95845088969180d650967f57f035bf5c5c9319de906106c9908490610e30565b60008160200151116107c55760405162461bcd60e51b81526004016105ae90610f25565b6041816040015151146107ea5760405162461bcd60e51b81526004016105ae90610f93565b80516001600160a01b031660009081526003602052604090205460ff16156108245760405162461bcd60e51b81526004016105ae90610ea9565b600081600001518260200151604051602001610841929190610de1565b6040516020818303038152906040528051906020012090506000610869828460400151610997565b6001600160a01b03811660009081526002602052604090205490915060ff166108a45760405162461bcd60e51b81526004016105ae90610f5c565b82516001600160a01b03908116600090815260036020908152604091829020805460ff191660011790558501518551915163469e080560e11b81527f00000000000000000000000014e9b07dc56a0b03ac8a58453b5cccb289d6ec9090931692638d3c100a92610917929160040161103a565b600060405180830381600087803b15801561093157600080fd5b505af1158015610945573d6000803e3d6000fd5b5050505082600001516001600160a01b03167fe86f6a4e34293c4b00e73d2a8b6237e4ab10bb4849b1495a1a8b45d3a59d8118846020015160405161098a9190611031565b60405180910390a2505050565b600081516041146109ef576040805162461bcd60e51b815260206004820152601f60248201527f45434453413a20696e76616c6964207369676e6174757265206c656e67746800604482015290519081900360640190fd5b60208201516040830151606084015160001a610a0d86828585610a17565b9695505050505050565b60007f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0821115610a785760405162461bcd60e51b81526004018080602001828103825260228152602001806110846022913960400191505060405180910390fd5b8360ff16601b1480610a8d57508360ff16601c145b610ac85760405162461bcd60e51b81526004018080602001828103825260228152602001806110a66022913960400191505060405180910390fd5b600060018686868660405160008152602001604052604051808581526020018460ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015610b24573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116610b8c576040805162461bcd60e51b815260206004820152601860248201527f45434453413a20696e76616c6964207369676e61747572650000000000000000604482015290519081900360640190fd5b95945050505050565b80356001600160a01b03811681146106fc57600080fd5b600060608284031215610bbd578081fd5b6040516060810167ffffffffffffffff8282108183111715610bdb57fe5b81604052829350610beb85610b95565b8352602091508185013582840152604085013581811115610c0b57600080fd5b8501601f81018713610c1c57600080fd5b803582811115610c2857fe5b610c3a601f8201601f19168501611051565b92508083528784828401011115610c5057600080fd5b80848301858501376000848285010152505080604084015250505092915050565b600060208284031215610c82578081fd5b610c8b82610b95565b9392505050565b60008060408385031215610ca4578081fd5b610cad83610b95565b91506020830135610cbd81611075565b809150509250929050565b60008060408385031215610cda578182fd5b610ce383610b95565b946020939093013593505050565b60006020808385031215610d03578182fd5b823567ffffffffffffffff80821115610d1a578384fd5b818501915085601f830112610d2d578384fd5b813581811115610d3957fe5b610d468485830201611051565b8181528481019250838501865b83811015610d7c57610d6a8a888435890101610bac565b85529386019390860190600101610d53565b509098975050505050505050565b600060208284031215610d9b578081fd5b8151610c8b81611075565b600060208284031215610db7578081fd5b813567ffffffffffffffff811115610dcd578182fd5b610dd984828501610bac565b949350505050565b60609290921b6bffffffffffffffffffffffff19168252601482015260340190565b6001600160a01b0391909116815260200190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b6020808252601b908201527f45786368616e67653a20656d7074792064657374696e6174696f6e0000000000604082015260600190565b6020808252601f908201527f45786368616e67653a20617574686f72697479206d75737420626520454f4100604082015260600190565b60208082526025908201527f45786368616e67653a20616c6c6f636174696f6e20616c72656164792072656460408201526419595b595960da1b606082015260800190565b60208082526019908201527f45786368616e67653a2063616e6e6f74207472616e7366657200000000000000604082015260600190565b6020808252601d908201527f45786368616e67653a207a65726f20746f6b656e7320766f7563686572000000604082015260600190565b60208082526018908201527f45786368616e67653a20696e76616c6964207369676e65720000000000000000604082015260600190565b6020808252601b908201527f45786368616e67653a20696e76616c6964207369676e61747572650000000000604082015260600190565b60208082526019908201527f45786368616e67653a20656d70747920617574686f7269747900000000000000604082015260600190565b602080825260169082015275115e18da185b99d94e88195b5c1d1e48185b5bdd5b9d60521b604082015260600190565b90815260200190565b9182526001600160a01b0316602082015260400190565b60405181810167ffffffffffffffff8111828210171561106d57fe5b604052919050565b801515811461025e57600080fdfe45434453413a20696e76616c6964207369676e6174757265202773272076616c756545434453413a20696e76616c6964207369676e6174757265202776272076616c7565a2646970667358221220adf687941e58cd874b16a79113cd35119bfa5d3dc4066fb158b6a13b750a307e64736f6c63430007060033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000ca59cceb39be1808d7aa607153f4a5062daf3a8300000000000000000000000014e9b07dc56a0b03ac8a58453b5cccb289d6ec900000000000000000000000004ebf30832ec2db76ae228d5d239083b59f530d1f000000000000000000000000840daec5df962d49cf2efd789c4e40a7b7e0117d
-----Decoded View---------------
Arg [0] : _graphToken (address): 0xCA59cCeb39bE1808d7aA607153f4A5062daF3a83
Arg [1] : _staking (address): 0x14e9B07Dc56A0B03ac8A58453B5cCCB289d6ec90
Arg [2] : _governor (address): 0x4EBf30832eC2db76aE228D5d239083B59f530d1f
Arg [3] : _authority (address): 0x840daec5dF962D49cf2EFd789c4E40A7b7e0117D
-----Encoded View---------------
4 Constructor Arguments found :
Arg [0] : 000000000000000000000000ca59cceb39be1808d7aa607153f4a5062daf3a83
Arg [1] : 00000000000000000000000014e9b07dc56a0b03ac8a58453b5cccb289d6ec90
Arg [2] : 0000000000000000000000004ebf30832ec2db76ae228d5d239083b59f530d1f
Arg [3] : 000000000000000000000000840daec5df962d49cf2efd789c4e40a7b7e0117d
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.