Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00
Cross-Chain Transactions
Loading...
Loading
Contract Name:
GhoBucketSteward
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
import {IGhoToken} from '../gho/interfaces/IGhoToken.sol';
import {RiskCouncilControlled} from './RiskCouncilControlled.sol';
import {IGhoBucketSteward} from './interfaces/IGhoBucketSteward.sol';
/**
* @title GhoBucketSteward
* @author Aave Labs
* @notice Helper contract for managing bucket capacities of controlled facilitators
* @dev Only the Risk Council is able to action contract's functions, based on specific conditions that have been agreed upon with the community.
* @dev Requires role GHO_TOKEN_BUCKET_MANAGER_ROLE on GhoToken
*/
contract GhoBucketSteward is Ownable, RiskCouncilControlled, IGhoBucketSteward {
using EnumerableSet for EnumerableSet.AddressSet;
/// @inheritdoc IGhoBucketSteward
uint256 public constant MINIMUM_DELAY = 1 days;
/// @inheritdoc IGhoBucketSteward
address public immutable GHO_TOKEN;
mapping(address => uint40) internal _facilitatorsBucketCapacityTimelocks;
mapping(address => bool) internal _controlledFacilitatorsByAddress;
EnumerableSet.AddressSet internal _controlledFacilitators;
/**
* @dev Only methods that are not timelocked can be called if marked by this modifier.
*/
modifier notTimelocked(uint40 timelock) {
require(block.timestamp - timelock > MINIMUM_DELAY, 'DEBOUNCE_NOT_RESPECTED');
_;
}
/**
* @dev Constructor
* @param owner The address of the contract's owner
* @param ghoToken The address of the GhoToken
* @param riskCouncil The address of the risk council
*/
constructor(
address owner,
address ghoToken,
address riskCouncil
) RiskCouncilControlled(riskCouncil) {
require(owner != address(0), 'INVALID_OWNER');
require(ghoToken != address(0), 'INVALID_GHO_TOKEN');
GHO_TOKEN = ghoToken;
_transferOwnership(owner);
}
/// @inheritdoc IGhoBucketSteward
function updateFacilitatorBucketCapacity(
address facilitator,
uint128 newBucketCapacity
) external onlyRiskCouncil notTimelocked(_facilitatorsBucketCapacityTimelocks[facilitator]) {
require(_controlledFacilitatorsByAddress[facilitator], 'FACILITATOR_NOT_CONTROLLED');
(uint256 currentBucketCapacity, ) = IGhoToken(GHO_TOKEN).getFacilitatorBucket(facilitator);
require(newBucketCapacity != currentBucketCapacity, 'NO_CHANGE_IN_BUCKET_CAPACITY');
require(
_isIncreaseLowerThanMax(currentBucketCapacity, newBucketCapacity, currentBucketCapacity),
'INVALID_BUCKET_CAPACITY_UPDATE'
);
_facilitatorsBucketCapacityTimelocks[facilitator] = uint40(block.timestamp);
IGhoToken(GHO_TOKEN).setFacilitatorBucketCapacity(facilitator, newBucketCapacity);
}
/// @inheritdoc IGhoBucketSteward
function setControlledFacilitator(
address[] memory facilitatorList,
bool approve
) external onlyOwner {
for (uint256 i = 0; i < facilitatorList.length; i++) {
_controlledFacilitatorsByAddress[facilitatorList[i]] = approve;
if (approve) {
_controlledFacilitators.add(facilitatorList[i]);
} else {
_controlledFacilitators.remove(facilitatorList[i]);
}
}
}
/// @inheritdoc IGhoBucketSteward
function getControlledFacilitators() external view returns (address[] memory) {
return _controlledFacilitators.values();
}
/// @inheritdoc IGhoBucketSteward
function isControlledFacilitator(address facilitator) external view returns (bool) {
return _controlledFacilitatorsByAddress[facilitator];
}
/// @inheritdoc IGhoBucketSteward
function getFacilitatorBucketCapacityTimelock(
address facilitator
) external view returns (uint40) {
return _facilitatorsBucketCapacityTimelocks[facilitator];
}
/// @inheritdoc IGhoBucketSteward
function RISK_COUNCIL() public view override returns (address) {
return _riskCouncil;
}
/**
* @dev Ensures that the change is positive and the difference is lower than max.
* @param from current value
* @param to new value
* @param max maximum difference between from and to
* @return bool true if difference between values is positive and lower than max, false otherwise
*/
function _isIncreaseLowerThanMax(
uint256 from,
uint256 to,
uint256 max
) internal pure returns (bool) {
return to >= from && to - from <= max;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {IAccessControl} from '@openzeppelin/contracts/access/IAccessControl.sol';
/**
* @title IGhoToken
* @author Aave
*/
interface IGhoToken is IERC20, IAccessControl {
struct Facilitator {
uint128 bucketCapacity;
uint128 bucketLevel;
string label;
}
/**
* @dev Emitted when a new facilitator is added
* @param facilitatorAddress The address of the new facilitator
* @param label A hashed human readable identifier for the facilitator
* @param bucketCapacity The initial capacity of the facilitator's bucket
*/
event FacilitatorAdded(
address indexed facilitatorAddress,
bytes32 indexed label,
uint256 bucketCapacity
);
/**
* @dev Emitted when a facilitator is removed
* @param facilitatorAddress The address of the removed facilitator
*/
event FacilitatorRemoved(address indexed facilitatorAddress);
/**
* @dev Emitted when the bucket capacity of a facilitator is updated
* @param facilitatorAddress The address of the facilitator whose bucket capacity is being changed
* @param oldCapacity The old capacity of the bucket
* @param newCapacity The new capacity of the bucket
*/
event FacilitatorBucketCapacityUpdated(
address indexed facilitatorAddress,
uint256 oldCapacity,
uint256 newCapacity
);
/**
* @dev Emitted when the bucket level changed
* @param facilitatorAddress The address of the facilitator whose bucket level is being changed
* @param oldLevel The old level of the bucket
* @param newLevel The new level of the bucket
*/
event FacilitatorBucketLevelUpdated(
address indexed facilitatorAddress,
uint256 oldLevel,
uint256 newLevel
);
/**
* @notice Returns the identifier of the Facilitator Manager Role
* @return The bytes32 id hash of the FacilitatorManager role
*/
function FACILITATOR_MANAGER_ROLE() external pure returns (bytes32);
/**
* @notice Returns the identifier of the Bucket Manager Role
* @return The bytes32 id hash of the BucketManager role
*/
function BUCKET_MANAGER_ROLE() external pure returns (bytes32);
/**
* @notice Mints the requested amount of tokens to the account address.
* @dev Only facilitators with enough bucket capacity available can mint.
* @dev The bucket level is increased upon minting.
* @param account The address receiving the GHO tokens
* @param amount The amount to mint
*/
function mint(address account, uint256 amount) external;
/**
* @notice Burns the requested amount of tokens from the account address.
* @dev Only active facilitators (bucket level > 0) can burn.
* @dev The bucket level is decreased upon burning.
* @param amount The amount to burn
*/
function burn(uint256 amount) external;
/**
* @notice Add the facilitator passed with the parameters to the facilitators list.
* @dev Only accounts with `FACILITATOR_MANAGER_ROLE` role can call this function
* @param facilitatorAddress The address of the facilitator to add
* @param facilitatorLabel A human readable identifier for the facilitator
* @param bucketCapacity The upward limit of GHO can be minted by the facilitator
*/
function addFacilitator(
address facilitatorAddress,
string calldata facilitatorLabel,
uint128 bucketCapacity
) external;
/**
* @notice Remove the facilitator from the facilitators list.
* @dev Only accounts with `FACILITATOR_MANAGER_ROLE` role can call this function
* @param facilitatorAddress The address of the facilitator to remove
*/
function removeFacilitator(address facilitatorAddress) external;
/**
* @notice Set the bucket capacity of the facilitator.
* @dev Only accounts with `BUCKET_MANAGER_ROLE` role can call this function
* @param facilitator The address of the facilitator
* @param newCapacity The new capacity of the bucket
*/
function setFacilitatorBucketCapacity(address facilitator, uint128 newCapacity) external;
/**
* @notice Returns the facilitator data
* @param facilitator The address of the facilitator
* @return The facilitator configuration
*/
function getFacilitator(address facilitator) external view returns (Facilitator memory);
/**
* @notice Returns the bucket configuration of the facilitator
* @param facilitator The address of the facilitator
* @return The capacity of the facilitator's bucket
* @return The level of the facilitator's bucket
*/
function getFacilitatorBucket(address facilitator) external view returns (uint256, uint256);
/**
* @notice Returns the list of the addresses of the active facilitator
* @return The list of the facilitators addresses
*/
function getFacilitatorsList() external view returns (address[] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/**
* @title RiskCouncilControlled
* @author Aave Labs
* @notice Helper contract for controlling access to Steward and other functions restricted to Risk Council
*/
abstract contract RiskCouncilControlled {
address internal immutable _riskCouncil;
/**
* @dev Constructor
* @param riskCouncil The address of the risk council
*/
constructor(address riskCouncil) {
require(riskCouncil != address(0), 'INVALID_RISK_COUNCIL');
_riskCouncil = riskCouncil;
}
/**
* @dev Only Risk Council can call functions marked by this modifier.
*/
modifier onlyRiskCouncil() {
require(_riskCouncil == msg.sender, 'INVALID_CALLER');
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
/**
* @title IGhoBucketSteward
* @author Aave Labs
* @notice Defines the basic interface of the GhoBucketSteward
*/
interface IGhoBucketSteward {
/**
* @notice Updates the bucket capacity of facilitator, only if:
* - respects `MINIMUM_DELAY`, the minimum time delay between updates
* - the update changes up to 100% upwards
* - the facilitator is controlled
* @dev Only callable by Risk Council
* @param facilitator The facilitator address
* @param newBucketCapacity The new facilitator bucket capacity
*/
function updateFacilitatorBucketCapacity(address facilitator, uint128 newBucketCapacity) external;
/**
* @notice Adds/Removes controlled facilitators
* @dev Only callable by owner
* @param facilitatorList A list of facilitators addresses to add to control
* @param approve True to add as controlled facilitators, false to remove
*/
function setControlledFacilitator(address[] memory facilitatorList, bool approve) external;
/**
* @notice Returns the list of controlled facilitators by this steward.
* @return An array of facilitator addresses
*/
function getControlledFacilitators() external view returns (address[] memory);
/**
* @notice Checks if a facilitator is controlled by this steward
* @param facilitator The facilitator address to check
* @return True if the facilitator is controlled by this steward
*/
function isControlledFacilitator(address facilitator) external view returns (bool);
/**
* @notice Returns timestamp of the facilitators last bucket capacity update
* @param facilitator The facilitator address
* @return The unix time of the last bucket capacity (in seconds).
*/
function getFacilitatorBucketCapacityTimelock(address facilitator) external view returns (uint40);
/**
* @notice Returns the minimum delay that must be respected between parameters update.
* @return The minimum delay between parameter updates (in seconds)
*/
function MINIMUM_DELAY() external view returns (uint256);
/**
* @notice Returns the address of the Gho Token
* @return The address of the GhoToken
*/
function GHO_TOKEN() external view returns (address);
/**
* @notice Returns the address of the risk council
* @return The address of the RiskCouncil
*/
function RISK_COUNCIL() external view returns (address);
}// 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: MIT
// OpenZeppelin Contracts (last updated v4.6.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 (access/IAccessControl.sol)
pragma solidity ^0.8.0;
/**
* @dev External interface of AccessControl declared to support ERC165 detection.
*/
interface IAccessControl {
/**
* @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
*
* `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
* {RoleAdminChanged} not being emitted signaling this.
*
* _Available since v3.1._
*/
event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
/**
* @dev Emitted when `account` is granted `role`.
*
* `sender` is the account that originated the contract call, an admin role
* bearer except when using {AccessControl-_setupRole}.
*/
event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Emitted when `account` is revoked `role`.
*
* `sender` is the account that originated the contract call:
* - if using `revokeRole`, it is the admin role bearer
* - if using `renounceRole`, it is the role bearer (i.e. `account`)
*/
event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
/**
* @dev Returns `true` if `account` has been granted `role`.
*/
function hasRole(bytes32 role, address account) external view returns (bool);
/**
* @dev Returns the admin role that controls `role`. See {grantRole} and
* {revokeRole}.
*
* To change a role's admin, use {AccessControl-_setRoleAdmin}.
*/
function getRoleAdmin(bytes32 role) external view returns (bytes32);
/**
* @dev Grants `role` to `account`.
*
* If `account` had not been already granted `role`, emits a {RoleGranted}
* event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function grantRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from `account`.
*
* If `account` had been granted `role`, emits a {RoleRevoked} event.
*
* Requirements:
*
* - the caller must have ``role``'s admin role.
*/
function revokeRole(bytes32 role, address account) external;
/**
* @dev Revokes `role` from the calling account.
*
* Roles are often managed via {grantRole} and {revokeRole}: this function's
* purpose is to provide a mechanism for accounts to lose their privileges
* if they are compromised (such as when a trusted device is misplaced).
*
* If the calling account had been granted `role`, emits a {RoleRevoked}
* event.
*
* Requirements:
*
* - the caller must be `account`.
*/
function renounceRole(bytes32 role, address account) external;
}{
"remappings": [
"@aave/core-v3/=lib/aave-v3-core/",
"@aave/periphery-v3/=lib/aave-v3-periphery/",
"@aave/=lib/aave-token/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"aave-stk-v1-5/=lib/aave-stk-v1-5/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"eth-gas-reporter/=node_modules/eth-gas-reporter/",
"forge-std/=lib/forge-std/src/",
"hardhat-deploy/=node_modules/hardhat-deploy/",
"hardhat/=node_modules/hardhat/",
"aave-address-book/=lib/aave-address-book/src/",
"aave-helpers/=lib/aave-stk-v1-5/lib/aave-helpers/",
"aave-v3-core/=lib/aave-address-book/lib/aave-v3-core/",
"aave-v3-periphery/=lib/aave-address-book/lib/aave-v3-periphery/",
"erc4626-tests/=lib/aave-stk-v1-5/lib/openzeppelin-contracts/lib/erc4626-tests/",
"openzeppelin-contracts/=lib/aave-stk-v1-5/lib/openzeppelin-contracts/",
"solidity-utils/=lib/solidity-utils/src/",
"aave-token/=lib/aave-token/contracts/",
"safety-module/=lib/safety-module/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"viaIR": false,
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"ghoToken","type":"address"},{"internalType":"address","name":"riskCouncil","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"GHO_TOKEN","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_DELAY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RISK_COUNCIL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getControlledFacilitators","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"facilitator","type":"address"}],"name":"getFacilitatorBucketCapacityTimelock","outputs":[{"internalType":"uint40","name":"","type":"uint40"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"facilitator","type":"address"}],"name":"isControlledFacilitator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"facilitatorList","type":"address[]"},{"internalType":"bool","name":"approve","type":"bool"}],"name":"setControlledFacilitator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"facilitator","type":"address"},{"internalType":"uint128","name":"newBucketCapacity","type":"uint128"}],"name":"updateFacilitatorBucketCapacity","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60c06040523480156200001157600080fd5b5060405162000e7638038062000e768339810160408190526200003491620001c4565b80620000403362000157565b6001600160a01b0381166200009c5760405162461bcd60e51b815260206004820152601460248201527f494e56414c49445f5249534b5f434f554e43494c00000000000000000000000060448201526064015b60405180910390fd5b6001600160a01b039081166080528316620000ea5760405162461bcd60e51b815260206004820152600d60248201526c24a72b20a624a22fa7aba722a960991b604482015260640162000093565b6001600160a01b038216620001365760405162461bcd60e51b815260206004820152601160248201527024a72b20a624a22fa3a427afaa27a5a2a760791b604482015260640162000093565b6001600160a01b03821660a0526200014e8362000157565b5050506200020e565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b80516001600160a01b0381168114620001bf57600080fd5b919050565b600080600060608486031215620001da57600080fd5b620001e584620001a7565b9250620001f560208501620001a7565b91506200020560408501620001a7565b90509250925092565b60805160a051610c2e62000248600039600081816101a60152818161047d01526105f901526000818160b001526103130152610c2e6000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063715018a611610071578063715018a6146101705780638da5cb5b14610178578063b1b43ae514610189578063b1c660f7146101a1578063ce5030b9146101c8578063f2fde38b1461020457600080fd5b806311aa1670146100ae578063153d9212146100ed57806337a0fdcb146101025780635ae6fb3a146101485780635e107b9c1461015d575b600080fd5b7f00000000000000000000000000000000000000000000000000000000000000005b6040516001600160a01b0390911681526020015b60405180910390f35b6100f5610217565b6040516100e4919061099c565b610132610110366004610a05565b6001600160a01b031660009081526001602052604090205464ffffffffff1690565b60405164ffffffffff90911681526020016100e4565b61015b610156366004610a46565b610228565b005b61015b61016b366004610b1d565b610311565b61015b61065d565b6000546001600160a01b03166100d0565b6101936201518081565b6040519081526020016100e4565b6100d07f000000000000000000000000000000000000000000000000000000000000000081565b6101f46101d6366004610a05565b6001600160a01b031660009081526002602052604090205460ff1690565b60405190151581526020016100e4565b61015b610212366004610a05565b610671565b606061022360036106ea565b905090565b6102306106fe565b60005b825181101561030c57816002600085848151811061025357610253610b60565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff02191690831515021790555081156102cb576102c58382815181106102ad576102ad610b60565b6020026020010151600361075890919063ffffffff16565b506102fa565b6102f88382815181106102e0576102e0610b60565b6020026020010151600361077690919063ffffffff16565b505b8061030481610b8c565b915050610233565b505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316331461037f5760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa1a0a62622a960911b60448201526064015b60405180910390fd5b6001600160a01b03821660009081526001602052604090205464ffffffffff16620151806103ad8242610ba7565b116103f35760405162461bcd60e51b815260206004820152601660248201527511115093d55390d157d393d517d49154d41150d5115160521b6044820152606401610376565b6001600160a01b03831660009081526002602052604090205460ff1661045b5760405162461bcd60e51b815260206004820152601a60248201527f464143494c495441544f525f4e4f545f434f4e54524f4c4c45440000000000006044820152606401610376565b6040516355017ca560e11b81526001600160a01b0384811660048301526000917f00000000000000000000000000000000000000000000000000000000000000009091169063aa02f94a906024016040805180830381865afa1580156104c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e99190610bbe565b50905080836001600160801b031614156105455760405162461bcd60e51b815260206004820152601c60248201527f4e4f5f4348414e47455f494e5f4255434b45545f4341504143495459000000006044820152606401610376565b61055981846001600160801b03168361078b565b6105a55760405162461bcd60e51b815260206004820152601e60248201527f494e56414c49445f4255434b45545f43415041434954595f55504441544500006044820152606401610376565b6001600160a01b0384811660008181526001602052604090819020805464ffffffffff19164264ffffffffff161790555163af93df5760e01b815260048101919091526001600160801b03851660248201527f00000000000000000000000000000000000000000000000000000000000000009091169063af93df5790604401600060405180830381600087803b15801561063f57600080fd5b505af1158015610653573d6000803e3d6000fd5b5050505050505050565b6106656106fe565b61066f60006107ae565b565b6106796106fe565b6001600160a01b0381166106de5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610376565b6106e7816107ae565b50565b606060006106f7836107fe565b9392505050565b6000546001600160a01b0316331461066f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610376565b600061076d836001600160a01b03841661085a565b90505b92915050565b600061076d836001600160a01b0384166108a9565b60008383101580156107a65750816107a38585610ba7565b11155b949350505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561084e57602002820191906000526020600020905b81548152602001906001019080831161083a575b50505050509050919050565b60008181526001830160205260408120546108a157508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610770565b506000610770565b600081815260018301602052604081205480156109925760006108cd600183610ba7565b85549091506000906108e190600190610ba7565b905081811461094657600086600001828154811061090157610901610b60565b906000526020600020015490508087600001848154811061092457610924610b60565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061095757610957610be2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610770565b6000915050610770565b6020808252825182820181905260009190848201906040850190845b818110156109dd5783516001600160a01b0316835292840192918401916001016109b8565b50909695505050505050565b80356001600160a01b0381168114610a0057600080fd5b919050565b600060208284031215610a1757600080fd5b61076d826109e9565b634e487b7160e01b600052604160045260246000fd5b80358015158114610a0057600080fd5b60008060408385031215610a5957600080fd5b823567ffffffffffffffff80821115610a7157600080fd5b818501915085601f830112610a8557600080fd5b8135602082821115610a9957610a99610a20565b8160051b604051601f19603f83011681018181108682111715610abe57610abe610a20565b604052928352818301935084810182019289841115610adc57600080fd5b948201945b83861015610b0157610af2866109e9565b85529482019493820193610ae1565b9650610b109050878201610a36565b9450505050509250929050565b60008060408385031215610b3057600080fd5b610b39836109e9565b915060208301356001600160801b0381168114610b5557600080fd5b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415610ba057610ba0610b76565b5060010190565b600082821015610bb957610bb9610b76565b500390565b60008060408385031215610bd157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220d1fdf34f1a2c1e412c206302e78664c2e806cdddafdc9efc52656803c90b28d864736f6c634300080a00330000000000000000000000009390b1735def18560c509e2d0bc090e9d6ba257a0000000000000000000000006bb7a212910682dcfdbd5bcbb3e28fb4e8da10ee0000000000000000000000008513e6f37dbc52de87b166980fa3f50639694b60
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106100a95760003560e01c8063715018a611610071578063715018a6146101705780638da5cb5b14610178578063b1b43ae514610189578063b1c660f7146101a1578063ce5030b9146101c8578063f2fde38b1461020457600080fd5b806311aa1670146100ae578063153d9212146100ed57806337a0fdcb146101025780635ae6fb3a146101485780635e107b9c1461015d575b600080fd5b7f0000000000000000000000008513e6f37dbc52de87b166980fa3f50639694b605b6040516001600160a01b0390911681526020015b60405180910390f35b6100f5610217565b6040516100e4919061099c565b610132610110366004610a05565b6001600160a01b031660009081526001602052604090205464ffffffffff1690565b60405164ffffffffff90911681526020016100e4565b61015b610156366004610a46565b610228565b005b61015b61016b366004610b1d565b610311565b61015b61065d565b6000546001600160a01b03166100d0565b6101936201518081565b6040519081526020016100e4565b6100d07f0000000000000000000000006bb7a212910682dcfdbd5bcbb3e28fb4e8da10ee81565b6101f46101d6366004610a05565b6001600160a01b031660009081526002602052604090205460ff1690565b60405190151581526020016100e4565b61015b610212366004610a05565b610671565b606061022360036106ea565b905090565b6102306106fe565b60005b825181101561030c57816002600085848151811061025357610253610b60565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002060006101000a81548160ff02191690831515021790555081156102cb576102c58382815181106102ad576102ad610b60565b6020026020010151600361075890919063ffffffff16565b506102fa565b6102f88382815181106102e0576102e0610b60565b6020026020010151600361077690919063ffffffff16565b505b8061030481610b8c565b915050610233565b505050565b7f0000000000000000000000008513e6f37dbc52de87b166980fa3f50639694b606001600160a01b0316331461037f5760405162461bcd60e51b815260206004820152600e60248201526d24a72b20a624a22fa1a0a62622a960911b60448201526064015b60405180910390fd5b6001600160a01b03821660009081526001602052604090205464ffffffffff16620151806103ad8242610ba7565b116103f35760405162461bcd60e51b815260206004820152601660248201527511115093d55390d157d393d517d49154d41150d5115160521b6044820152606401610376565b6001600160a01b03831660009081526002602052604090205460ff1661045b5760405162461bcd60e51b815260206004820152601a60248201527f464143494c495441544f525f4e4f545f434f4e54524f4c4c45440000000000006044820152606401610376565b6040516355017ca560e11b81526001600160a01b0384811660048301526000917f0000000000000000000000006bb7a212910682dcfdbd5bcbb3e28fb4e8da10ee9091169063aa02f94a906024016040805180830381865afa1580156104c5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104e99190610bbe565b50905080836001600160801b031614156105455760405162461bcd60e51b815260206004820152601c60248201527f4e4f5f4348414e47455f494e5f4255434b45545f4341504143495459000000006044820152606401610376565b61055981846001600160801b03168361078b565b6105a55760405162461bcd60e51b815260206004820152601e60248201527f494e56414c49445f4255434b45545f43415041434954595f55504441544500006044820152606401610376565b6001600160a01b0384811660008181526001602052604090819020805464ffffffffff19164264ffffffffff161790555163af93df5760e01b815260048101919091526001600160801b03851660248201527f0000000000000000000000006bb7a212910682dcfdbd5bcbb3e28fb4e8da10ee9091169063af93df5790604401600060405180830381600087803b15801561063f57600080fd5b505af1158015610653573d6000803e3d6000fd5b5050505050505050565b6106656106fe565b61066f60006107ae565b565b6106796106fe565b6001600160a01b0381166106de5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610376565b6106e7816107ae565b50565b606060006106f7836107fe565b9392505050565b6000546001600160a01b0316331461066f5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610376565b600061076d836001600160a01b03841661085a565b90505b92915050565b600061076d836001600160a01b0384166108a9565b60008383101580156107a65750816107a38585610ba7565b11155b949350505050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561084e57602002820191906000526020600020905b81548152602001906001019080831161083a575b50505050509050919050565b60008181526001830160205260408120546108a157508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610770565b506000610770565b600081815260018301602052604081205480156109925760006108cd600183610ba7565b85549091506000906108e190600190610ba7565b905081811461094657600086600001828154811061090157610901610b60565b906000526020600020015490508087600001848154811061092457610924610b60565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061095757610957610be2565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050610770565b6000915050610770565b6020808252825182820181905260009190848201906040850190845b818110156109dd5783516001600160a01b0316835292840192918401916001016109b8565b50909695505050505050565b80356001600160a01b0381168114610a0057600080fd5b919050565b600060208284031215610a1757600080fd5b61076d826109e9565b634e487b7160e01b600052604160045260246000fd5b80358015158114610a0057600080fd5b60008060408385031215610a5957600080fd5b823567ffffffffffffffff80821115610a7157600080fd5b818501915085601f830112610a8557600080fd5b8135602082821115610a9957610a99610a20565b8160051b604051601f19603f83011681018181108682111715610abe57610abe610a20565b604052928352818301935084810182019289841115610adc57600080fd5b948201945b83861015610b0157610af2866109e9565b85529482019493820193610ae1565b9650610b109050878201610a36565b9450505050509250929050565b60008060408385031215610b3057600080fd5b610b39836109e9565b915060208301356001600160801b0381168114610b5557600080fd5b809150509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000600019821415610ba057610ba0610b76565b5060010190565b600082821015610bb957610bb9610b76565b500390565b60008060408385031215610bd157600080fd5b505080516020909101519092909150565b634e487b7160e01b600052603160045260246000fdfea2646970667358221220d1fdf34f1a2c1e412c206302e78664c2e806cdddafdc9efc52656803c90b28d864736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000009390b1735def18560c509e2d0bc090e9d6ba257a0000000000000000000000006bb7a212910682dcfdbd5bcbb3e28fb4e8da10ee0000000000000000000000008513e6f37dbc52de87b166980fa3f50639694b60
-----Decoded View---------------
Arg [0] : owner (address): 0x9390B1735def18560c509E2d0bc090E9d6BA257a
Arg [1] : ghoToken (address): 0x6Bb7a212910682DCFdbd5BCBb3e28FB4E8da10Ee
Arg [2] : riskCouncil (address): 0x8513e6F37dBc52De87b166980Fa3F50639694B60
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 0000000000000000000000009390b1735def18560c509e2d0bc090e9d6ba257a
Arg [1] : 0000000000000000000000006bb7a212910682dcfdbd5bcbb3e28fb4e8da10ee
Arg [2] : 0000000000000000000000008513e6f37dbc52de87b166980fa3f50639694b60
Loading...
Loading
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
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.