Source Code
Overview
ETH Balance
0 ETH
Token Holdings
More Info
ContractCreator
TokenTracker
Multi Chain
Multichain Addresses
0 address found via
Latest 25 internal transactions (View All)
Advanced mode:
Parent Txn Hash | Block | From | To | Value | ||
---|---|---|---|---|---|---|
10136484 | 7 days 22 mins ago | 0 ETH | ||||
10073055 | 18 days 5 hrs ago | 0 ETH | ||||
10067508 | 19 days 4 hrs ago | 0 ETH | ||||
10067499 | 19 days 4 hrs ago | 0 ETH | ||||
10065496 | 19 days 13 hrs ago | 0 ETH | ||||
10061454 | 20 days 6 hrs ago | 0 ETH | ||||
10060914 | 20 days 8 hrs ago | 0 ETH | ||||
9998582 | 31 days 4 hrs ago | 0 ETH | ||||
9985973 | 33 days 9 hrs ago | 0 ETH | ||||
9978884 | 34 days 15 hrs ago | 0 ETH | ||||
9974752 | 35 days 9 hrs ago | 0 ETH | ||||
9974706 | 35 days 10 hrs ago | 0 ETH | ||||
9968527 | 36 days 13 hrs ago | 0 ETH | ||||
9967446 | 36 days 18 hrs ago | 0 ETH | ||||
9967439 | 36 days 18 hrs ago | 0 ETH | ||||
9946955 | 40 days 9 hrs ago | 0 ETH | ||||
9903535 | 48 days ago | 0 ETH | ||||
9882140 | 51 days 15 hrs ago | 0 ETH | ||||
9873415 | 53 days 3 hrs ago | 0 ETH | ||||
9867817 | 54 days 3 hrs ago | 0 ETH | ||||
9855175 | 56 days 8 hrs ago | 0 ETH | ||||
9853709 | 56 days 14 hrs ago | 0 ETH | ||||
9853193 | 56 days 16 hrs ago | 0 ETH | ||||
9789581 | 67 days 20 hrs ago | 0 ETH | ||||
9784346 | 68 days 18 hrs ago | 0 ETH |
Loading...
Loading
Contract Name:
StakedTokenV2Rev4
Compiler Version
v0.7.5+commit.eb77ed08
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: AGPL-3.0 pragma solidity 0.7.5; pragma experimental ABIEncoderV2; import {ERC20} from '@aave/aave-token/contracts/open-zeppelin/ERC20.sol'; import {IGhoVariableDebtToken} from './interfaces/IGhoVariableDebtToken.sol'; import {IStakedAave} from '@aave/safety-module/contracts/interfaces/IStakedAave.sol'; import {IERC20} from '@aave/safety-module/contracts/interfaces/IERC20.sol'; import {ITransferHook} from '@aave/safety-module/contracts/interfaces/ITransferHook.sol'; import {DistributionTypes} from '@aave/safety-module/contracts/lib/DistributionTypes.sol'; import {SafeMath} from '@aave/safety-module/contracts/lib/SafeMath.sol'; import {SafeERC20} from '@aave/safety-module/contracts/lib/SafeERC20.sol'; import {VersionedInitializable} from '@aave/safety-module/contracts/utils/VersionedInitializable.sol'; import {AaveDistributionManager} from '@aave/safety-module/contracts/stake/AaveDistributionManager.sol'; import {GovernancePowerWithSnapshot} from '@aave/safety-module/contracts/lib/GovernancePowerWithSnapshot.sol'; /** * @title StakedToken * @notice Contract to stake Aave token, tokenize the position and get rewards, inheriting from a distribution manager contract * @author Aave **/ contract StakedTokenV2Rev4 is IStakedAave, GovernancePowerWithSnapshot, VersionedInitializable, AaveDistributionManager { using SafeMath for uint256; using SafeERC20 for IERC20; /// @dev Start of Storage layout from StakedToken v1 uint256 public constant REVISION = 4; IERC20 public immutable STAKED_TOKEN; IERC20 public immutable REWARD_TOKEN; uint256 public immutable COOLDOWN_SECONDS; /// @notice Seconds available to redeem once the cooldown period is fullfilled uint256 public immutable UNSTAKE_WINDOW; /// @notice Address to pull from the rewards, needs to have approved this contract address public immutable REWARDS_VAULT; mapping(address => uint256) public stakerRewardsToClaim; mapping(address => uint256) public stakersCooldowns; /// @dev End of Storage layout from StakedToken v1 /// @dev To see the voting mappings, go to GovernancePowerWithSnapshot.sol mapping(address => address) internal _votingDelegates; mapping(address => mapping(uint256 => Snapshot)) internal _propositionPowerSnapshots; mapping(address => uint256) internal _propositionPowerSnapshotsCounts; mapping(address => address) internal _propositionPowerDelegates; bytes32 public DOMAIN_SEPARATOR; bytes public constant EIP712_REVISION = bytes('1'); bytes32 internal constant EIP712_DOMAIN = keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'); bytes32 public constant PERMIT_TYPEHASH = keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'); /// @dev owner => next valid nonce to submit with permit() mapping(address => uint256) public _nonces; /// @dev End of Storage layout from StakedTokenV2Rev3 IGhoVariableDebtToken public ghoDebtToken; event Staked(address indexed from, address indexed onBehalfOf, uint256 amount); event Redeem(address indexed from, address indexed to, uint256 amount); event RewardsAccrued(address user, uint256 amount); event RewardsClaimed(address indexed from, address indexed to, uint256 amount); event Cooldown(address indexed user); constructor( IERC20 stakedToken, IERC20 rewardToken, uint256 cooldownSeconds, uint256 unstakeWindow, address rewardsVault, address emissionManager, uint128 distributionDuration, string memory name, string memory symbol, uint8 decimals, address governance ) public ERC20(name, symbol) AaveDistributionManager(emissionManager, distributionDuration) { STAKED_TOKEN = stakedToken; REWARD_TOKEN = rewardToken; COOLDOWN_SECONDS = cooldownSeconds; UNSTAKE_WINDOW = unstakeWindow; REWARDS_VAULT = rewardsVault; _aaveGovernance = ITransferHook(governance); ERC20._setupDecimals(decimals); } /** * @dev Called by the proxy contract **/ function initialize(address _ghoDebtToken) external initializer { uint256 chainId; //solium-disable-next-line assembly { chainId := chainid() } DOMAIN_SEPARATOR = keccak256( abi.encode( EIP712_DOMAIN, keccak256(bytes(name())), keccak256(EIP712_REVISION), chainId, address(this) ) ); ghoDebtToken = IGhoVariableDebtToken(_ghoDebtToken); } function stake(address onBehalfOf, uint256 amount) external override { require(amount != 0, 'INVALID_ZERO_AMOUNT'); uint256 balanceOfUser = balanceOf(onBehalfOf); uint256 accruedRewards = _updateUserAssetInternal( onBehalfOf, address(this), balanceOfUser, totalSupply() ); if (accruedRewards != 0) { emit RewardsAccrued(onBehalfOf, accruedRewards); stakerRewardsToClaim[onBehalfOf] = stakerRewardsToClaim[onBehalfOf].add(accruedRewards); } stakersCooldowns[onBehalfOf] = getNextCooldownTimestamp(0, amount, onBehalfOf, balanceOfUser); _mint(onBehalfOf, amount); IERC20(STAKED_TOKEN).safeTransferFrom(msg.sender, address(this), amount); emit Staked(msg.sender, onBehalfOf, amount); } /** * @dev Redeems staked tokens, and stop earning rewards * @param to Address to redeem to * @param amount Amount to redeem **/ function redeem(address to, uint256 amount) external override { require(amount != 0, 'INVALID_ZERO_AMOUNT'); //solium-disable-next-line uint256 cooldownStartTimestamp = stakersCooldowns[msg.sender]; require( block.timestamp > cooldownStartTimestamp.add(COOLDOWN_SECONDS), 'INSUFFICIENT_COOLDOWN' ); require( block.timestamp.sub(cooldownStartTimestamp.add(COOLDOWN_SECONDS)) <= UNSTAKE_WINDOW, 'UNSTAKE_WINDOW_FINISHED' ); uint256 balanceOfMessageSender = balanceOf(msg.sender); uint256 amountToRedeem = (amount > balanceOfMessageSender) ? balanceOfMessageSender : amount; _updateCurrentUnclaimedRewards(msg.sender, balanceOfMessageSender, true); _burn(msg.sender, amountToRedeem); if (balanceOfMessageSender.sub(amountToRedeem) == 0) { stakersCooldowns[msg.sender] = 0; } IERC20(STAKED_TOKEN).safeTransfer(to, amountToRedeem); emit Redeem(msg.sender, to, amountToRedeem); } /** * @dev Activates the cooldown period to unstake * - It can't be called if the user is not staking **/ function cooldown() external override { require(balanceOf(msg.sender) != 0, 'INVALID_BALANCE_ON_COOLDOWN'); //solium-disable-next-line stakersCooldowns[msg.sender] = block.timestamp; emit Cooldown(msg.sender); } /** * @dev Claims an `amount` of `REWARD_TOKEN` to the address `to` * @param to Address to stake for * @param amount Amount to stake **/ function claimRewards(address to, uint256 amount) external override { uint256 newTotalRewards = _updateCurrentUnclaimedRewards( msg.sender, balanceOf(msg.sender), false ); uint256 amountToClaim = (amount == type(uint256).max) ? newTotalRewards : amount; stakerRewardsToClaim[msg.sender] = newTotalRewards.sub(amountToClaim, 'INVALID_AMOUNT'); REWARD_TOKEN.safeTransferFrom(REWARDS_VAULT, to, amountToClaim); emit RewardsClaimed(msg.sender, to, amountToClaim); } /** * @dev Internal ERC20 _transfer of the tokenized staked tokens * @param from Address to transfer from * @param to Address to transfer to * @param amount Amount to transfer **/ function _transfer( address from, address to, uint256 amount ) internal override { uint256 balanceOfFrom = balanceOf(from); // Sender _updateCurrentUnclaimedRewards(from, balanceOfFrom, true); // Recipient if (from != to) { uint256 balanceOfTo = balanceOf(to); _updateCurrentUnclaimedRewards(to, balanceOfTo, true); uint256 previousSenderCooldown = stakersCooldowns[from]; stakersCooldowns[to] = getNextCooldownTimestamp( previousSenderCooldown, amount, to, balanceOfTo ); // if cooldown was set and whole balance of sender was transferred - clear cooldown if (balanceOfFrom == amount && previousSenderCooldown != 0) { stakersCooldowns[from] = 0; } } super._transfer(from, to, amount); } /** * @dev Updates the user state related with his accrued rewards * @param user Address of the user * @param userBalance The current balance of the user * @param updateStorage Boolean flag used to update or not the stakerRewardsToClaim of the user * @return The unclaimed rewards that were added to the total accrued **/ function _updateCurrentUnclaimedRewards( address user, uint256 userBalance, bool updateStorage ) internal returns (uint256) { uint256 accruedRewards = _updateUserAssetInternal( user, address(this), userBalance, totalSupply() ); uint256 unclaimedRewards = stakerRewardsToClaim[user].add(accruedRewards); if (accruedRewards != 0) { if (updateStorage) { stakerRewardsToClaim[user] = unclaimedRewards; } emit RewardsAccrued(user, accruedRewards); } return unclaimedRewards; } /** * @dev Calculates the how is gonna be a new cooldown timestamp depending on the sender/receiver situation * - If the timestamp of the sender is "better" or the timestamp of the recipient is 0, we take the one of the recipient * - Weighted average of from/to cooldown timestamps if: * # The sender doesn't have the cooldown activated (timestamp 0). * # The sender timestamp is expired * # The sender has a "worse" timestamp * - If the receiver's cooldown timestamp expired (too old), the next is 0 * @param fromCooldownTimestamp Cooldown timestamp of the sender * @param amountToReceive Amount * @param toAddress Address of the recipient * @param toBalance Current balance of the receiver * @return The new cooldown timestamp **/ function getNextCooldownTimestamp( uint256 fromCooldownTimestamp, uint256 amountToReceive, address toAddress, uint256 toBalance ) public view returns (uint256) { uint256 toCooldownTimestamp = stakersCooldowns[toAddress]; if (toCooldownTimestamp == 0) { return 0; } uint256 minimalValidCooldownTimestamp = block.timestamp.sub(COOLDOWN_SECONDS).sub( UNSTAKE_WINDOW ); if (minimalValidCooldownTimestamp > toCooldownTimestamp) { toCooldownTimestamp = 0; } else { uint256 fromCooldownTimestamp = (minimalValidCooldownTimestamp > fromCooldownTimestamp) ? block.timestamp : fromCooldownTimestamp; if (fromCooldownTimestamp < toCooldownTimestamp) { return toCooldownTimestamp; } else { toCooldownTimestamp = ( amountToReceive.mul(fromCooldownTimestamp).add(toBalance.mul(toCooldownTimestamp)) ).div(amountToReceive.add(toBalance)); } } return toCooldownTimestamp; } /** * @dev Return the total rewards pending to claim by an staker * @param staker The staker address * @return The rewards */ function getTotalRewardsBalance(address staker) external view returns (uint256) { DistributionTypes.UserStakeInput[] memory userStakeInputs = new DistributionTypes.UserStakeInput[](1); userStakeInputs[0] = DistributionTypes.UserStakeInput({ underlyingAsset: address(this), stakedByUser: balanceOf(staker), totalStaked: totalSupply() }); return stakerRewardsToClaim[staker].add(_getUnclaimedRewards(staker, userStakeInputs)); } /** * @dev returns the revision of the implementation contract * @return The revision */ function getRevision() internal pure override returns (uint256) { return REVISION; } /** * @dev implements the permit function as for https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md * @param owner the owner of the funds * @param spender the spender * @param value the amount * @param deadline the deadline timestamp, type(uint256).max for no deadline * @param v signature param * @param s signature param * @param r signature param */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external { require(owner != address(0), 'INVALID_OWNER'); //solium-disable-next-line require(block.timestamp <= deadline, 'INVALID_EXPIRATION'); uint256 currentValidNonce = _nonces[owner]; bytes32 digest = keccak256( abi.encodePacked( '\x19\x01', DOMAIN_SEPARATOR, keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline)) ) ); require(owner == ecrecover(digest, v, r, s), 'INVALID_SIGNATURE'); _nonces[owner] = currentValidNonce.add(1); _approve(owner, spender, value); } /** * @dev Writes a snapshot before any operation involving transfer of value: _transfer, _mint and _burn * - On _transfer, it writes snapshots for both "from" and "to" * - On _mint, only for _to * - On _burn, only for _from * @param from the from address * @param to the to address * @param amount the amount to transfer */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal override { ghoDebtToken.updateDiscountDistribution(from, to, balanceOf(from), balanceOf(to), amount); address votingFromDelegatee = _votingDelegates[from]; address votingToDelegatee = _votingDelegates[to]; if (votingFromDelegatee == address(0)) { votingFromDelegatee = from; } if (votingToDelegatee == address(0)) { votingToDelegatee = to; } _moveDelegatesByType( votingFromDelegatee, votingToDelegatee, amount, DelegationType.VOTING_POWER ); address propPowerFromDelegatee = _propositionPowerDelegates[from]; address propPowerToDelegatee = _propositionPowerDelegates[to]; if (propPowerFromDelegatee == address(0)) { propPowerFromDelegatee = from; } if (propPowerToDelegatee == address(0)) { propPowerToDelegatee = to; } _moveDelegatesByType( propPowerFromDelegatee, propPowerToDelegatee, amount, DelegationType.PROPOSITION_POWER ); // caching the aave governance address to avoid multiple state loads ITransferHook aaveGovernance = _aaveGovernance; if (aaveGovernance != ITransferHook(0)) { aaveGovernance.onTransfer(from, to, amount); } } function _getDelegationDataByType(DelegationType delegationType) internal view override returns ( mapping(address => mapping(uint256 => Snapshot)) storage, //snapshots mapping(address => uint256) storage, //snapshots count mapping(address => address) storage //delegatees list ) { if (delegationType == DelegationType.VOTING_POWER) { return (_votingSnapshots, _votingSnapshotsCounts, _votingDelegates); } else { return ( _propositionPowerSnapshots, _propositionPowerSnapshotsCounts, _propositionPowerDelegates ); } } /** * @dev Delegates power from signatory to `delegatee` * @param delegatee The address to delegate votes to * @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER) * @param nonce The contract state required to match the signature * @param expiry The time at which to expire the signature * @param v The recovery byte of the signature * @param r Half of the ECDSA signature pair * @param s Half of the ECDSA signature pair */ function delegateByTypeBySig( address delegatee, DelegationType delegationType, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s ) public { bytes32 structHash = keccak256( abi.encode(DELEGATE_BY_TYPE_TYPEHASH, delegatee, uint256(delegationType), nonce, expiry) ); bytes32 digest = keccak256(abi.encodePacked('\x19\x01', DOMAIN_SEPARATOR, structHash)); address signatory = ecrecover(digest, v, r, s); require(signatory != address(0), 'INVALID_SIGNATURE'); require(nonce == _nonces[signatory]++, 'INVALID_NONCE'); require(block.timestamp <= expiry, 'INVALID_EXPIRATION'); _delegateByType(signatory, delegatee, delegationType); } /** * @dev Delegates power from signatory to `delegatee` * @param delegatee The address to delegate votes to * @param nonce The contract state required to match the signature * @param expiry The time at which to expire the signature * @param v The recovery byte of the signature * @param r Half of the ECDSA signature pair * @param s Half of the ECDSA signature pair */ function delegateBySig( address delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s ) public { bytes32 structHash = keccak256(abi.encode(DELEGATE_TYPEHASH, delegatee, nonce, expiry)); bytes32 digest = keccak256(abi.encodePacked('\x19\x01', DOMAIN_SEPARATOR, structHash)); address signatory = ecrecover(digest, v, r, s); require(signatory != address(0), 'INVALID_SIGNATURE'); require(nonce == _nonces[signatory]++, 'INVALID_NONCE'); require(block.timestamp <= expiry, 'INVALID_EXPIRATION'); _delegateByType(signatory, delegatee, DelegationType.VOTING_POWER); _delegateByType(signatory, delegatee, DelegationType.PROPOSITION_POWER); } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; /** * @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); }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; interface IGovernancePowerDelegationToken { enum DelegationType {VOTING_POWER, PROPOSITION_POWER} /** * @dev emitted when a user delegates to another * @param delegator the delegator * @param delegatee the delegatee * @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER) **/ event DelegateChanged( address indexed delegator, address indexed delegatee, DelegationType delegationType ); /** * @dev emitted when an action changes the delegated power of a user * @param user the user which delegated power has changed * @param amount the amount of delegated power for the user * @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER) **/ event DelegatedPowerChanged(address indexed user, uint256 amount, DelegationType delegationType); /** * @dev delegates the specific power to a delegatee * @param delegatee the user which delegated power has changed * @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER) **/ function delegateByType(address delegatee, DelegationType delegationType) external virtual; /** * @dev delegates all the powers to a specific user * @param delegatee the user to which the power will be delegated **/ function delegate(address delegatee) external virtual; /** * @dev returns the delegatee of an user * @param delegator the address of the delegator **/ function getDelegateeByType(address delegator, DelegationType delegationType) external virtual view returns (address); /** * @dev returns the current delegated power of a user. The current power is the * power delegated at the time of the last snapshot * @param user the user **/ function getPowerCurrent(address user, DelegationType delegationType) external virtual view returns (uint256); /** * @dev returns the delegated power of a user at a certain block * @param user the user **/ function getPowerAtBlock( address user, uint256 blockNumber, DelegationType delegationType ) external virtual view returns (uint256); /** * @dev returns the total supply at a certain block number **/ function totalSupplyAt(uint256 blockNumber) external virtual view returns (uint256); }
pragma solidity ^0.7.5; /** * @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) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @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"); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.5; /* * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.7.5; import "./Context.sol"; import "../interfaces/IERC20.sol"; import "./SafeMath.sol"; import "./Address.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin guidelines: functions revert instead * of returning `false` on failure. This behavior is nonetheless conventional * and does not conflict with the expectations of ERC20 applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20 { using SafeMath for uint256; using Address for address; mapping (address => uint256) private _balances; mapping (address => mapping (address => uint256)) private _allowances; uint256 private _totalSupply; string internal _name; string internal _symbol; uint8 private _decimals; /** * @dev Sets the values for {name} and {symbol}, initializes {decimals} with * a default value of 18. * * To select a different value for {decimals}, use {_setupDecimals}. * * All three of these values are immutable: they can only be set once during * construction. */ constructor (string memory name, string memory symbol) public { _name = name; _symbol = symbol; _decimals = 18; } /** * @dev Returns the name of the token. */ function name() public view returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5,05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is * called. * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view returns (uint8) { return _decimals; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `recipient` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}; * * Requirements: * - `sender` and `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. * - the caller must have allowance for ``sender``'s tokens of at least * `amount`. */ function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance")); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero")); return true; } /** * @dev Moves tokens `amount` from `sender` to `recipient`. * * This is internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `sender` cannot be the zero address. * - `recipient` cannot be the zero address. * - `sender` must have a balance of at least `amount`. */ function _transfer(address sender, address recipient, uint256 amount) internal virtual { require(sender != address(0), "ERC20: transfer from the zero address"); require(recipient != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance"); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements * * - `to` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance"); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens. * * This is internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve(address owner, address spender, uint256 amount) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Sets {decimals} to a value other than the default one of 18. * * WARNING: This function should only be called from the constructor. Most * applications that interact with token contracts will not expect * {decimals} to ever change, and may work incorrectly if it does. */ function _setupDecimals(uint8 decimals_) internal { _decimals = decimals_; } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be to transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { } }
pragma solidity ^0.7.5; /** * @dev Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, "SafeMath: addition overflow"); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, "SafeMath: subtraction overflow"); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * 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); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, "SafeMath: multiplication overflow"); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, "SafeMath: division by zero"); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, "SafeMath: modulo by zero"); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message 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, string memory errorMessage) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; import {SafeMath} from '../../open-zeppelin/SafeMath.sol'; import {ERC20} from '../../open-zeppelin/ERC20.sol'; import { IGovernancePowerDelegationToken } from '../../interfaces/IGovernancePowerDelegationToken.sol'; /** * @notice implementation of the AAVE token contract * @author Aave */ abstract contract GovernancePowerDelegationERC20 is ERC20, IGovernancePowerDelegationToken { using SafeMath for uint256; /// @notice The EIP-712 typehash for the delegation struct used by the contract bytes32 public constant DELEGATE_BY_TYPE_TYPEHASH = keccak256( 'DelegateByType(address delegatee,uint256 type,uint256 nonce,uint256 expiry)' ); bytes32 public constant DELEGATE_TYPEHASH = keccak256( 'Delegate(address delegatee,uint256 nonce,uint256 expiry)' ); /// @dev snapshot of a value on a specific block, used for votes struct Snapshot { uint128 blockNumber; uint128 value; } /** * @dev delegates one specific power to a delegatee * @param delegatee the user which delegated power has changed * @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER) **/ function delegateByType(address delegatee, DelegationType delegationType) external override { _delegateByType(msg.sender, delegatee, delegationType); } /** * @dev delegates all the powers to a specific user * @param delegatee the user to which the power will be delegated **/ function delegate(address delegatee) external override { _delegateByType(msg.sender, delegatee, DelegationType.VOTING_POWER); _delegateByType(msg.sender, delegatee, DelegationType.PROPOSITION_POWER); } /** * @dev returns the delegatee of an user * @param delegator the address of the delegator **/ function getDelegateeByType(address delegator, DelegationType delegationType) external override view returns (address) { (, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType); return _getDelegatee(delegator, delegates); } /** * @dev returns the current delegated power of a user. The current power is the * power delegated at the time of the last snapshot * @param user the user **/ function getPowerCurrent(address user, DelegationType delegationType) external override view returns (uint256) { ( mapping(address => mapping(uint256 => Snapshot)) storage snapshots, mapping(address => uint256) storage snapshotsCounts, ) = _getDelegationDataByType(delegationType); return _searchByBlockNumber(snapshots, snapshotsCounts, user, block.number); } /** * @dev returns the delegated power of a user at a certain block * @param user the user **/ function getPowerAtBlock( address user, uint256 blockNumber, DelegationType delegationType ) external override view returns (uint256) { ( mapping(address => mapping(uint256 => Snapshot)) storage snapshots, mapping(address => uint256) storage snapshotsCounts, ) = _getDelegationDataByType(delegationType); return _searchByBlockNumber(snapshots, snapshotsCounts, user, blockNumber); } /** * @dev returns the total supply at a certain block number * used by the voting strategy contracts to calculate the total votes needed for threshold/quorum * In this initial implementation with no AAVE minting, simply returns the current supply * A snapshots mapping will need to be added in case a mint function is added to the AAVE token in the future **/ function totalSupplyAt(uint256 blockNumber) external override view returns (uint256) { return super.totalSupply(); } /** * @dev delegates the specific power to a delegatee * @param delegatee the user which delegated power has changed * @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER) **/ function _delegateByType( address delegator, address delegatee, DelegationType delegationType ) internal { require(delegatee != address(0), 'INVALID_DELEGATEE'); (, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType); uint256 delegatorBalance = balanceOf(delegator); address previousDelegatee = _getDelegatee(delegator, delegates); delegates[delegator] = delegatee; _moveDelegatesByType(previousDelegatee, delegatee, delegatorBalance, delegationType); emit DelegateChanged(delegator, delegatee, delegationType); } /** * @dev moves delegated power from one user to another * @param from the user from which delegated power is moved * @param to the user that will receive the delegated power * @param amount the amount of delegated power to be moved * @param delegationType the type of delegation (VOTING_POWER, PROPOSITION_POWER) **/ function _moveDelegatesByType( address from, address to, uint256 amount, DelegationType delegationType ) internal { if (from == to) { return; } ( mapping(address => mapping(uint256 => Snapshot)) storage snapshots, mapping(address => uint256) storage snapshotsCounts, ) = _getDelegationDataByType(delegationType); if (from != address(0)) { uint256 previous = 0; uint256 fromSnapshotsCount = snapshotsCounts[from]; if (fromSnapshotsCount != 0) { previous = snapshots[from][fromSnapshotsCount - 1].value; } else { previous = balanceOf(from); } _writeSnapshot( snapshots, snapshotsCounts, from, uint128(previous), uint128(previous.sub(amount)) ); emit DelegatedPowerChanged(from, previous.sub(amount), delegationType); } if (to != address(0)) { uint256 previous = 0; uint256 toSnapshotsCount = snapshotsCounts[to]; if (toSnapshotsCount != 0) { previous = snapshots[to][toSnapshotsCount - 1].value; } else { previous = balanceOf(to); } _writeSnapshot( snapshots, snapshotsCounts, to, uint128(previous), uint128(previous.add(amount)) ); emit DelegatedPowerChanged(to, previous.add(amount), delegationType); } } /** * @dev searches a snapshot by block number. Uses binary search. * @param snapshots the snapshots mapping * @param snapshotsCounts the number of snapshots * @param user the user for which the snapshot is being searched * @param blockNumber the block number being searched **/ function _searchByBlockNumber( mapping(address => mapping(uint256 => Snapshot)) storage snapshots, mapping(address => uint256) storage snapshotsCounts, address user, uint256 blockNumber ) internal view returns (uint256) { require(blockNumber <= block.number, 'INVALID_BLOCK_NUMBER'); uint256 snapshotsCount = snapshotsCounts[user]; if (snapshotsCount == 0) { return balanceOf(user); } // First check most recent balance if (snapshots[user][snapshotsCount - 1].blockNumber <= blockNumber) { return snapshots[user][snapshotsCount - 1].value; } // Next check implicit zero balance if (snapshots[user][0].blockNumber > blockNumber) { return 0; } uint256 lower = 0; uint256 upper = snapshotsCount - 1; while (upper > lower) { uint256 center = upper - (upper - lower) / 2; // ceil, avoiding overflow Snapshot memory snapshot = snapshots[user][center]; if (snapshot.blockNumber == blockNumber) { return snapshot.value; } else if (snapshot.blockNumber < blockNumber) { lower = center; } else { upper = center - 1; } } return snapshots[user][lower].value; } /** * @dev returns the delegation data (snapshot, snapshotsCount, list of delegates) by delegation type * NOTE: Ideal implementation would have mapped this in a struct by delegation type. Unfortunately, * the AAVE token and StakeToken already include a mapping for the snapshots, so we require contracts * who inherit from this to provide access to the delegation data by overriding this method. * @param delegationType the type of delegation **/ function _getDelegationDataByType(DelegationType delegationType) internal virtual view returns ( mapping(address => mapping(uint256 => Snapshot)) storage, //snapshots mapping(address => uint256) storage, //snapshots count mapping(address => address) storage //delegatees list ); /** * @dev Writes a snapshot for an owner of tokens * @param owner The owner of the tokens * @param oldValue The value before the operation that is gonna be executed after the snapshot * @param newValue The value after the operation */ function _writeSnapshot( mapping(address => mapping(uint256 => Snapshot)) storage snapshots, mapping(address => uint256) storage snapshotsCounts, address owner, uint128 oldValue, uint128 newValue ) internal { uint128 currentBlock = uint128(block.number); uint256 ownerSnapshotsCount = snapshotsCounts[owner]; mapping(uint256 => Snapshot) storage snapshotsOwner = snapshots[owner]; // Doing multiple operations in the same block if ( ownerSnapshotsCount != 0 && snapshotsOwner[ownerSnapshotsCount - 1].blockNumber == currentBlock ) { snapshotsOwner[ownerSnapshotsCount - 1].value = newValue; } else { snapshotsOwner[ownerSnapshotsCount] = Snapshot(currentBlock, newValue); snapshotsCounts[owner] = ownerSnapshotsCount + 1; } } /** * @dev returns the user delegatee. If a user never performed any delegation, * his delegated address will be 0x0. In that case we simply return the user itself * @param delegator the address of the user for which return the delegatee * @param delegates the array of delegates for a particular type of delegation **/ function _getDelegatee(address delegator, mapping(address => address) storage delegates) internal view returns (address) { address previousDelegatee = delegates[delegator]; if (previousDelegatee == address(0)) { return delegator; } return previousDelegatee; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; pragma experimental ABIEncoderV2; import {DistributionTypes} from '../lib/DistributionTypes.sol'; interface IAaveDistributionManager { function configureAssets(DistributionTypes.AssetConfigInput[] calldata assetsConfigInput) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.7.5; /** * @dev Interface of the ERC20 standard as defined in the EIP. * From https://github.com/OpenZeppelin/openzeppelin-contracts */ 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); }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; import {IERC20} from './IERC20.sol'; /** * @dev Interface for ERC20 including metadata **/ interface IERC20Detailed is IERC20 { function name() external view returns (string memory); function symbol() external view returns (string memory); function decimals() external view returns (uint8); }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; interface IStakedAave { function stake(address to, uint256 amount) external; function redeem(address to, uint256 amount) external; function cooldown() external; function claimRewards(address to, uint256 amount) external; }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; interface ITransferHook { function onTransfer( address from, address to, uint256 amount ) external; }
// SPDX-License-Identifier: MIT pragma solidity 0.7.5; /** * @dev Collection of functions related to the address type * From https://github.com/OpenZeppelin/openzeppelin-contracts */ 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) { // According to EIP-1052, 0x0 is the value returned for not-yet created accounts // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned // for accounts without code, i.e. `keccak256('')` bytes32 codehash; bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; // solhint-disable-next-line no-inline-assembly assembly { codehash := extcodehash(account) } return (codehash != accountHash && codehash != 0x0); } /** * @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'); } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.5; /** * @dev From https://github.com/OpenZeppelin/openzeppelin-contracts * Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with GSN meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address payable) { return msg.sender; } function _msgData() internal view virtual returns (bytes memory) { this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691 return msg.data; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; pragma experimental ABIEncoderV2; library DistributionTypes { struct AssetConfigInput { uint128 emissionPerSecond; uint256 totalStaked; address underlyingAsset; } struct UserStakeInput { address underlyingAsset; uint256 stakedByUser; uint256 totalStaked; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; import {Context} from './Context.sol'; import {IERC20} from '../interfaces/IERC20.sol'; import {IERC20Detailed} from '../interfaces/IERC20Detailed.sol'; import {SafeMath} from './SafeMath.sol'; /** * @title ERC20 * @notice Basic ERC20 implementation * @author Aave **/ contract ERC20 is Context, IERC20, IERC20Detailed { using SafeMath for uint256; mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; uint8 private _decimals; constructor( string memory name, string memory symbol, uint8 decimals ) public { _name = name; _symbol = symbol; _decimals = decimals; } /** * @return the name of the token **/ function name() public view override returns (string memory) { return _name; } /** * @return the symbol of the token **/ function symbol() public view override returns (string memory) { return _symbol; } /** * @return the decimals of the token **/ function decimals() public view override returns (uint8) { return _decimals; } /** * @return the total supply of the token **/ function totalSupply() public view override returns (uint256) { return _totalSupply; } /** * @return the balance of the token **/ function balanceOf(address account) public view override returns (uint256) { return _balances[account]; } /** * @dev executes a transfer of tokens from msg.sender to recipient * @param recipient the recipient of the tokens * @param amount the amount of tokens being transferred * @return true if the transfer succeeds, false otherwise **/ function transfer(address recipient, uint256 amount) public virtual override returns (bool) { _transfer(_msgSender(), recipient, amount); return true; } /** * @dev returns the allowance of spender on the tokens owned by owner * @param owner the owner of the tokens * @param spender the user allowed to spend the owner's tokens * @return the amount of owner's tokens spender is allowed to spend **/ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev allows spender to spend the tokens owned by msg.sender * @param spender the user allowed to spend msg.sender tokens * @return true **/ function approve(address spender, uint256 amount) public virtual override returns (bool) { _approve(_msgSender(), spender, amount); return true; } /** * @dev executes a transfer of token from sender to recipient, if msg.sender is allowed to do so * @param sender the owner of the tokens * @param recipient the recipient of the tokens * @param amount the amount of tokens being transferred * @return true if the transfer succeeds, false otherwise **/ function transferFrom( address sender, address recipient, uint256 amount ) public virtual override returns (bool) { _transfer(sender, recipient, amount); _approve( sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, 'ERC20: transfer amount exceeds allowance') ); return true; } /** * @dev increases the allowance of spender to spend msg.sender tokens * @param spender the user allowed to spend on behalf of msg.sender * @param addedValue the amount being added to the allowance * @return true **/ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue)); return true; } /** * @dev decreases the allowance of spender to spend msg.sender tokens * @param spender the user allowed to spend on behalf of msg.sender * @param subtractedValue the amount being subtracted to the allowance * @return true **/ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { _approve( _msgSender(), spender, _allowances[_msgSender()][spender].sub( subtractedValue, 'ERC20: decreased allowance below zero' ) ); return true; } function _transfer( address sender, address recipient, uint256 amount ) internal virtual { require(sender != address(0), 'ERC20: transfer from the zero address'); require(recipient != address(0), 'ERC20: transfer to the zero address'); _beforeTokenTransfer(sender, recipient, amount); _balances[sender] = _balances[sender].sub(amount, 'ERC20: transfer amount exceeds balance'); _balances[recipient] = _balances[recipient].add(amount); emit Transfer(sender, recipient, amount); } function _mint(address account, uint256 amount) internal virtual { require(account != address(0), 'ERC20: mint to the zero address'); _beforeTokenTransfer(address(0), account, amount); _totalSupply = _totalSupply.add(amount); _balances[account] = _balances[account].add(amount); emit Transfer(address(0), account, amount); } function _burn(address account, uint256 amount) internal virtual { require(account != address(0), 'ERC20: burn from the zero address'); _beforeTokenTransfer(account, address(0), amount); _balances[account] = _balances[account].sub(amount, 'ERC20: burn amount exceeds balance'); _totalSupply = _totalSupply.sub(amount); emit Transfer(account, address(0), amount); } function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), 'ERC20: approve from the zero address'); require(spender != address(0), 'ERC20: approve to the zero address'); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } function _setName(string memory newName) internal { _name = newName; } function _setSymbol(string memory newSymbol) internal { _symbol = newSymbol; } function _setDecimals(uint8 newDecimals) internal { _decimals = newDecimals; } function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; import {ERC20} from '../lib/ERC20.sol'; import {ITransferHook} from '../interfaces/ITransferHook.sol'; import {SafeMath} from '../lib/SafeMath.sol'; import { GovernancePowerDelegationERC20 } from '@aave/aave-token/contracts/token/base/GovernancePowerDelegationERC20.sol'; /** * @title ERC20WithSnapshot * @notice ERC20 including snapshots of balances on transfer-related actions * @author Aave **/ abstract contract GovernancePowerWithSnapshot is GovernancePowerDelegationERC20 { using SafeMath for uint256; /** * @dev The following storage layout points to the prior StakedToken.sol implementation: * _snapshots => _votingSnapshots * _snapshotsCounts => _votingSnapshotsCounts * _aaveGovernance => _aaveGovernance */ mapping(address => mapping(uint256 => Snapshot)) public _votingSnapshots; mapping(address => uint256) public _votingSnapshotsCounts; /// @dev reference to the Aave governance contract to call (if initialized) on _beforeTokenTransfer /// !!! IMPORTANT The Aave governance is considered a trustable contract, being its responsibility /// to control all potential reentrancies by calling back the this contract ITransferHook public _aaveGovernance; function _setAaveGovernance(ITransferHook aaveGovernance) internal virtual { _aaveGovernance = aaveGovernance; } }
// SPDX-License-Identifier: MIT pragma solidity 0.7.5; import {IERC20} from '../interfaces/IERC20.sol'; import {SafeMath} from './SafeMath.sol'; import {Address} from './Address.sol'; /** * @title SafeERC20 * @dev From https://github.com/OpenZeppelin/openzeppelin-contracts * Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using SafeMath for uint256; using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } function safeApprove( IERC20 token, address spender, uint256 value ) internal { require( (value == 0) || (token.allowance(address(this), spender) == 0), 'SafeERC20: approve from non-zero to non-zero allowance' ); callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function callOptionalReturn(IERC20 token, bytes memory data) private { require(address(token).isContract(), 'SafeERC20: call to non-contract'); // solhint-disable-next-line avoid-low-level-calls (bool success, bytes memory returndata) = address(token).call(data); require(success, 'SafeERC20: low-level call failed'); if (returndata.length > 0) { // Return data is optional // solhint-disable-next-line max-line-length require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed'); } } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; /** * @dev From https://github.com/OpenZeppelin/openzeppelin-contracts * Wrappers over Solidity's arithmetic operations with added overflow * checks. * * Arithmetic operations in Solidity wrap on overflow. This can easily result * in bugs, because programmers usually assume that an overflow raises an * error, which is the standard behavior in high level programming languages. * `SafeMath` restores this intuition by reverting the transaction when an * operation overflows. * * Using this library instead of the unchecked operations eliminates an entire * class of bugs, so it's recommended to use it always. */ library SafeMath { /** * @dev Returns the addition of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `+` operator. * * Requirements: * - Addition cannot overflow. */ function add(uint256 a, uint256 b) internal pure returns (uint256) { uint256 c = a + b; require(c >= a, 'SafeMath: addition overflow'); return c; } /** * @dev Returns the subtraction of two unsigned integers, reverting on * overflow (when the result is negative). * * Counterpart to Solidity's `-` operator. * * Requirements: * - Subtraction cannot overflow. */ function sub(uint256 a, uint256 b) internal pure returns (uint256) { return sub(a, b, 'SafeMath: subtraction overflow'); } /** * @dev Returns the subtraction of two unsigned integers, reverting with custom message on * overflow (when the result is negative). * * 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); uint256 c = a - b; return c; } /** * @dev Returns the multiplication of two unsigned integers, reverting on * overflow. * * Counterpart to Solidity's `*` operator. * * Requirements: * - Multiplication cannot overflow. */ function mul(uint256 a, uint256 b) internal pure returns (uint256) { // Gas optimization: this is cheaper than requiring 'a' not being zero, but the // benefit is lost if 'b' is also tested. // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 if (a == 0) { return 0; } uint256 c = a * b; require(c / a == b, 'SafeMath: multiplication overflow'); return c; } /** * @dev Returns the integer division of two unsigned integers. Reverts on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div(uint256 a, uint256 b) internal pure returns (uint256) { return div(a, b, 'SafeMath: division by zero'); } /** * @dev Returns the integer division of two unsigned integers. Reverts with custom message on * division by zero. The result is rounded towards zero. * * Counterpart to Solidity's `/` operator. Note: this function uses a * `revert` opcode (which leaves remaining gas untouched) while Solidity * uses an invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function div( uint256 a, uint256 b, string memory errorMessage ) internal pure returns (uint256) { // Solidity only automatically asserts when dividing by 0 require(b > 0, errorMessage); uint256 c = a / b; // assert(a == b * c + a % b); // There is no case in which this doesn't hold return c; } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts when dividing by zero. * * Counterpart to Solidity's `%` operator. This function uses a `revert` * opcode (which leaves remaining gas untouched) while Solidity uses an * invalid opcode to revert (consuming all remaining gas). * * Requirements: * - The divisor cannot be zero. */ function mod(uint256 a, uint256 b) internal pure returns (uint256) { return mod(a, b, 'SafeMath: modulo by zero'); } /** * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), * Reverts with custom message 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, string memory errorMessage ) internal pure returns (uint256) { require(b != 0, errorMessage); return a % b; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; pragma experimental ABIEncoderV2; import {SafeMath} from '../lib/SafeMath.sol'; import {DistributionTypes} from '../lib/DistributionTypes.sol'; import {IAaveDistributionManager} from '../interfaces/IAaveDistributionManager.sol'; /** * @title AaveDistributionManager * @notice Accounting contract to manage multiple staking distributions * @author Aave **/ contract AaveDistributionManager is IAaveDistributionManager { using SafeMath for uint256; struct AssetData { uint128 emissionPerSecond; uint128 lastUpdateTimestamp; uint256 index; mapping(address => uint256) users; } uint256 public immutable DISTRIBUTION_END; address public immutable EMISSION_MANAGER; uint8 public constant PRECISION = 18; mapping(address => AssetData) public assets; event AssetConfigUpdated(address indexed asset, uint256 emission); event AssetIndexUpdated(address indexed asset, uint256 index); event UserIndexUpdated(address indexed user, address indexed asset, uint256 index); constructor(address emissionManager, uint256 distributionDuration) public { DISTRIBUTION_END = block.timestamp.add(distributionDuration); EMISSION_MANAGER = emissionManager; } /** * @dev Configures the distribution of rewards for a list of assets * @param assetsConfigInput The list of configurations to apply **/ function configureAssets(DistributionTypes.AssetConfigInput[] calldata assetsConfigInput) external override { require(msg.sender == EMISSION_MANAGER, 'ONLY_EMISSION_MANAGER'); for (uint256 i = 0; i < assetsConfigInput.length; i++) { AssetData storage assetConfig = assets[assetsConfigInput[i].underlyingAsset]; _updateAssetStateInternal( assetsConfigInput[i].underlyingAsset, assetConfig, assetsConfigInput[i].totalStaked ); assetConfig.emissionPerSecond = assetsConfigInput[i].emissionPerSecond; emit AssetConfigUpdated( assetsConfigInput[i].underlyingAsset, assetsConfigInput[i].emissionPerSecond ); } } /** * @dev Updates the state of one distribution, mainly rewards index and timestamp * @param underlyingAsset The address used as key in the distribution, for example sAAVE or the aTokens addresses on Aave * @param assetConfig Storage pointer to the distribution's config * @param totalStaked Current total of staked assets for this distribution * @return The new distribution index **/ function _updateAssetStateInternal( address underlyingAsset, AssetData storage assetConfig, uint256 totalStaked ) internal returns (uint256) { uint256 oldIndex = assetConfig.index; uint128 lastUpdateTimestamp = assetConfig.lastUpdateTimestamp; if (block.timestamp == lastUpdateTimestamp) { return oldIndex; } uint256 newIndex = _getAssetIndex(oldIndex, assetConfig.emissionPerSecond, lastUpdateTimestamp, totalStaked); if (newIndex != oldIndex) { assetConfig.index = newIndex; emit AssetIndexUpdated(underlyingAsset, newIndex); } assetConfig.lastUpdateTimestamp = uint128(block.timestamp); return newIndex; } /** * @dev Updates the state of an user in a distribution * @param user The user's address * @param asset The address of the reference asset of the distribution * @param stakedByUser Amount of tokens staked by the user in the distribution at the moment * @param totalStaked Total tokens staked in the distribution * @return The accrued rewards for the user until the moment **/ function _updateUserAssetInternal( address user, address asset, uint256 stakedByUser, uint256 totalStaked ) internal returns (uint256) { AssetData storage assetData = assets[asset]; uint256 userIndex = assetData.users[user]; uint256 accruedRewards = 0; uint256 newIndex = _updateAssetStateInternal(asset, assetData, totalStaked); if (userIndex != newIndex) { if (stakedByUser != 0) { accruedRewards = _getRewards(stakedByUser, newIndex, userIndex); } assetData.users[user] = newIndex; emit UserIndexUpdated(user, asset, newIndex); } return accruedRewards; } /** * @dev Used by "frontend" stake contracts to update the data of an user when claiming rewards from there * @param user The address of the user * @param stakes List of structs of the user data related with his stake * @return The accrued rewards for the user until the moment **/ function _claimRewards(address user, DistributionTypes.UserStakeInput[] memory stakes) internal returns (uint256) { uint256 accruedRewards = 0; for (uint256 i = 0; i < stakes.length; i++) { accruedRewards = accruedRewards.add( _updateUserAssetInternal( user, stakes[i].underlyingAsset, stakes[i].stakedByUser, stakes[i].totalStaked ) ); } return accruedRewards; } /** * @dev Return the accrued rewards for an user over a list of distribution * @param user The address of the user * @param stakes List of structs of the user data related with his stake * @return The accrued rewards for the user until the moment **/ function _getUnclaimedRewards(address user, DistributionTypes.UserStakeInput[] memory stakes) internal view returns (uint256) { uint256 accruedRewards = 0; for (uint256 i = 0; i < stakes.length; i++) { AssetData storage assetConfig = assets[stakes[i].underlyingAsset]; uint256 assetIndex = _getAssetIndex( assetConfig.index, assetConfig.emissionPerSecond, assetConfig.lastUpdateTimestamp, stakes[i].totalStaked ); accruedRewards = accruedRewards.add( _getRewards(stakes[i].stakedByUser, assetIndex, assetConfig.users[user]) ); } return accruedRewards; } /** * @dev Internal function for the calculation of user's rewards on a distribution * @param principalUserBalance Amount staked by the user on a distribution * @param reserveIndex Current index of the distribution * @param userIndex Index stored for the user, representation his staking moment * @return The rewards **/ function _getRewards( uint256 principalUserBalance, uint256 reserveIndex, uint256 userIndex ) internal pure returns (uint256) { return principalUserBalance.mul(reserveIndex.sub(userIndex)).div(10**uint256(PRECISION)); } /** * @dev Calculates the next value of an specific distribution index, with validations * @param currentIndex Current index of the distribution * @param emissionPerSecond Representing the total rewards distributed per second per asset unit, on the distribution * @param lastUpdateTimestamp Last moment this distribution was updated * @param totalBalance of tokens considered for the distribution * @return The new index. **/ function _getAssetIndex( uint256 currentIndex, uint256 emissionPerSecond, uint128 lastUpdateTimestamp, uint256 totalBalance ) internal view returns (uint256) { if ( emissionPerSecond == 0 || totalBalance == 0 || lastUpdateTimestamp == block.timestamp || lastUpdateTimestamp >= DISTRIBUTION_END ) { return currentIndex; } uint256 currentTimestamp = block.timestamp > DISTRIBUTION_END ? DISTRIBUTION_END : block.timestamp; uint256 timeDelta = currentTimestamp.sub(lastUpdateTimestamp); return emissionPerSecond.mul(timeDelta).mul(10**uint256(PRECISION)).div(totalBalance).add( currentIndex ); } /** * @dev Returns the data of an user on a distribution * @param user Address of the user * @param asset The address of the reference asset of the distribution * @return The new index **/ function getUserAssetData(address user, address asset) public view returns (uint256) { return assets[asset].users[user]; } }
// SPDX-License-Identifier: agpl-3.0 pragma solidity 0.7.5; /** * @title VersionedInitializable * * @dev Helper contract to support initializer functions. To use it, replace * the constructor with a function that has the `initializer` modifier. * WARNING: Unlike constructors, initializer functions must be manually * invoked. This applies both to deploying an Initializable contract, as well * as extending an Initializable contract via inheritance. * WARNING: When used with inheritance, manual care must be taken to not invoke * a parent initializer twice, or ensure that all initializers are idempotent, * because this is not dealt with automatically as with constructors. * * @author Aave, inspired by the OpenZeppelin Initializable contract */ abstract contract VersionedInitializable { /** * @dev Indicates that the contract has been initialized. */ uint256 internal lastInitializedRevision = 0; /** * @dev Modifier to use in the initializer function of a contract. */ modifier initializer() { uint256 revision = getRevision(); require(revision > lastInitializedRevision, 'Contract instance has already been initialized'); lastInitializedRevision = revision; _; } /// @dev returns the revision number of the contract. /// Needs to be defined in the inherited class as a constant. function getRevision() internal pure virtual returns (uint256); // Reserved storage space to allow for layout changes in the future. uint256[50] private ______gap; }
// SPDX-License-Identifier: MIT pragma solidity 0.7.5; interface IGhoVariableDebtToken { /** * @notice Updates the discount percents of the users when a discount token transfer occurs * @param sender The address of sender * @param recipient The address of recipient * @param senderDiscountTokenBalance The sender discount token balance * @param recipientDiscountTokenBalance The recipient discount token balance * @param amount The amount of discount token being transferred */ function updateDiscountDistribution( address sender, address recipient, uint256 senderDiscountTokenBalance, uint256 recipientDiscountTokenBalance, uint256 amount ) external; }
{ "evmVersion": "istanbul", "libraries": {}, "metadata": { "bytecodeHash": "ipfs", "useLiteralContent": true }, "optimizer": { "enabled": true, "runs": 200 }, "remappings": [], "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } } }
[{"inputs":[{"internalType":"contract IERC20","name":"stakedToken","type":"address"},{"internalType":"contract IERC20","name":"rewardToken","type":"address"},{"internalType":"uint256","name":"cooldownSeconds","type":"uint256"},{"internalType":"uint256","name":"unstakeWindow","type":"uint256"},{"internalType":"address","name":"rewardsVault","type":"address"},{"internalType":"address","name":"emissionManager","type":"address"},{"internalType":"uint128","name":"distributionDuration","type":"uint128"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"address","name":"governance","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"emission","type":"uint256"}],"name":"AssetConfigUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"AssetIndexUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"}],"name":"Cooldown","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"delegatee","type":"address"},{"indexed":false,"internalType":"enum IGovernancePowerDelegationToken.DelegationType","name":"delegationType","type":"uint8"}],"name":"DelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"enum IGovernancePowerDelegationToken.DelegationType","name":"delegationType","type":"uint8"}],"name":"DelegatedPowerChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Redeem","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsAccrued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RewardsClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"onBehalfOf","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"index","type":"uint256"}],"name":"UserIndexUpdated","type":"event"},{"inputs":[],"name":"COOLDOWN_SECONDS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELEGATE_BY_TYPE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DELEGATE_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISTRIBUTION_END","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EIP712_REVISION","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMISSION_MANAGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRECISION","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REVISION","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARDS_VAULT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_TOKEN","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"STAKED_TOKEN","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNSTAKE_WINDOW","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"_aaveGovernance","outputs":[{"internalType":"contract ITransferHook","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"_votingSnapshots","outputs":[{"internalType":"uint128","name":"blockNumber","type":"uint128"},{"internalType":"uint128","name":"value","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"_votingSnapshotsCounts","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"assets","outputs":[{"internalType":"uint128","name":"emissionPerSecond","type":"uint128"},{"internalType":"uint128","name":"lastUpdateTimestamp","type":"uint128"},{"internalType":"uint256","name":"index","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"claimRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint128","name":"emissionPerSecond","type":"uint128"},{"internalType":"uint256","name":"totalStaked","type":"uint256"},{"internalType":"address","name":"underlyingAsset","type":"address"}],"internalType":"struct DistributionTypes.AssetConfigInput[]","name":"assetsConfigInput","type":"tuple[]"}],"name":"configureAssets","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cooldown","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"enum IGovernancePowerDelegationToken.DelegationType","name":"delegationType","type":"uint8"}],"name":"delegateByType","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"enum IGovernancePowerDelegationToken.DelegationType","name":"delegationType","type":"uint8"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateByTypeBySig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegator","type":"address"},{"internalType":"enum IGovernancePowerDelegationToken.DelegationType","name":"delegationType","type":"uint8"}],"name":"getDelegateeByType","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"fromCooldownTimestamp","type":"uint256"},{"internalType":"uint256","name":"amountToReceive","type":"uint256"},{"internalType":"address","name":"toAddress","type":"address"},{"internalType":"uint256","name":"toBalance","type":"uint256"}],"name":"getNextCooldownTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"blockNumber","type":"uint256"},{"internalType":"enum IGovernancePowerDelegationToken.DelegationType","name":"delegationType","type":"uint8"}],"name":"getPowerAtBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"enum IGovernancePowerDelegationToken.DelegationType","name":"delegationType","type":"uint8"}],"name":"getPowerCurrent","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"staker","type":"address"}],"name":"getTotalRewardsBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"asset","type":"address"}],"name":"getUserAssetData","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ghoDebtToken","outputs":[{"internalType":"contract IGhoVariableDebtToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ghoDebtToken","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"onBehalfOf","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakerRewardsToClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"stakersCooldowns","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"name":"totalSupplyAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
61016060405260006009553480156200001757600080fd5b5060405162003e2038038062003e208339810160408190526200003a916200032d565b85856001600160801b0316858581600390805190602001906200005f92919062000197565b5080516200007590600490602084019062000197565b505060058054601260ff19909116179055506200009f42826200011f602090811b620019c817901c565b60805250606090811b6001600160601b031990811660a0528c821b811660c0528b821b811660e0526101008b90526101208a90529088901b1661014052600880546001600160a01b0319166001600160a01b0383161790556200010e8262000181602090811b62001a2217901c565b505050505050505050505062000434565b6000828201838110156200017a576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b9392505050565b6005805460ff191660ff92909216919091179055565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282620001cf57600085556200021a565b82601f10620001ea57805160ff19168380011785556200021a565b828001600101855582156200021a579182015b828111156200021a578251825591602001919060010190620001fd565b50620002289291506200022c565b5090565b5b808211156200022857600081556001016200022d565b80516001600160a01b03811681146200025b57600080fd5b919050565b600082601f83011262000271578081fd5b81516001600160401b03808211156200028657fe5b6040516020601f8401601f1916820181018381118382101715620002a657fe5b80604052508194508382528681858801011115620002c357600080fd5b600092505b83831015620002e75785830181015182840182015291820191620002c8565b83831115620002f95760008185840101525b5050505092915050565b80516001600160801b03811681146200025b57600080fd5b805160ff811681146200025b57600080fd5b60008060008060008060008060008060006101608c8e0312156200034f578687fd5b6200035a8c62000243565b9a506200036a60208d0162000243565b995060408c0151985060608c015197506200038860808d0162000243565b96506200039860a08d0162000243565b9550620003a860c08d0162000303565b60e08d01519095506001600160401b03811115620003c4578485fd5b620003d28e828f0162000260565b6101008e015190955090506001600160401b03811115620003f1578384fd5b620003ff8e828f0162000260565b935050620004116101208d016200031b565b9150620004226101408d0162000243565b90509295989b509295989b9093969950565b60805160a05160601c60c05160601c60e05160601c61010051610120516101405160601c61394b620004d560003980610cb45280610e0c52508061079c52806109f4528061178552508061075852806107c45280610b1d52806117aa525080610d435280610de252508061087052806109975280611022525080611098528061153a525080610c905280612d865280612dc25280612def525061394b6000f3fe608060405234801561001057600080fd5b50600436106102f15760003560e01c8063919cd40f1161019d578063b9844d8d116100e9578063d505accf116100a2578063dde43cba1161007c578063dde43cba146105f1578063f11b8188146105f9578063f1cc432a1461061b578063f713d8a81461062e576102f1565b8063d505accf146105b8578063dc937e1c146105cb578063dd62ed3e146105de576102f1565b8063b9844d8d1461055c578063c2ffbb911461056f578063c3863ada14610582578063c3cda5201461058a578063c4d66de81461059d578063cbcbb507146105b0576102f1565b8063a457c2d711610156578063aaf5eb6811610130578063aaf5eb681461051b578063adc9772e14610523578063b2a5dbfa14610536578063b2f4201d14610549576102f1565b8063a457c2d7146104ed578063a9059cbb14610500578063aa9fbe0214610513576102f1565b8063919cd40f146104a7578063946776cd146104af57806395d89b41146104b7578063981b24d0146104bf57806399248ea7146104d25780639a99b4f0146104da576102f1565b80633644e5151161025c57806370a0823111610215578063787a08a6116101ef578063787a08a6146104665780637bb73c971461046e5780637e90d7ef146104815780638dbefee214610494576102f1565b806370a082311461044357806372b49d6314610456578063781603761461045e576102f1565b80633644e515146103d957806339509351146103e157806341cbf54a146103f45780635b3cc0cf146103fc5780635c19a95c1461041d5780636f50458d14610430576102f1565b806323b872dd116102ae57806323b872dd1461038657806330adf81f14610399578063312f6b83146103a1578063313ce567146103a95780633373ee4c146103be578063359c4a96146103d1576102f1565b806306fdde03146102f6578063091030c314610314578063095ea7b314610334578063174ed5421461035457806318160ddd146103695780631e9a695014610371575b600080fd5b6102fe610641565b60405161030b9190613547565b60405180910390f35b61032761032236600461308d565b6106d7565b60405161030b9190613470565b6103476103423660046131d7565b6106e9565b60405161030b9190613465565b61035c610707565b60405161030b91906133e3565b610327610716565b61038461037f3660046131d7565b61071c565b005b6103476103943660046130d9565b6108e9565b610327610971565b61035c610995565b6103b16109b9565b60405161030b919061374a565b6103276103cc3660046130a7565b6109c2565b6103276109f2565b610327610a16565b6103476103ef3660046131d7565b610a1c565b610327610a6a565b61040f61040a3660046131d7565b610a8e565b60405161030b92919061370c565b61038461042b36600461308d565b610abf565b61035c61043e36600461317d565b610ada565b61032761045136600461308d565b610afc565b610327610b1b565b6102fe610b3f565b610384610b5c565b61032761047c36600461308d565b610bbb565b61032761048f36600461308d565b610bcd565b6103276104a236600461308d565b610bdf565b610327610c8e565b61035c610cb2565b6102fe610cd6565b6103276104cd366004613329565b610d37565b61035c610d41565b6103846104e83660046131d7565b610d65565b6103476104fb3660046131d7565b610e83565b61034761050e3660046131d7565b610eeb565b610327610eff565b6103b1610f23565b6103846105313660046131d7565b610f28565b610384610544366004613292565b61108d565b61032761055736600461317d565b611240565b61032761056a36600461308d565b611268565b61032761057d366004613200565b61127a565b61035c6112a3565b61038461059836600461323b565b6112b2565b6103846105ab36600461308d565b61142e565b61035c611538565b6103846105c6366004613114565b61155c565b6103846105d936600461317d565b6116e9565b6103276105ec3660046130a7565b6116f8565b610327611723565b61060c61060736600461308d565b611728565b60405161030b93929190613726565b610327610629366004613341565b611756565b61038461063c3660046131a6565b61184b565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106cd5780601f106106a2576101008083540402835291602001916106cd565b820191906000526020600020905b8154815290600101906020018083116106b057829003601f168201915b5050505050905090565b603e6020526000908152604090205481565b60006106fd6106f6611a38565b8484611a3c565b5060015b92915050565b6045546001600160a01b031681565b60025490565b806107425760405162461bcd60e51b81526004016107399061355a565b60405180910390fd5b336000908152603e602052604090205461077c817f00000000000000000000000000000000000000000000000000000000000000006119c8565b421161079a5760405162461bcd60e51b8152600401610739906135b2565b7f00000000000000000000000000000000000000000000000000000000000000006107ef6107e8837f00000000000000000000000000000000000000000000000000000000000000006119c8565b4290611b28565b111561080d5760405162461bcd60e51b81526004016107399061368a565b600061081833610afc565b90506000818411610829578361082b565b815b905061083933836001611b6a565b506108443382611c0e565b61084e8282611b28565b61086357336000908152603e60205260408120555b6108976001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000168683611d0a565b846001600160a01b0316336001600160a01b03167fd12200efa34901b99367694174c3b0d32c99585fdf37c7c26892136ddd0836d9836040516108da9190613470565b60405180910390a35050505050565b60006108f6848484611d5c565b61096684610902611a38565b61096185604051806060016040528060288152602001613807602891396001600160a01b038a16600090815260016020526040812090610940611a38565b6001600160a01b031681526020810191909152604001600020549190611e28565b611a3c565b5060015b9392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b7f000000000000000000000000000000000000000000000000000000000000000081565b60055460ff1690565b6001600160a01b038082166000908152603c60209081526040808320938616835260029093019052205492915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60435481565b60006106fd610a29611a38565b846109618560016000610a3a611a38565b6001600160a01b03908116825260208083019390935260409182016000908120918c1681529252902054906119c8565b7f9a9a49b990ba9bb39f8048c490a40ab25c18f55d208d5fbcf958261a9b48716d81565b60066020908152600092835260408084209091529082529020546001600160801b0380821691600160801b90041682565b610acb33826000611ebf565b610ad733826001611ebf565b50565b600080610ae683611fd0565b92505050610af4848261200a565b949350505050565b6001600160a01b0381166000908152602081905260409020545b919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b604051806040016040528060018152602001603160f81b81525081565b610b6533610afc565b610b815760405162461bcd60e51b8152600401610739906136c1565b336000818152603e6020526040808220429055517ff52f50426b32362d3e6bb8cb36b7074756b224622def6352a59eac7f66ebe6e89190a2565b60076020526000908152604090205481565b603d6020526000908152604090205481565b60408051600180825281830190925260009160609190816020015b610c02613015565b815260200190600190039081610bfa5790505090506040518060600160405280306001600160a01b03168152602001610c3a85610afc565b8152602001610c47610716565b81525081600081518110610c5757fe5b602002602001018190525061096a610c6f8483612035565b6001600160a01b0385166000908152603d6020526040902054906119c8565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106cd5780601f106106a2576101008083540402835291602001916106cd565b6000610701610716565b7f000000000000000000000000000000000000000000000000000000000000000081565b6000610d7b33610d7433610afc565b6000611b6a565b905060006000198314610d8e5782610d90565b815b9050610dcd816040518060400160405280600e81526020016d1253959053125117d05353d5539560921b81525084611e289092919063ffffffff16565b336000908152603d6020526040902055610e327f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03167f00000000000000000000000000000000000000000000000000000000000000008684612126565b836001600160a01b0316336001600160a01b03167f9310ccfcb8de723f578a9e4282ea9f521f05ae40dc08f3068dfad528a65ee3c783604051610e759190613470565b60405180910390a350505050565b60006106fd610e90611a38565b84610961856040518060600160405280602581526020016138f16025913960016000610eba611a38565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190611e28565b60006106fd610ef8611a38565b8484611d5c565b7f10d8d059343739efce7dad10d09f0806da52b252b3e6a7951920d2d6ec4102e581565b601281565b80610f455760405162461bcd60e51b81526004016107399061355a565b6000610f5083610afc565b90506000610f67843084610f62610716565b612180565b90508015610fe5577f2468f9268c60ad90e2d49edb0032c8a001e733ae888b3ab8e982edf535be1a768482604051610fa092919061344c565b60405180910390a16001600160a01b0384166000908152603d6020526040902054610fcb90826119c8565b6001600160a01b0385166000908152603d60205260409020555b610ff26000848685611756565b6001600160a01b0385166000908152603e6020526040902055611015848461223f565b61104a6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016333086612126565b836001600160a01b0316336001600160a01b03167f5dac0c1b1112564a045ba943c9d50270893e8e826c49be8e7073adc713ab7bd785604051610e759190613470565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146110d55760405162461bcd60e51b815260040161073990613634565b60005b8181101561123b576000603c60008585858181106110f257fe5b905060600201604001602081019061110a919061308d565b6001600160a01b03166001600160a01b03168152602001908152602001600020905061116f84848481811061113b57fe5b9050606002016040016020810190611153919061308d565b8286868681811061116057fe5b9050606002016020013561232f565b5083838381811061117c57fe5b6111929260206060909202019081019150613302565b81546001600160801b0319166001600160801b03919091161781558383838181106111b957fe5b90506060020160400160208101906111d1919061308d565b6001600160a01b03167f87fa03892a0556cb6b8f97e6d533a150d4d55fcbf275fff5fa003fa636bcc7fa85858581811061120757fe5b61121d9260206060909202019081019150613302565b60405161122a91906136f8565b60405180910390a2506001016110d8565b505050565b600080600061124e84611fd0565b509150915061125f828287436123ec565b95945050505050565b60446020526000908152604090205481565b600080600061128884611fd0565b5091509150611299828288886123ec565b9695505050505050565b6008546001600160a01b031681565b60007f9a9a49b990ba9bb39f8048c490a40ab25c18f55d208d5fbcf958261a9b48716d8787876040516020016112eb94939291906134ad565b60405160208183030381529060405280519060200120905060006043548260405160200161131a9291906133c8565b6040516020818303038152906040528051906020012090506000600182878787604051600081526020016040526040516113579493929190613529565b6020604051602081039080840390855afa158015611379573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166113ac5760405162461bcd60e51b815260040161073990613587565b6001600160a01b038116600090815260446020526040902080546001810190915588146113eb5760405162461bcd60e51b81526004016107399061360d565b8642111561140b5760405162461bcd60e51b8152600401610739906135e1565b611417818a6000611ebf565b611423818a6001611ebf565b505050505050505050565b6000611438612608565b9050600954811161147a5760405162461bcd60e51b815260040180806020018281038252602e81526020018061382f602e913960400191505060405180910390fd5b6009819055467f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6114a9610641565b805160209182012060408051808201825260018152603160f81b90840152516114f993927fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69186913091016134fd565b60408051808303601f1901815291905280516020909101206043555050604580546001600160a01b0319166001600160a01b0392909216919091179055565b7f000000000000000000000000000000000000000000000000000000000000000081565b6001600160a01b0387166115825760405162461bcd60e51b815260040161073990613663565b834211156115a25760405162461bcd60e51b8152600401610739906135e1565b6001600160a01b03871660009081526044602090815260408083205460435491519093926115fc917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918d918d918d9189918e9101613479565b604051602081830303815290604052805190602001206040516020016116239291906133c8565b6040516020818303038152906040528051906020012090506001818686866040516000815260200160405260405161165e9493929190613529565b6020604051602081039080840390855afa158015611680573d6000803e3d6000fd5b505050602060405103516001600160a01b0316896001600160a01b0316146116ba5760405162461bcd60e51b815260040161073990613587565b6116c58260016119c8565b6001600160a01b038a16600090815260446020526040902055611423898989611a3c565b6116f4338383611ebf565b5050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600481565b603c60205260009081526040902080546001909101546001600160801b0380831692600160801b9004169083565b6001600160a01b0382166000908152603e60205260408120548061177e576000915050610af4565b60006117d47f00000000000000000000000000000000000000000000000000000000000000006117ce427f0000000000000000000000000000000000000000000000000000000000000000611b28565b90611b28565b9050818111156117e75760009150611841565b60008782116117f657876117f8565b425b90508281101561180d57829350505050610af4565b61183d61181a88876119c8565b611837611827888761260d565b6118318b8661260d565b906119c8565b90612666565b9250505b5095945050505050565b60007f10d8d059343739efce7dad10d09f0806da52b252b3e6a7951920d2d6ec4102e58888600181111561187b57fe5b88886040516020016118919594939291906134d1565b6040516020818303038152906040528051906020012090506000604354826040516020016118c09291906133c8565b6040516020818303038152906040528051906020012090506000600182878787604051600081526020016040526040516118fd9493929190613529565b6020604051602081039080840390855afa15801561191f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166119525760405162461bcd60e51b815260040161073990613587565b6001600160a01b038116600090815260446020526040902080546001810190915588146119915760405162461bcd60e51b81526004016107399061360d565b864211156119b15760405162461bcd60e51b8152600401610739906135e1565b6119bc818b8b611ebf565b50505050505050505050565b60008282018381101561096a576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6005805460ff191660ff92909216919091179055565b3390565b6001600160a01b038316611a815760405162461bcd60e51b81526004018080602001828103825260248152602001806138a36024913960400191505060405180910390fd5b6001600160a01b038216611ac65760405162461bcd60e51b815260040180806020018281038252602281526020018061379e6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b600061096a83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611e28565b600080611b7b853086610f62610716565b6001600160a01b0386166000908152603d602052604081205491925090611ba290836119c8565b9050811561125f578315611bcc576001600160a01b0386166000908152603d602052604090208190555b7f2468f9268c60ad90e2d49edb0032c8a001e733ae888b3ab8e982edf535be1a768683604051611bfd92919061344c565b60405180910390a195945050505050565b6001600160a01b038216611c535760405162461bcd60e51b815260040180806020018281038252602181526020018061385d6021913960400191505060405180910390fd5b611c5f826000836126a8565b611c9c8160405180606001604052806022815260200161377c602291396001600160a01b0385166000908152602081905260409020549190611e28565b6001600160a01b038316600090815260208190526040902055600254611cc29082611b28565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261123b90849061283d565b6000611d6784610afc565b9050611d7584826001611b6a565b50826001600160a01b0316846001600160a01b031614611e17576000611d9a84610afc565b9050611da884826001611b6a565b506001600160a01b0385166000908152603e6020526040902054611dce81858785611756565b6001600160a01b0386166000908152603e60205260409020558284148015611df557508015155b15611e14576001600160a01b0386166000908152603e60205260408120555b50505b611e228484846129f5565b50505050565b60008184841115611eb75760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611e7c578181015183820152602001611e64565b50505050905090810190601f168015611ea95780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b038216611f0e576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f44454c45474154454560781b604482015290519081900360640190fd5b6000611f1982611fd0565b925050506000611f2885610afc565b90506000611f36868461200a565b6001600160a01b03878116600090815260208690526040902080546001600160a01b0319169188169190911790559050611f7281868487612b50565b846001600160a01b0316866001600160a01b03167fe8d51c8e11bd570db1734c8ec775785330e77007feed45c43b608ef33ff914bd8660405180826001811115611fb857fe5b815260200191505060405180910390a3505050505050565b6000808080846001811115611fe157fe5b1415611ff757506006915060079050603f612003565b50604091506041905060425b9193909250565b6001600160a01b038083166000908152602083905260408120549091168061096a5783915050610701565b600080805b835181101561211e576000603c600086848151811061205557fe5b602090810291909101810151516001600160a01b0316825281019190915260400160009081206001810154815488519294506120bd926001600160801b0380831692600160801b900416908a90889081106120ac57fe5b602002602001015160400151612d5e565b905061211261210b8785815181106120d157fe5b602002602001015160200151838560020160008c6001600160a01b03166001600160a01b0316815260200190815260200160002054612e57565b85906119c8565b9350505060010161203a565b509392505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611e2290859061283d565b6001600160a01b038084166000908152603c6020908152604080832093881683526002840190915281205490919082806121bb88858861232f565b90508083146122335786156121d8576121d5878285612e57565b91505b6001600160a01b03808a1660008181526002870160205260409081902084905551918a16917fbb123b5c06d5408bbea3c4fef481578175cfb432e3b482c6186f02ed9086585b9061222a908590613470565b60405180910390a35b50979650505050505050565b6001600160a01b03821661229a576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6122a6600083836126a8565b6002546122b390826119c8565b6002556001600160a01b0382166000908152602081905260409020546122d990826119c8565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001820154825460009190600160801b90046001600160801b03164281141561235a5750905061096a565b84546000906123759084906001600160801b03168488612d5e565b90508281146123c957808660010181905550866001600160a01b03167f5777ca300dfe5bead41006fbce4389794dbc0ed8d6cccebfaf94630aa04184bc826040516123c09190613470565b60405180910390a25b85546001600160801b03428116600160801b029116178655925050509392505050565b60004382111561243a576040805162461bcd60e51b815260206004820152601460248201527324a72b20a624a22fa12627a1a5afa72aa6a122a960611b604482015290519081900360640190fd5b6001600160a01b038316600090815260208590526040902054806124695761246184610afc565b915050610af4565b6001600160a01b038416600090815260208781526040808320600019850184529091529020546001600160801b031683106124dc576001600160a01b038416600090815260208781526040808320600019909401835292905220546001600160801b03600160801b909104169050610af4565b6001600160a01b0384166000908152602087815260408083208380529091529020546001600160801b0316831015612518576000915050610af4565b600060001982015b818111156125ca57600282820304810361253861303f565b506001600160a01b038716600090815260208a815260408083208484528252918290208251808401909352546001600160801b03808216808552600160801b90920416918301919091528714156125a257602001516001600160801b03169450610af49350505050565b80516001600160801b03168711156125bc578193506125c3565b6001820392505b5050612520565b506001600160a01b03851660009081526020888152604080832093835292905220546001600160801b03600160801b90910416915050949350505050565b600490565b60008261261c57506000610701565b8282028284828161262957fe5b041461096a5760405162461bcd60e51b81526004018080602001828103825260218152602001806137e66021913960400191505060405180910390fd5b600061096a83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612e79565b6045546001600160a01b0316635b9c4cf184846126c482610afc565b6126cd87610afc565b866040518663ffffffff1660e01b81526004016126ee95949392919061341b565b600060405180830381600087803b15801561270857600080fd5b505af115801561271c573d6000803e3d6000fd5b5050506001600160a01b038085166000908152603f602052604080822054868416835291205490821692501681612751578491505b6001600160a01b0381166127625750825b61276f8282856000612b50565b6001600160a01b038086166000908152604260205260408082205487841683529120549082169116816127a0578691505b6001600160a01b0381166127b15750845b6127be8282876001612b50565b6008546001600160a01b0316801561283357604051634a39314960e01b81526001600160a01b03821690634a39314990612800908b908b908b906004016133f7565b600060405180830381600087803b15801561281a57600080fd5b505af115801561282e573d6000803e3d6000fd5b505050505b5050505050505050565b61284f826001600160a01b0316612ede565b6128a0576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106128de5780518252601f1990920191602091820191016128bf565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612940576040519150601f19603f3d011682016040523d82523d6000602084013e612945565b606091505b50915091508161299c576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115611e22578080602001905160208110156129b857600080fd5b5051611e225760405162461bcd60e51b815260040180806020018281038252602a8152602001806138c7602a913960400191505060405180910390fd5b6001600160a01b038316612a3a5760405162461bcd60e51b815260040180806020018281038252602581526020018061387e6025913960400191505060405180910390fd5b6001600160a01b038216612a7f5760405162461bcd60e51b81526004018080602001828103825260238152602001806137596023913960400191505060405180910390fd5b612a8a8383836126a8565b612ac7816040518060600160405280602681526020016137c0602691396001600160a01b0386166000908152602081905260409020549190611e28565b6001600160a01b038085166000908152602081905260408082209390935590841681522054612af690826119c8565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b826001600160a01b0316846001600160a01b03161415612b6f57611e22565b600080612b7b83611fd0565b5090925090506001600160a01b03861615612c6e576001600160a01b0386166000908152602082905260408120548015612bec576001600160a01b03881660009081526020858152604080832060001985018452909152902054600160801b90046001600160801b03169150612bf8565b612bf588610afc565b91505b612c0e84848a85612c09818c611b28565b612f17565b6001600160a01b0388167fa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f612c438489611b28565b8760405180838152602001826001811115612c5a57fe5b81526020019250505060405180910390a250505b6001600160a01b03851615612d56576001600160a01b0385166000908152602082905260408120548015612cd9576001600160a01b03871660009081526020858152604080832060001985018452909152902054600160801b90046001600160801b03169150612ce5565b612ce287610afc565b91505b612cf684848985612c09818c6119c8565b6001600160a01b0387167fa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f612d2b84896119c8565b8760405180838152602001826001811115612d4257fe5b81526020019250505060405180910390a250505b505050505050565b6000831580612d6b575081155b80612d7e575042836001600160801b0316145b80612db257507f0000000000000000000000000000000000000000000000000000000000000000836001600160801b031610155b15612dbe575083610af4565b60007f00000000000000000000000000000000000000000000000000000000000000004211612ded5742612e0f565b7f00000000000000000000000000000000000000000000000000000000000000005b90506000612e26826001600160801b038716611b28565b9050612e4c8761183186611837670de0b6b3a7640000612e468c8861260d565b9061260d565b979650505050505050565b6000610af4670de0b6b3a7640000611837612e728686611b28565b879061260d565b60008183612ec85760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611e7c578181015183820152602001611e64565b506000838581612ed457fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610af4575050151592915050565b6001600160a01b03831660009081526020858152604080832054918890529091204391908115801590612f68575060001982016000908152602082905260409020546001600160801b038481169116145b15612f9d576000198201600090815260208290526040902080546001600160801b03808716600160801b029116179055612833565b6040805180820182526001600160801b038086168252868116602080840191825260008781528682528581209451855493518516600160801b029085166001600160801b031990941693909317909316919091179092556001600160a01b038916815290899052206001830190555050505050505050565b604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b604080518082019091526000808252602082015290565b80356001600160a01b0381168114610b1657600080fd5b803560028110610b1657600080fd5b803560ff81168114610b1657600080fd5b60006020828403121561309e578081fd5b61096a82613056565b600080604083850312156130b9578081fd5b6130c283613056565b91506130d060208401613056565b90509250929050565b6000806000606084860312156130ed578081fd5b6130f684613056565b925061310460208501613056565b9150604084013590509250925092565b600080600080600080600060e0888a03121561312e578283fd5b61313788613056565b965061314560208901613056565b955060408801359450606088013593506131616080890161307c565b925060a0880135915060c0880135905092959891949750929550565b6000806040838503121561318f578182fd5b61319883613056565b91506130d06020840161306d565b600080600080600080600060e0888a0312156131c0578283fd5b6131c988613056565b96506131456020890161306d565b600080604083850312156131e9578182fd5b6131f283613056565b946020939093013593505050565b600080600060608486031215613214578283fd5b61321d84613056565b9250602084013591506132326040850161306d565b90509250925092565b60008060008060008060c08789031215613253578182fd5b61325c87613056565b955060208701359450604087013593506132786060880161307c565b92506080870135915060a087013590509295509295509295565b600080602083850312156132a4578182fd5b823567ffffffffffffffff808211156132bb578384fd5b818501915085601f8301126132ce578384fd5b8135818111156132dc578485fd5b8660206060830285010111156132f0578485fd5b60209290920196919550909350505050565b600060208284031215613313578081fd5b81356001600160801b038116811461096a578182fd5b60006020828403121561333a578081fd5b5035919050565b60008060008060808587031215613356578182fd5b843593506020850135925061336d60408601613056565b9396929550929360600135925050565b60008151808452815b818110156133a257602081850181015186830182015201613386565b818111156133b35782602083870101525b50601f01601f19169290920160200192915050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03958616815293909416602084015260408301919091526060820152608081019190915260a00190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9384526001600160a01b039290921660208401526040830152606082015260800190565b9485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b60006020825261096a602083018461337d565b6020808252601390820152721253959053125117d6915493d7d05353d55395606a1b604082015260600190565b602080825260119082015270494e56414c49445f5349474e415455524560781b604082015260600190565b60208082526015908201527424a729aaa32324a1a4a2a72a2fa1a7a7a62227aba760591b604082015260600190565b60208082526012908201527124a72b20a624a22fa2ac2824a920aa24a7a760711b604082015260600190565b6020808252600d908201526c494e56414c49445f4e4f4e434560981b604082015260600190565b60208082526015908201527427a7262cafa2a6a4a9a9a4a7a72fa6a0a720a3a2a960591b604082015260600190565b6020808252600d908201526c24a72b20a624a22fa7aba722a960991b604082015260600190565b60208082526017908201527f554e5354414b455f57494e444f575f46494e4953484544000000000000000000604082015260600190565b6020808252601b908201527f494e56414c49445f42414c414e43455f4f4e5f434f4f4c444f574e0000000000604082015260600190565b6001600160801b0391909116815260200190565b6001600160801b0392831681529116602082015260400190565b6001600160801b039384168152919092166020820152604081019190915260600190565b60ff9190911681526020019056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a656445524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220e2d4cb1976f0cbe264a62c15819b021ca2e8bd26aed3ff0e3a1f2d4beb4427fa64736f6c63430007050033000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd0000000000000000000000000000000000000000000000000000000000000e1000000000000000000000000000000000000000000000000000000000000007080000000000000000000000002892e37624ec31cc42502f2978211097002709710000000000000000000000002892e37624ec31cc42502f29782110970027097100000000000000000000000000000000000000000000000000000000bbf81e00000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5374616b65642041415645000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000773746b4141564500000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106102f15760003560e01c8063919cd40f1161019d578063b9844d8d116100e9578063d505accf116100a2578063dde43cba1161007c578063dde43cba146105f1578063f11b8188146105f9578063f1cc432a1461061b578063f713d8a81461062e576102f1565b8063d505accf146105b8578063dc937e1c146105cb578063dd62ed3e146105de576102f1565b8063b9844d8d1461055c578063c2ffbb911461056f578063c3863ada14610582578063c3cda5201461058a578063c4d66de81461059d578063cbcbb507146105b0576102f1565b8063a457c2d711610156578063aaf5eb6811610130578063aaf5eb681461051b578063adc9772e14610523578063b2a5dbfa14610536578063b2f4201d14610549576102f1565b8063a457c2d7146104ed578063a9059cbb14610500578063aa9fbe0214610513576102f1565b8063919cd40f146104a7578063946776cd146104af57806395d89b41146104b7578063981b24d0146104bf57806399248ea7146104d25780639a99b4f0146104da576102f1565b80633644e5151161025c57806370a0823111610215578063787a08a6116101ef578063787a08a6146104665780637bb73c971461046e5780637e90d7ef146104815780638dbefee214610494576102f1565b806370a082311461044357806372b49d6314610456578063781603761461045e576102f1565b80633644e515146103d957806339509351146103e157806341cbf54a146103f45780635b3cc0cf146103fc5780635c19a95c1461041d5780636f50458d14610430576102f1565b806323b872dd116102ae57806323b872dd1461038657806330adf81f14610399578063312f6b83146103a1578063313ce567146103a95780633373ee4c146103be578063359c4a96146103d1576102f1565b806306fdde03146102f6578063091030c314610314578063095ea7b314610334578063174ed5421461035457806318160ddd146103695780631e9a695014610371575b600080fd5b6102fe610641565b60405161030b9190613547565b60405180910390f35b61032761032236600461308d565b6106d7565b60405161030b9190613470565b6103476103423660046131d7565b6106e9565b60405161030b9190613465565b61035c610707565b60405161030b91906133e3565b610327610716565b61038461037f3660046131d7565b61071c565b005b6103476103943660046130d9565b6108e9565b610327610971565b61035c610995565b6103b16109b9565b60405161030b919061374a565b6103276103cc3660046130a7565b6109c2565b6103276109f2565b610327610a16565b6103476103ef3660046131d7565b610a1c565b610327610a6a565b61040f61040a3660046131d7565b610a8e565b60405161030b92919061370c565b61038461042b36600461308d565b610abf565b61035c61043e36600461317d565b610ada565b61032761045136600461308d565b610afc565b610327610b1b565b6102fe610b3f565b610384610b5c565b61032761047c36600461308d565b610bbb565b61032761048f36600461308d565b610bcd565b6103276104a236600461308d565b610bdf565b610327610c8e565b61035c610cb2565b6102fe610cd6565b6103276104cd366004613329565b610d37565b61035c610d41565b6103846104e83660046131d7565b610d65565b6103476104fb3660046131d7565b610e83565b61034761050e3660046131d7565b610eeb565b610327610eff565b6103b1610f23565b6103846105313660046131d7565b610f28565b610384610544366004613292565b61108d565b61032761055736600461317d565b611240565b61032761056a36600461308d565b611268565b61032761057d366004613200565b61127a565b61035c6112a3565b61038461059836600461323b565b6112b2565b6103846105ab36600461308d565b61142e565b61035c611538565b6103846105c6366004613114565b61155c565b6103846105d936600461317d565b6116e9565b6103276105ec3660046130a7565b6116f8565b610327611723565b61060c61060736600461308d565b611728565b60405161030b93929190613726565b610327610629366004613341565b611756565b61038461063c3660046131a6565b61184b565b60038054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106cd5780601f106106a2576101008083540402835291602001916106cd565b820191906000526020600020905b8154815290600101906020018083116106b057829003601f168201915b5050505050905090565b603e6020526000908152604090205481565b60006106fd6106f6611a38565b8484611a3c565b5060015b92915050565b6045546001600160a01b031681565b60025490565b806107425760405162461bcd60e51b81526004016107399061355a565b60405180910390fd5b336000908152603e602052604090205461077c817f0000000000000000000000000000000000000000000000000000000000000e106119c8565b421161079a5760405162461bcd60e51b8152600401610739906135b2565b7f00000000000000000000000000000000000000000000000000000000000007086107ef6107e8837f0000000000000000000000000000000000000000000000000000000000000e106119c8565b4290611b28565b111561080d5760405162461bcd60e51b81526004016107399061368a565b600061081833610afc565b90506000818411610829578361082b565b815b905061083933836001611b6a565b506108443382611c0e565b61084e8282611b28565b61086357336000908152603e60205260408120555b6108976001600160a01b037f000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd168683611d0a565b846001600160a01b0316336001600160a01b03167fd12200efa34901b99367694174c3b0d32c99585fdf37c7c26892136ddd0836d9836040516108da9190613470565b60405180910390a35050505050565b60006108f6848484611d5c565b61096684610902611a38565b61096185604051806060016040528060288152602001613807602891396001600160a01b038a16600090815260016020526040812090610940611a38565b6001600160a01b031681526020810191909152604001600020549190611e28565b611a3c565b5060015b9392505050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b7f000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd81565b60055460ff1690565b6001600160a01b038082166000908152603c60209081526040808320938616835260029093019052205492915050565b7f000000000000000000000000000000000000000000000000000000000000070881565b60435481565b60006106fd610a29611a38565b846109618560016000610a3a611a38565b6001600160a01b03908116825260208083019390935260409182016000908120918c1681529252902054906119c8565b7f9a9a49b990ba9bb39f8048c490a40ab25c18f55d208d5fbcf958261a9b48716d81565b60066020908152600092835260408084209091529082529020546001600160801b0380821691600160801b90041682565b610acb33826000611ebf565b610ad733826001611ebf565b50565b600080610ae683611fd0565b92505050610af4848261200a565b949350505050565b6001600160a01b0381166000908152602081905260409020545b919050565b7f0000000000000000000000000000000000000000000000000000000000000e1081565b604051806040016040528060018152602001603160f81b81525081565b610b6533610afc565b610b815760405162461bcd60e51b8152600401610739906136c1565b336000818152603e6020526040808220429055517ff52f50426b32362d3e6bb8cb36b7074756b224622def6352a59eac7f66ebe6e89190a2565b60076020526000908152604090205481565b603d6020526000908152604090205481565b60408051600180825281830190925260009160609190816020015b610c02613015565b815260200190600190039081610bfa5790505090506040518060600160405280306001600160a01b03168152602001610c3a85610afc565b8152602001610c47610716565b81525081600081518110610c5757fe5b602002602001018190525061096a610c6f8483612035565b6001600160a01b0385166000908152603d6020526040902054906119c8565b7f000000000000000000000000000000000000000000000000000000011fc9d70881565b7f0000000000000000000000002892e37624ec31cc42502f29782110970027097181565b60048054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156106cd5780601f106106a2576101008083540402835291602001916106cd565b6000610701610716565b7f000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd81565b6000610d7b33610d7433610afc565b6000611b6a565b905060006000198314610d8e5782610d90565b815b9050610dcd816040518060400160405280600e81526020016d1253959053125117d05353d5539560921b81525084611e289092919063ffffffff16565b336000908152603d6020526040902055610e327f000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd6001600160a01b03167f0000000000000000000000002892e37624ec31cc42502f2978211097002709718684612126565b836001600160a01b0316336001600160a01b03167f9310ccfcb8de723f578a9e4282ea9f521f05ae40dc08f3068dfad528a65ee3c783604051610e759190613470565b60405180910390a350505050565b60006106fd610e90611a38565b84610961856040518060600160405280602581526020016138f16025913960016000610eba611a38565b6001600160a01b03908116825260208083019390935260409182016000908120918d16815292529020549190611e28565b60006106fd610ef8611a38565b8484611d5c565b7f10d8d059343739efce7dad10d09f0806da52b252b3e6a7951920d2d6ec4102e581565b601281565b80610f455760405162461bcd60e51b81526004016107399061355a565b6000610f5083610afc565b90506000610f67843084610f62610716565b612180565b90508015610fe5577f2468f9268c60ad90e2d49edb0032c8a001e733ae888b3ab8e982edf535be1a768482604051610fa092919061344c565b60405180910390a16001600160a01b0384166000908152603d6020526040902054610fcb90826119c8565b6001600160a01b0385166000908152603d60205260409020555b610ff26000848685611756565b6001600160a01b0385166000908152603e6020526040902055611015848461223f565b61104a6001600160a01b037f000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd16333086612126565b836001600160a01b0316336001600160a01b03167f5dac0c1b1112564a045ba943c9d50270893e8e826c49be8e7073adc713ab7bd785604051610e759190613470565b336001600160a01b037f0000000000000000000000002892e37624ec31cc42502f29782110970027097116146110d55760405162461bcd60e51b815260040161073990613634565b60005b8181101561123b576000603c60008585858181106110f257fe5b905060600201604001602081019061110a919061308d565b6001600160a01b03166001600160a01b03168152602001908152602001600020905061116f84848481811061113b57fe5b9050606002016040016020810190611153919061308d565b8286868681811061116057fe5b9050606002016020013561232f565b5083838381811061117c57fe5b6111929260206060909202019081019150613302565b81546001600160801b0319166001600160801b03919091161781558383838181106111b957fe5b90506060020160400160208101906111d1919061308d565b6001600160a01b03167f87fa03892a0556cb6b8f97e6d533a150d4d55fcbf275fff5fa003fa636bcc7fa85858581811061120757fe5b61121d9260206060909202019081019150613302565b60405161122a91906136f8565b60405180910390a2506001016110d8565b505050565b600080600061124e84611fd0565b509150915061125f828287436123ec565b95945050505050565b60446020526000908152604090205481565b600080600061128884611fd0565b5091509150611299828288886123ec565b9695505050505050565b6008546001600160a01b031681565b60007f9a9a49b990ba9bb39f8048c490a40ab25c18f55d208d5fbcf958261a9b48716d8787876040516020016112eb94939291906134ad565b60405160208183030381529060405280519060200120905060006043548260405160200161131a9291906133c8565b6040516020818303038152906040528051906020012090506000600182878787604051600081526020016040526040516113579493929190613529565b6020604051602081039080840390855afa158015611379573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166113ac5760405162461bcd60e51b815260040161073990613587565b6001600160a01b038116600090815260446020526040902080546001810190915588146113eb5760405162461bcd60e51b81526004016107399061360d565b8642111561140b5760405162461bcd60e51b8152600401610739906135e1565b611417818a6000611ebf565b611423818a6001611ebf565b505050505050505050565b6000611438612608565b9050600954811161147a5760405162461bcd60e51b815260040180806020018281038252602e81526020018061382f602e913960400191505060405180910390fd5b6009819055467f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6114a9610641565b805160209182012060408051808201825260018152603160f81b90840152516114f993927fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc69186913091016134fd565b60408051808303601f1901815291905280516020909101206043555050604580546001600160a01b0319166001600160a01b0392909216919091179055565b7f0000000000000000000000002892e37624ec31cc42502f29782110970027097181565b6001600160a01b0387166115825760405162461bcd60e51b815260040161073990613663565b834211156115a25760405162461bcd60e51b8152600401610739906135e1565b6001600160a01b03871660009081526044602090815260408083205460435491519093926115fc917f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9918d918d918d9189918e9101613479565b604051602081830303815290604052805190602001206040516020016116239291906133c8565b6040516020818303038152906040528051906020012090506001818686866040516000815260200160405260405161165e9493929190613529565b6020604051602081039080840390855afa158015611680573d6000803e3d6000fd5b505050602060405103516001600160a01b0316896001600160a01b0316146116ba5760405162461bcd60e51b815260040161073990613587565b6116c58260016119c8565b6001600160a01b038a16600090815260446020526040902055611423898989611a3c565b6116f4338383611ebf565b5050565b6001600160a01b03918216600090815260016020908152604080832093909416825291909152205490565b600481565b603c60205260009081526040902080546001909101546001600160801b0380831692600160801b9004169083565b6001600160a01b0382166000908152603e60205260408120548061177e576000915050610af4565b60006117d47f00000000000000000000000000000000000000000000000000000000000007086117ce427f0000000000000000000000000000000000000000000000000000000000000e10611b28565b90611b28565b9050818111156117e75760009150611841565b60008782116117f657876117f8565b425b90508281101561180d57829350505050610af4565b61183d61181a88876119c8565b611837611827888761260d565b6118318b8661260d565b906119c8565b90612666565b9250505b5095945050505050565b60007f10d8d059343739efce7dad10d09f0806da52b252b3e6a7951920d2d6ec4102e58888600181111561187b57fe5b88886040516020016118919594939291906134d1565b6040516020818303038152906040528051906020012090506000604354826040516020016118c09291906133c8565b6040516020818303038152906040528051906020012090506000600182878787604051600081526020016040526040516118fd9493929190613529565b6020604051602081039080840390855afa15801561191f573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b0381166119525760405162461bcd60e51b815260040161073990613587565b6001600160a01b038116600090815260446020526040902080546001810190915588146119915760405162461bcd60e51b81526004016107399061360d565b864211156119b15760405162461bcd60e51b8152600401610739906135e1565b6119bc818b8b611ebf565b50505050505050505050565b60008282018381101561096a576040805162461bcd60e51b815260206004820152601b60248201527f536166654d6174683a206164646974696f6e206f766572666c6f770000000000604482015290519081900360640190fd5b6005805460ff191660ff92909216919091179055565b3390565b6001600160a01b038316611a815760405162461bcd60e51b81526004018080602001828103825260248152602001806138a36024913960400191505060405180910390fd5b6001600160a01b038216611ac65760405162461bcd60e51b815260040180806020018281038252602281526020018061379e6022913960400191505060405180910390fd5b6001600160a01b03808416600081815260016020908152604080832094871680845294825291829020859055815185815291517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259281900390910190a3505050565b600061096a83836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250611e28565b600080611b7b853086610f62610716565b6001600160a01b0386166000908152603d602052604081205491925090611ba290836119c8565b9050811561125f578315611bcc576001600160a01b0386166000908152603d602052604090208190555b7f2468f9268c60ad90e2d49edb0032c8a001e733ae888b3ab8e982edf535be1a768683604051611bfd92919061344c565b60405180910390a195945050505050565b6001600160a01b038216611c535760405162461bcd60e51b815260040180806020018281038252602181526020018061385d6021913960400191505060405180910390fd5b611c5f826000836126a8565b611c9c8160405180606001604052806022815260200161377c602291396001600160a01b0385166000908152602081905260409020549190611e28565b6001600160a01b038316600090815260208190526040902055600254611cc29082611b28565b6002556040805182815290516000916001600160a01b038516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9181900360200190a35050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261123b90849061283d565b6000611d6784610afc565b9050611d7584826001611b6a565b50826001600160a01b0316846001600160a01b031614611e17576000611d9a84610afc565b9050611da884826001611b6a565b506001600160a01b0385166000908152603e6020526040902054611dce81858785611756565b6001600160a01b0386166000908152603e60205260409020558284148015611df557508015155b15611e14576001600160a01b0386166000908152603e60205260408120555b50505b611e228484846129f5565b50505050565b60008184841115611eb75760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015611e7c578181015183820152602001611e64565b50505050905090810190601f168015611ea95780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b505050900390565b6001600160a01b038216611f0e576040805162461bcd60e51b8152602060048201526011602482015270494e56414c49445f44454c45474154454560781b604482015290519081900360640190fd5b6000611f1982611fd0565b925050506000611f2885610afc565b90506000611f36868461200a565b6001600160a01b03878116600090815260208690526040902080546001600160a01b0319169188169190911790559050611f7281868487612b50565b846001600160a01b0316866001600160a01b03167fe8d51c8e11bd570db1734c8ec775785330e77007feed45c43b608ef33ff914bd8660405180826001811115611fb857fe5b815260200191505060405180910390a3505050505050565b6000808080846001811115611fe157fe5b1415611ff757506006915060079050603f612003565b50604091506041905060425b9193909250565b6001600160a01b038083166000908152602083905260408120549091168061096a5783915050610701565b600080805b835181101561211e576000603c600086848151811061205557fe5b602090810291909101810151516001600160a01b0316825281019190915260400160009081206001810154815488519294506120bd926001600160801b0380831692600160801b900416908a90889081106120ac57fe5b602002602001015160400151612d5e565b905061211261210b8785815181106120d157fe5b602002602001015160200151838560020160008c6001600160a01b03166001600160a01b0316815260200190815260200160002054612e57565b85906119c8565b9350505060010161203a565b509392505050565b604080516001600160a01b0380861660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b179052611e2290859061283d565b6001600160a01b038084166000908152603c6020908152604080832093881683526002840190915281205490919082806121bb88858861232f565b90508083146122335786156121d8576121d5878285612e57565b91505b6001600160a01b03808a1660008181526002870160205260409081902084905551918a16917fbb123b5c06d5408bbea3c4fef481578175cfb432e3b482c6186f02ed9086585b9061222a908590613470565b60405180910390a35b50979650505050505050565b6001600160a01b03821661229a576040805162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f206164647265737300604482015290519081900360640190fd5b6122a6600083836126a8565b6002546122b390826119c8565b6002556001600160a01b0382166000908152602081905260409020546122d990826119c8565b6001600160a01b0383166000818152602081815260408083209490945583518581529351929391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9281900390910190a35050565b6001820154825460009190600160801b90046001600160801b03164281141561235a5750905061096a565b84546000906123759084906001600160801b03168488612d5e565b90508281146123c957808660010181905550866001600160a01b03167f5777ca300dfe5bead41006fbce4389794dbc0ed8d6cccebfaf94630aa04184bc826040516123c09190613470565b60405180910390a25b85546001600160801b03428116600160801b029116178655925050509392505050565b60004382111561243a576040805162461bcd60e51b815260206004820152601460248201527324a72b20a624a22fa12627a1a5afa72aa6a122a960611b604482015290519081900360640190fd5b6001600160a01b038316600090815260208590526040902054806124695761246184610afc565b915050610af4565b6001600160a01b038416600090815260208781526040808320600019850184529091529020546001600160801b031683106124dc576001600160a01b038416600090815260208781526040808320600019909401835292905220546001600160801b03600160801b909104169050610af4565b6001600160a01b0384166000908152602087815260408083208380529091529020546001600160801b0316831015612518576000915050610af4565b600060001982015b818111156125ca57600282820304810361253861303f565b506001600160a01b038716600090815260208a815260408083208484528252918290208251808401909352546001600160801b03808216808552600160801b90920416918301919091528714156125a257602001516001600160801b03169450610af49350505050565b80516001600160801b03168711156125bc578193506125c3565b6001820392505b5050612520565b506001600160a01b03851660009081526020888152604080832093835292905220546001600160801b03600160801b90910416915050949350505050565b600490565b60008261261c57506000610701565b8282028284828161262957fe5b041461096a5760405162461bcd60e51b81526004018080602001828103825260218152602001806137e66021913960400191505060405180910390fd5b600061096a83836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250612e79565b6045546001600160a01b0316635b9c4cf184846126c482610afc565b6126cd87610afc565b866040518663ffffffff1660e01b81526004016126ee95949392919061341b565b600060405180830381600087803b15801561270857600080fd5b505af115801561271c573d6000803e3d6000fd5b5050506001600160a01b038085166000908152603f602052604080822054868416835291205490821692501681612751578491505b6001600160a01b0381166127625750825b61276f8282856000612b50565b6001600160a01b038086166000908152604260205260408082205487841683529120549082169116816127a0578691505b6001600160a01b0381166127b15750845b6127be8282876001612b50565b6008546001600160a01b0316801561283357604051634a39314960e01b81526001600160a01b03821690634a39314990612800908b908b908b906004016133f7565b600060405180830381600087803b15801561281a57600080fd5b505af115801561282e573d6000803e3d6000fd5b505050505b5050505050505050565b61284f826001600160a01b0316612ede565b6128a0576040805162461bcd60e51b815260206004820152601f60248201527f5361666545524332303a2063616c6c20746f206e6f6e2d636f6e747261637400604482015290519081900360640190fd5b60006060836001600160a01b0316836040518082805190602001908083835b602083106128de5780518252601f1990920191602091820191016128bf565b6001836020036101000a0380198251168184511680821785525050505050509050019150506000604051808303816000865af19150503d8060008114612940576040519150601f19603f3d011682016040523d82523d6000602084013e612945565b606091505b50915091508161299c576040805162461bcd60e51b815260206004820181905260248201527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564604482015290519081900360640190fd5b805115611e22578080602001905160208110156129b857600080fd5b5051611e225760405162461bcd60e51b815260040180806020018281038252602a8152602001806138c7602a913960400191505060405180910390fd5b6001600160a01b038316612a3a5760405162461bcd60e51b815260040180806020018281038252602581526020018061387e6025913960400191505060405180910390fd5b6001600160a01b038216612a7f5760405162461bcd60e51b81526004018080602001828103825260238152602001806137596023913960400191505060405180910390fd5b612a8a8383836126a8565b612ac7816040518060600160405280602681526020016137c0602691396001600160a01b0386166000908152602081905260409020549190611e28565b6001600160a01b038085166000908152602081905260408082209390935590841681522054612af690826119c8565b6001600160a01b038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b826001600160a01b0316846001600160a01b03161415612b6f57611e22565b600080612b7b83611fd0565b5090925090506001600160a01b03861615612c6e576001600160a01b0386166000908152602082905260408120548015612bec576001600160a01b03881660009081526020858152604080832060001985018452909152902054600160801b90046001600160801b03169150612bf8565b612bf588610afc565b91505b612c0e84848a85612c09818c611b28565b612f17565b6001600160a01b0388167fa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f612c438489611b28565b8760405180838152602001826001811115612c5a57fe5b81526020019250505060405180910390a250505b6001600160a01b03851615612d56576001600160a01b0385166000908152602082905260408120548015612cd9576001600160a01b03871660009081526020858152604080832060001985018452909152902054600160801b90046001600160801b03169150612ce5565b612ce287610afc565b91505b612cf684848985612c09818c6119c8565b6001600160a01b0387167fa0a19463ee116110c9b282012d9b65cc5522dc38a9520340cbaf3142e550127f612d2b84896119c8565b8760405180838152602001826001811115612d4257fe5b81526020019250505060405180910390a250505b505050505050565b6000831580612d6b575081155b80612d7e575042836001600160801b0316145b80612db257507f000000000000000000000000000000000000000000000000000000011fc9d708836001600160801b031610155b15612dbe575083610af4565b60007f000000000000000000000000000000000000000000000000000000011fc9d7084211612ded5742612e0f565b7f000000000000000000000000000000000000000000000000000000011fc9d7085b90506000612e26826001600160801b038716611b28565b9050612e4c8761183186611837670de0b6b3a7640000612e468c8861260d565b9061260d565b979650505050505050565b6000610af4670de0b6b3a7640000611837612e728686611b28565b879061260d565b60008183612ec85760405162461bcd60e51b8152602060048201818152835160248401528351909283926044909101919085019080838360008315611e7c578181015183820152602001611e64565b506000838581612ed457fe5b0495945050505050565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470818114801590610af4575050151592915050565b6001600160a01b03831660009081526020858152604080832054918890529091204391908115801590612f68575060001982016000908152602082905260409020546001600160801b038481169116145b15612f9d576000198201600090815260208290526040902080546001600160801b03808716600160801b029116179055612833565b6040805180820182526001600160801b038086168252868116602080840191825260008781528682528581209451855493518516600160801b029085166001600160801b031990941693909317909316919091179092556001600160a01b038916815290899052206001830190555050505050505050565b604051806060016040528060006001600160a01b0316815260200160008152602001600081525090565b604080518082019091526000808252602082015290565b80356001600160a01b0381168114610b1657600080fd5b803560028110610b1657600080fd5b803560ff81168114610b1657600080fd5b60006020828403121561309e578081fd5b61096a82613056565b600080604083850312156130b9578081fd5b6130c283613056565b91506130d060208401613056565b90509250929050565b6000806000606084860312156130ed578081fd5b6130f684613056565b925061310460208501613056565b9150604084013590509250925092565b600080600080600080600060e0888a03121561312e578283fd5b61313788613056565b965061314560208901613056565b955060408801359450606088013593506131616080890161307c565b925060a0880135915060c0880135905092959891949750929550565b6000806040838503121561318f578182fd5b61319883613056565b91506130d06020840161306d565b600080600080600080600060e0888a0312156131c0578283fd5b6131c988613056565b96506131456020890161306d565b600080604083850312156131e9578182fd5b6131f283613056565b946020939093013593505050565b600080600060608486031215613214578283fd5b61321d84613056565b9250602084013591506132326040850161306d565b90509250925092565b60008060008060008060c08789031215613253578182fd5b61325c87613056565b955060208701359450604087013593506132786060880161307c565b92506080870135915060a087013590509295509295509295565b600080602083850312156132a4578182fd5b823567ffffffffffffffff808211156132bb578384fd5b818501915085601f8301126132ce578384fd5b8135818111156132dc578485fd5b8660206060830285010111156132f0578485fd5b60209290920196919550909350505050565b600060208284031215613313578081fd5b81356001600160801b038116811461096a578182fd5b60006020828403121561333a578081fd5b5035919050565b60008060008060808587031215613356578182fd5b843593506020850135925061336d60408601613056565b9396929550929360600135925050565b60008151808452815b818110156133a257602081850181015186830182015201613386565b818111156133b35782602083870101525b50601f01601f19169290920160200192915050565b61190160f01b81526002810192909252602282015260420190565b6001600160a01b0391909116815260200190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6001600160a01b03958616815293909416602084015260408301919091526060820152608081019190915260a00190565b6001600160a01b03929092168252602082015260400190565b901515815260200190565b90815260200190565b9586526001600160a01b0394851660208701529290931660408501526060840152608083019190915260a082015260c00190565b9384526001600160a01b039290921660208401526040830152606082015260800190565b9485526001600160a01b0393909316602085015260408401919091526060830152608082015260a00190565b9485526020850193909352604084019190915260608301526001600160a01b0316608082015260a00190565b93845260ff9290921660208401526040830152606082015260800190565b60006020825261096a602083018461337d565b6020808252601390820152721253959053125117d6915493d7d05353d55395606a1b604082015260600190565b602080825260119082015270494e56414c49445f5349474e415455524560781b604082015260600190565b60208082526015908201527424a729aaa32324a1a4a2a72a2fa1a7a7a62227aba760591b604082015260600190565b60208082526012908201527124a72b20a624a22fa2ac2824a920aa24a7a760711b604082015260600190565b6020808252600d908201526c494e56414c49445f4e4f4e434560981b604082015260600190565b60208082526015908201527427a7262cafa2a6a4a9a9a4a7a72fa6a0a720a3a2a960591b604082015260600190565b6020808252600d908201526c24a72b20a624a22fa7aba722a960991b604082015260600190565b60208082526017908201527f554e5354414b455f57494e444f575f46494e4953484544000000000000000000604082015260600190565b6020808252601b908201527f494e56414c49445f42414c414e43455f4f4e5f434f4f4c444f574e0000000000604082015260600190565b6001600160801b0391909116815260200190565b6001600160801b0392831681529116602082015260400190565b6001600160801b039384168152919092166020820152604081019190915260600190565b60ff9190911681526020019056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a206275726e20616d6f756e7420657863656564732062616c616e636545524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e6365536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f7745524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e6365436f6e747261637420696e7374616e63652068617320616c7265616479206265656e20696e697469616c697a656445524332303a206275726e2066726f6d20746865207a65726f206164647265737345524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f20616464726573735361666545524332303a204552433230206f7065726174696f6e20646964206e6f74207375636365656445524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220e2d4cb1976f0cbe264a62c15819b021ca2e8bd26aed3ff0e3a1f2d4beb4427fa64736f6c63430007050033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd0000000000000000000000000000000000000000000000000000000000000e1000000000000000000000000000000000000000000000000000000000000007080000000000000000000000002892e37624ec31cc42502f2978211097002709710000000000000000000000002892e37624ec31cc42502f29782110970027097100000000000000000000000000000000000000000000000000000000bbf81e00000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b5374616b65642041415645000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000773746b4141564500000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : stakedToken (address): 0xE205181Eb3D7415f15377F79aA7769F846cE56DD
Arg [1] : rewardToken (address): 0xE205181Eb3D7415f15377F79aA7769F846cE56DD
Arg [2] : cooldownSeconds (uint256): 3600
Arg [3] : unstakeWindow (uint256): 1800
Arg [4] : rewardsVault (address): 0x2892e37624Ec31CC42502f297821109700270971
Arg [5] : emissionManager (address): 0x2892e37624Ec31CC42502f297821109700270971
Arg [6] : distributionDuration (uint128): 3153600000
Arg [7] : name (string): Staked AAVE
Arg [8] : symbol (string): stkAAVE
Arg [9] : decimals (uint8): 18
Arg [10] : governance (address): 0x0000000000000000000000000000000000000000
-----Encoded View---------------
15 Constructor Arguments found :
Arg [0] : 000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd
Arg [1] : 000000000000000000000000e205181eb3d7415f15377f79aa7769f846ce56dd
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000e10
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000708
Arg [4] : 0000000000000000000000002892e37624ec31cc42502f297821109700270971
Arg [5] : 0000000000000000000000002892e37624ec31cc42502f297821109700270971
Arg [6] : 00000000000000000000000000000000000000000000000000000000bbf81e00
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [8] : 00000000000000000000000000000000000000000000000000000000000001a0
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [11] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [12] : 5374616b65642041415645000000000000000000000000000000000000000000
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000007
Arg [14] : 73746b4141564500000000000000000000000000000000000000000000000000
Loading...
Loading
[ Download: CSV Export ]
[ 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.