Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
- Contract name:
- SinkManager
- Optimization enabled
- true
- Compiler version
- v0.8.19+commit.7dd6d404
- Optimization runs
- 200
- EVM Version
- default
- Verified at
- 2023-10-05T14:30:40.266361Z
Constructor Arguments
0x000000000000000000000000c6eaf7d353d9901375be2d8f9ba38dd58524d8b300000000000000000000000087e7742fe8cb0ef71f6fc21344a20fb0ce9c03620000000000000000000000004c0846c484d7a6a9639b20e1828e3337bbc8d7d7000000000000000000000000842d477f8ce0efbb669ddc2ace21816b9a841ee4000000000000000000000000e1da44c0da55b075ae8e2e4b6986adc76ac77d73000000000000000000000000b6a075e9cf5dba476994b63b60217a5cf9ab272700000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a0000000000000000000000004937fcfaf9fbd139b78d95a128425a19721c3072000000000000000000000000411bb8829a14d56356485df13cc6a00c9ddf19db
Arg [0] (address) : 0xc6eaf7d353d9901375be2d8f9ba38dd58524d8b3
Arg [1] (address) : 0x87e7742fe8cb0ef71f6fc21344a20fb0ce9c0362
Arg [2] (address) : 0x4c0846c484d7a6a9639b20e1828e3337bbc8d7d7
Arg [3] (address) : 0x842d477f8ce0efbb669ddc2ace21816b9a841ee4
Arg [4] (address) : 0xe1da44c0da55b075ae8e2e4b6986adc76ac77d73
Arg [5] (address) : 0xb6a075e9cf5dba476994b63b60217a5cf9ab2727
Arg [6] (address) : 0x35361c9c2a324f5fb8f3aed2d7ba91ce1410893a
Arg [7] (address) : 0x4937fcfaf9fbd139b78d95a128425a19721c3072
Arg [8] (address) : 0x411bb8829a14d56356485df13cc6a00c9ddf19db
contracts/v1/sink/SinkManager.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import { SinkManagerFacilitator } from "./SinkManagerFacilitator.sol"; import { ISinkManager } from "../../interfaces/ISinkManager.sol"; import { IMinter } from "../../interfaces/IMinter.sol"; import { IVotingEscrow } from "../../interfaces/IVotingEscrow.sol"; import { IVara } from "../../interfaces/IVara.sol"; import { IGaugeV1 } from "../../interfaces/v1/IGaugeV1.sol"; import { IVoterV1 } from "../../interfaces/v1/IVoterV1.sol"; import { IVotingEscrowV1 } from "../../interfaces/v1/IVotingEscrowV1.sol"; import { IRewardsDistributorV1 } from "../../interfaces/v1/IRewardsDistributorV1.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Context } from "@openzeppelin/contracts/utils/Context.sol"; import { ERC2771Context } from "@openzeppelin/contracts/metatx/ERC2771Context.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; import { ReentrancyGuard } from "@openzeppelin/contracts/security/ReentrancyGuard.sol"; import { Clones } from "@openzeppelin/contracts/proxy/Clones.sol"; import { VelodromeTimeLibrary } from "../../libraries/VelodromeTimeLibrary.sol"; /// @title Velodrome Sink Manager /// @notice Absorb v1 Vara and converting v1 veNFTs and VELO into v2 /// @author varadrome.finance, @pegahcarter contract SinkManager is ISinkManager, ERC2771Context, Ownable, ERC721Holder, ReentrancyGuard { uint256 internal constant MAXTIME = 4 * 365 days; uint256 internal constant WEEK = 1 weeks; // @dev Additional salt for contract creation uint256 private counter; /// @dev tokenId => tokenIdV2 mapping(uint256 => uint256) public conversions; /// @dev tokenId => facilitator address mapping(uint256 => address) public facilitators; /// @dev token id of veNFT owned by this contract to capture v1 VELO emissions uint256 public ownedTokenId; /// @dev Address of fake pool used to capture emissions address private sinkDrain; // @dev Address of deployed facilitator contract to clone address public facilitatorImplementation; /// @dev V1 Voting contract IVoterV1 public immutable voter; /// @dev V1 Vara contract IVara public immutable vara; /// @dev V2 Vara contract IVara public immutable varaV2; /// @dev V2 Minter contract IMinter public immutable minterV2; /// @dev V1 Voting Escrow contract IVotingEscrowV1 public immutable ve; /// @dev V2 Voting Escrow contract IVotingEscrow public immutable veV2; /// @dev V1 Rewards Distributor contract IRewardsDistributorV1 public immutable rewardsDistributor; /// @dev V1 sinkDrain gauge IGaugeV1 public gauge; /// @dev epoch start => vara captured mapping(uint256 => uint256) internal _captured; constructor( address _forwarder, address _sinkDrain, address _facilitatorImplementation, address _voter, address _vara, address _varaV2, address _ve, address _veV2, address _rewardsDistributor ) ERC2771Context(_forwarder) { sinkDrain = _sinkDrain; facilitatorImplementation = _facilitatorImplementation; voter = IVoterV1(_voter); vara = IVara(_vara); varaV2 = IVara(_varaV2); minterV2 = IMinter(IVara(_varaV2).minter()); ve = IVotingEscrowV1(_ve); veV2 = IVotingEscrow(_veV2); rewardsDistributor = IRewardsDistributorV1(_rewardsDistributor); vara.approve(_ve, type(uint256).max); varaV2.approve(_veV2, type(uint256).max); } // -------------------------------------------------------------------- // Conversion methods // -------------------------------------------------------------------- /// @inheritdoc ISinkManager function convertVELO(uint256 amount) external { uint256 _ownedTokenId = ownedTokenId; if (_ownedTokenId == 0) revert TokenIdNotSet(); address sender = _msgSender(); // Mint emissions prior to conversion minterV2.updatePeriod(); // Deposit old VELO vara.transferFrom(sender, address(this), amount); // Add VELO to owned escrow ve.increase_amount(_ownedTokenId, amount); // return new VELO varaV2.mint(sender, amount); _captured[VelodromeTimeLibrary.epochStart(block.timestamp)] += amount; emit ConvertVELO(sender, amount, block.timestamp); } /// @inheritdoc ISinkManager function convertVe(uint256 tokenId) external nonReentrant returns (uint256 tokenIdV2) { uint256 _ownedTokenId = ownedTokenId; if (_ownedTokenId == 0) revert TokenIdNotSet(); // Ensure the veNFT was not converted if (conversions[tokenId] != 0) revert NFTAlreadyConverted(); // Ensure this contract has been approved to transfer the veNFT if (!ve.isApprovedOrOwner(address(this), tokenId)) revert NFTNotApproved(); // Ensure the veNFT has not expired if (ve.locked__end(tokenId) <= block.timestamp) revert NFTExpired(); address sender = _msgSender(); // Mint emissions prior to conversion minterV2.updatePeriod(); // Create contract to facilitate the merge SinkManagerFacilitator facilitator = SinkManagerFacilitator( Clones.cloneDeterministic( facilitatorImplementation, keccak256(abi.encodePacked(++counter, blockhash(block.number - 1))) ) ); // Transfer the veNFT to the facilitator ve.safeTransferFrom(sender, address(facilitator), tokenId); /* Create new veNFT with same lock parameters */ // Fetch lock information of v1 veNFT (int128 _lockAmount, uint256 lockEnd) = ve.locked(tokenId); // amount of v1 VELO locked, unlock timestamp uint256 lockAmount = uint256(int256(_lockAmount)); // determine lockDuration based on current epoch start - see unlockTime in ve._createLock() uint256 lockDuration = lockEnd - (block.timestamp / WEEK) * WEEK; // mint v2 VELO to deposit into lock varaV2.mint(address(this), lockAmount); // Create v2 veNFT tokenIdV2 = veV2.createLockFor(lockAmount, lockDuration, sender); // Merge into the sinkManager veNFT ve.approve(address(facilitator), ownedTokenId); facilitator.merge(ve, tokenId, ownedTokenId); ve.approve(address(0), ownedTokenId); // poke vote to update voting balance to gauge voter.poke(_ownedTokenId); // event emission and storage of conversion conversions[tokenId] = tokenIdV2; facilitators[tokenId] = address(facilitator); _captured[VelodromeTimeLibrary.epochStart(block.timestamp)] += lockAmount; emit ConvertVe(sender, tokenId, tokenIdV2, lockAmount, lockEnd, block.timestamp); } // -------------------------------------------------------------------- // Maintenance // -------------------------------------------------------------------- /// @inheritdoc ISinkManager function claimRebaseAndGaugeRewards() external { if (address(gauge) == address(0)) revert GaugeNotSet(); uint256 _ownedTokenId = ownedTokenId; // Claim gauge rewards and deposit into owned veNFT uint256 amountResidual = vara.balanceOf(address(this)); address[] memory rewards = new address[](1); rewards[0] = address(vara); gauge.getReward(address(this), rewards); uint256 amountAfterReward = vara.balanceOf(address(this)); uint256 amountRewarded = amountAfterReward - amountResidual; if (amountAfterReward > 0) { ve.increase_amount(_ownedTokenId, amountAfterReward); } // Claim rebases uint256 amountRebased = rewardsDistributor.claimable(_ownedTokenId); if (amountRebased > 0) { rewardsDistributor.claim(_ownedTokenId); } // increase locktime to max if possible uint256 unlockTime = ((block.timestamp + MAXTIME) / WEEK) * WEEK; (, uint256 end) = ve.locked(_ownedTokenId); if (unlockTime > end) { ve.increase_unlock_time(_ownedTokenId, MAXTIME); } // poke vote to update voting balance to gauge voter.poke(_ownedTokenId); emit ClaimRebaseAndGaugeRewards( _msgSender(), amountResidual, amountRewarded, amountRebased, block.timestamp ); } // -------------------------------------------------------------------- // Admin // -------------------------------------------------------------------- /// @notice Initial setup of the ownedTokenId, the v1 veNFT which votes for the SinkDrain function setOwnedTokenId(uint256 tokenId) external onlyOwner { if (ownedTokenId != 0) revert TokenIdAlreadySet(); if (ve.ownerOf(tokenId) != address(this)) revert ContractNotOwnerOfToken(); ownedTokenId = tokenId; } /// @notice Deposit all of SinkDrain token to gauge to earn 100% of rewards /// And vote for the gauge to allocate rewards function setupSinkDrain(address _gauge) external onlyOwner { uint256 _ownedTokenId = ownedTokenId; if (_ownedTokenId == 0) revert TokenIdNotSet(); if (address(gauge) != address(0)) revert GaugeAlreadySet(); // Set gauge for future claims gauge = IGaugeV1(_gauge); // Approve gauge to transfer token IERC20 token = IERC20(gauge.stake()); uint256 balance = token.balanceOf(address(this)); token.approve(_gauge, balance); // Deposit SinkDrain to gauge gauge.deposit(balance, 0); // Initial vote address[] memory poolVote = new address[](1); uint256[] memory weights = new uint256[](1); poolVote[0] = gauge.stake(); weights[0] = 1; voter.vote(_ownedTokenId, poolVote, weights); } /// @inheritdoc ISinkManager function captured(uint256 _timestamp) external view returns (uint256 _amount) { _amount = _captured[VelodromeTimeLibrary.epochStart(_timestamp)]; } function _msgData() internal view override(ERC2771Context, Context) returns (bytes calldata) { return ERC2771Context._msgData(); } function _msgSender() internal view override(ERC2771Context, Context) returns (address) { return ERC2771Context._msgSender(); } }
@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.0; import "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
contracts/governance/IVotes.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /// Modified IVotes interface for tokenId based voting interface IVotes { /** * @dev Emitted when an account changes their delegate. */ event DelegateChanged(address indexed delegator, uint256 indexed fromDelegate, uint256 indexed toDelegate); /** * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes. */ event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance); /** * @dev Returns the amount of votes that `tokenId` had at a specific moment in the past. * If the account passed in is not the owner, returns 0. */ function getPastVotes(address account, uint256 tokenId, uint256 timepoint) external view returns (uint256); /** * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is * configured to use block numbers, this will return the value the end of the corresponding block. * * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. * Votes that have not been delegated are still part of total supply, even though they would not participate in a * vote. */ function getPastTotalSupply(uint256 timepoint) external view returns (uint256); /** * @dev Returns the delegate that `tokenId` has chosen. Can never be equal to the delegator's `tokenId`. * Returns 0 if not delegated. */ function delegates(uint256 tokenId) external view returns (uint256); /** * @dev Delegates votes from the sender to `delegatee`. */ function delegate(uint256 delegator, uint256 delegatee) external; /** * @dev Delegates votes from `delegator` to `delegatee`. Signer must own `delegator`. */ function delegateBySig( uint256 delegator, uint256 delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s ) external; }
@openzeppelin/contracts/access/Ownable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
@openzeppelin/contracts/interfaces/IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
@openzeppelin/contracts/interfaces/IERC4906.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4906.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; import "./IERC721.sol"; /// @title EIP-721 Metadata Update Extension interface IERC4906 is IERC165, IERC721 { /// @dev This event emits when the metadata of a token is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFT. event MetadataUpdate(uint256 _tokenId); /// @dev This event emits when the metadata of a range of tokens is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFTs. event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); }
@openzeppelin/contracts/interfaces/IERC721.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) pragma solidity ^0.8.0; import "../token/ERC721/IERC721.sol";
@openzeppelin/contracts/metatx/ERC2771Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (metatx/ERC2771Context.sol) pragma solidity ^0.8.9; import "../utils/Context.sol"; /** * @dev Context variant with ERC2771 support. */ abstract contract ERC2771Context is Context { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable _trustedForwarder; /// @custom:oz-upgrades-unsafe-allow constructor constructor(address trustedForwarder) { _trustedForwarder = trustedForwarder; } function isTrustedForwarder(address forwarder) public view virtual returns (bool) { return forwarder == _trustedForwarder; } function _msgSender() internal view virtual override returns (address sender) { if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) { // The assembly code is more direct than the Solidity version using `abi.decode`. /// @solidity memory-safe-assembly assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) } } else { return super._msgSender(); } } function _msgData() internal view virtual override returns (bytes calldata) { if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) { return msg.data[:msg.data.length - 20]; } else { return super._msgData(); } } }
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
@openzeppelin/contracts/proxy/Clones.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/Clones.sol) pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create(0, 0x09, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create2(0, 0x09, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(add(ptr, 0x38), deployer) mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) mstore(add(ptr, 0x14), implementation) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) mstore(add(ptr, 0x58), salt) mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) predicted := keccak256(add(ptr, 0x43), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt ) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } }
@openzeppelin/contracts/security/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
@openzeppelin/contracts/token/ERC721/IERC721.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
@openzeppelin/contracts/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
contracts/interfaces/IMinter.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IMinter { error AlreadyNudged(); error NotEpochGovernor(); error TailEmissionsInactive(); event Mint( address indexed _sender, uint256 _weekly, uint256 _circulating_supply, bool indexed _tail ); event Nudge(uint256 indexed _period, uint256 _oldRate, uint256 _newRate); /// @notice Timestamp of start of epoch that updatePeriod was last called in function activePeriod() external returns (uint256); /// @notice Allows epoch governor to modify the tail emission rate by at most 1 basis point /// per epoch to a maximum of 100 basis points or to a minimum of 1 basis point. /// Note: the very first nudge proposal must take place the week prior /// to the tail emission schedule starting. /// @dev Throws if not epoch governor. /// Throws if not currently in tail emission schedule. /// Throws if already nudged this epoch. /// Throws if nudging above maximum rate. /// Throws if nudging below minimum rate. /// This contract is coupled to EpochGovernor as it requires three option simple majority voting. function nudge() external; /// @notice Calculates rebases according to the formula /// weekly * (ve.totalSupply / vara.totalSupply) ^ 3 / 2 /// Note that ve.totalSupply is the locked ve supply /// vara.totalSupply is the total ve supply minted /// @param _minted Amount of VELO minted this epoch /// @return _growth Rebases function calculateGrowth(uint256 _minted) external view returns (uint256 _growth); /// @notice Processes emissions and rebases. Callable once per epoch (1 week). /// @return _period Start of current epoch. function updatePeriod() external returns (uint256 _period); }
contracts/interfaces/ISinkManager.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IVara } from "./IVara.sol"; interface ISinkManager { event ConvertVELO(address indexed who, uint256 amount, uint256 timestamp); event ConvertVe( address indexed who, uint256 indexed tokenId, uint256 indexed tokenIdV2, uint256 amount, uint256 lockEnd, uint256 timestamp ); event ClaimRebaseAndGaugeRewards( address indexed who, uint256 amountResidual, uint256 amountRewarded, uint256 amountRebased, uint256 timestamp ); error ContractNotOwnerOfToken(); error GaugeAlreadySet(); error GaugeNotSet(); error GaugeNotSinkDrain(); error NFTAlreadyConverted(); error NFTNotApproved(); error NFTExpired(); error TokenIdNotSet(); error TokenIdAlreadySet(); function ownedTokenId() external view returns (uint256); function vara() external view returns (IVara); function varaV2() external view returns (IVara); /// @notice Helper utility that returns amount of token captured by epoch function captured(uint256 timestamp) external view returns (uint256 amount); /// @notice User converts their v1 VELO into v2 VELO /// @param amount Amount of VELO to convert function convertVELO(uint256 amount) external; /// @notice User converts their v1 ve into v2 ve /// @param tokenId Token ID of v1 ve /// @return tokenIdV2 Token ID of v2 ve function convertVe(uint256 tokenId) external returns (uint256 tokenIdV2); /// @notice Claim SinkManager-eligible rebase and gauge rewards to lock into the SinkManager-owned tokenId /// @dev Callable by anyone function claimRebaseAndGaugeRewards() external; }
contracts/interfaces/IVara.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IVara is IERC20 { error NotMinter(); error NotOwner(); error NotMinterOrSinkManager(); error SinkManagerAlreadySet(); function mint(address, uint256) external returns (bool); function minter() external returns (address); }
contracts/interfaces/IVotingEscrow.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC721, IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {IERC4906} from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import {IVotes} from "../governance/IVotes.sol"; interface IVotingEscrow is IVotes, IERC4906, IERC721Metadata { struct LockedBalance { int128 amount; uint256 end; bool isPermanent; } struct UserPoint { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block uint256 permanent; } struct GlobalPoint { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block uint256 permanentLockBalance; } /// @notice A checkpoint for recorded delegated voting weights at a certain timestamp struct Checkpoint { uint256 fromTimestamp; address owner; uint256 delegatedBalance; uint256 delegatee; } enum DepositType { DEPOSIT_FOR_TYPE, CREATE_LOCK_TYPE, INCREASE_LOCK_AMOUNT, INCREASE_UNLOCK_TIME } /// @dev Different types of veNFTs: /// NORMAL - typical veNFT /// LOCKED - veNFT which is locked into a MANAGED veNFT /// MANAGED - veNFT which can accept the deposit of NORMAL veNFTs enum EscrowType { NORMAL, LOCKED, MANAGED } error AlreadyVoted(); error AmountTooBig(); error ERC721ReceiverRejectedTokens(); error ERC721TransferToNonERC721ReceiverImplementer(); error InvalidNonce(); error InvalidSignature(); error InvalidSignatureS(); error InvalidManagedNFTId(); error LockDurationNotInFuture(); error LockDurationTooLong(); error LockExpired(); error LockNotExpired(); error NoLockFound(); error NonExistentToken(); error NotApprovedOrOwner(); error NotDistributor(); error NotEmergencyCouncilOrGovernor(); error NotGovernor(); error NotGovernorOrManager(); error NotManagedNFT(); error NotManagedOrNormalNFT(); error NotLockedNFT(); error NotNormalNFT(); error NotPermanentLock(); error NotOwner(); error NotTeam(); error NotVoter(); error OwnershipChange(); error PermanentLock(); error SameAddress(); error SameNFT(); error SameState(); error SplitNoOwner(); error SplitNotAllowed(); error SignatureExpired(); error TooManyTokenIDs(); error ZeroAddress(); error ZeroAmount(); error ZeroBalance(); event Deposit( address indexed provider, uint256 indexed tokenId, DepositType indexed depositType, uint256 value, uint256 locktime, uint256 ts ); event Withdraw(address indexed provider, uint256 indexed tokenId, uint256 value, uint256 ts); event LockPermanent(address indexed _owner, uint256 indexed _tokenId, uint256 amount, uint256 _ts); event UnlockPermanent(address indexed _owner, uint256 indexed _tokenId, uint256 amount, uint256 _ts); event Supply(uint256 prevSupply, uint256 supply); event Merge( address indexed _sender, uint256 indexed _from, uint256 indexed _to, uint256 _amountFrom, uint256 _amountTo, uint256 _amountFinal, uint256 _locktime, uint256 _ts ); event Split( uint256 indexed _from, uint256 indexed _tokenId1, uint256 indexed _tokenId2, address _sender, uint256 _splitAmount1, uint256 _splitAmount2, uint256 _locktime, uint256 _ts ); event CreateManaged( address indexed _to, uint256 indexed _mTokenId, address indexed _from, address _lockedManagedReward, address _freeManagedReward ); event DepositManaged( address indexed _owner, uint256 indexed _tokenId, uint256 indexed _mTokenId, uint256 _weight, uint256 _ts ); event WithdrawManaged( address indexed _owner, uint256 indexed _tokenId, uint256 indexed _mTokenId, uint256 _weight, uint256 _ts ); event SetAllowedManager(address indexed _allowedManager); // State variables function factoryRegistry() external view returns (address); function token() external view returns (address); function distributor() external view returns (address); function voter() external view returns (address); function team() external view returns (address); function artProxy() external view returns (address); function allowedManager() external view returns (address); function tokenId() external view returns (uint256); /*/////////////////////////////////////////////////////////////// MANAGED NFT STORAGE //////////////////////////////////////////////////////////////*/ /// @dev Mapping of token id to escrow type /// Takes advantage of the fact default value is EscrowType.NORMAL function escrowType(uint256 tokenId) external view returns (EscrowType); /// @dev Mapping of token id to managed id function idToManaged(uint256 tokenId) external view returns (uint256 managedTokenId); /// @dev Mapping of user token id to managed token id to weight of token id function weights(uint256 tokenId, uint256 managedTokenId) external view returns (uint256 weight); /// @dev Mapping of managed id to deactivated state function deactivated(uint256 tokenId) external view returns (bool inactive); /// @dev Mapping from managed nft id to locked managed rewards /// `token` denominated rewards (rebases/rewards) stored in locked managed rewards contract /// to prevent co-mingling of assets function managedToLocked(uint256 tokenId) external view returns (address); /// @dev Mapping from managed nft id to free managed rewards contract /// these rewards can be freely withdrawn by users function managedToFree(uint256 tokenId) external view returns (address); /*/////////////////////////////////////////////////////////////// MANAGED NFT LOGIC //////////////////////////////////////////////////////////////*/ /// @notice Create managed NFT (a permanent lock) for use within ecosystem. /// @dev Throws if address already owns a managed NFT. /// @return _mTokenId managed token id. function createManagedLockFor(address _to) external returns (uint256 _mTokenId); /// @notice Delegates balance to managed nft /// Note that NFTs deposited into a managed NFT will be re-locked /// to the maximum lock time on withdrawal. /// Permanent locks that are deposited will automatically unlock. /// @dev Managed nft will remain max-locked as long as there is at least one /// deposit or withdrawal per week. /// Throws if deposit nft is managed. /// Throws if recipient nft is not managed. /// Throws if deposit nft is already locked. /// Throws if not called by voter. /// @param _tokenId tokenId of NFT being deposited /// @param _mTokenId tokenId of managed NFT that will receive the deposit function depositManaged(uint256 _tokenId, uint256 _mTokenId) external; /// @notice Retrieves locked rewards and withdraws balance from managed nft. /// Note that the NFT withdrawn is re-locked to the maximum lock time. /// @dev Throws if NFT not locked. /// Throws if not called by voter. /// @param _tokenId tokenId of NFT being deposited. function withdrawManaged(uint256 _tokenId) external; /// @notice Permit one address to call createManagedLockFor() that is not Voter.governor() function setAllowedManager(address _allowedManager) external; /// @notice Set Managed NFT state. Inactive NFTs cannot be deposited into. /// @param _mTokenId managed nft state to set /// @param _state true => inactive, false => active function setManagedState(uint256 _mTokenId, bool _state) external; /*/////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ function name() external view returns (string memory); function symbol() external view returns (string memory); function version() external view returns (string memory); function decimals() external view returns (uint8); function setTeam(address _team) external; function setArtProxy(address _proxy) external; /// @inheritdoc IERC721Metadata function tokenURI(uint256 tokenId) external view returns (string memory); /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ /// @dev Mapping from owner address to mapping of index to tokenId function ownerToNFTokenIdList(address _owner, uint256 _index) external view returns (uint256 _tokenId); /// @inheritdoc IERC721 function ownerOf(uint256 tokenId) external view returns (address owner); /// @inheritdoc IERC721 function balanceOf(address owner) external view returns (uint256 balance); /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ /// @inheritdoc IERC721 function getApproved(uint256 _tokenId) external view returns (address operator); /// @inheritdoc IERC721 function isApprovedForAll(address owner, address operator) external view returns (bool); /// @notice Check whether spender is owner or an approved user for a given veNFT /// @param _spender . /// @param _tokenId . function isApprovedOrOwner(address _spender, uint256 _tokenId) external returns (bool); /*////////////////////////////////////////////////////////////// ERC721 LOGIC //////////////////////////////////////////////////////////////*/ /// @inheritdoc IERC721 function approve(address to, uint256 tokenId) external; /// @inheritdoc IERC721 function setApprovalForAll(address operator, bool approved) external; /// @inheritdoc IERC721 function transferFrom(address from, address to, uint256 tokenId) external; /// @inheritdoc IERC721 function safeTransferFrom(address from, address to, uint256 tokenId) external; /// @inheritdoc IERC721 function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 _interfaceID) external view returns (bool); /*////////////////////////////////////////////////////////////// ESCROW STORAGE //////////////////////////////////////////////////////////////*/ function epoch() external view returns (uint256); function supply() external view returns (uint256); function userPointEpoch(uint256 _tokenId) external view returns (uint256 _epoch); /// @notice time -> signed slope change function slopeChanges(uint256 _timestamp) external view returns (int128); /// @notice account -> can split function canSplit(address _account) external view returns (bool); /// @notice Global point history at a given index function pointHistory(uint256 _loc) external view returns (GlobalPoint memory); /// @notice Get the LockedBalance (amount, end) of a _tokenId /// @param _tokenId . /// @return LockedBalance of _tokenId function locked(uint256 _tokenId) external view returns (LockedBalance memory); /// @notice User -> UserPoint[userEpoch] function userPointHistory(uint256 _tokenId, uint256 _loc) external view returns (UserPoint memory); /*////////////////////////////////////////////////////////////// ESCROW LOGIC //////////////////////////////////////////////////////////////*/ /// @notice Record global data to checkpoint function checkpoint() external; /// @notice Deposit `_value` tokens for `_tokenId` and add to the lock /// @dev Anyone (even a smart contract) can deposit for someone else, but /// cannot extend their locktime and deposit for a brand new user /// @param _tokenId lock NFT /// @param _value Amount to add to user's lock function depositFor(uint256 _tokenId, uint256 _value) external; /// @notice Deposit `_value` tokens for `msg.sender` and lock for `_lockDuration` /// @param _value Amount to deposit /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week) /// @return TokenId of created veNFT function createLock(uint256 _value, uint256 _lockDuration) external returns (uint256); /// @notice Deposit `_value` tokens for `_to` and lock for `_lockDuration` /// @param _value Amount to deposit /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week) /// @param _to Address to deposit /// @return TokenId of created veNFT function createLockFor(uint256 _value, uint256 _lockDuration, address _to) external returns (uint256); /// @notice Deposit `_value` additional tokens for `_tokenId` without modifying the unlock time /// @param _value Amount of tokens to deposit and add to the lock function increaseAmount(uint256 _tokenId, uint256 _value) external; /// @notice Extend the unlock time for `_tokenId` /// Cannot extend lock time of permanent locks /// @param _lockDuration New number of seconds until tokens unlock function increaseUnlockTime(uint256 _tokenId, uint256 _lockDuration) external; /// @notice Withdraw all tokens for `_tokenId` /// @dev Only possible if the lock is both expired and not permanent /// This will burn the veNFT. Any rebases or rewards that are unclaimed /// will no longer be claimable. Claim all rebases and rewards prior to calling this. function withdraw(uint256 _tokenId) external; /// @notice Merges `_from` into `_to`. /// @dev Cannot merge `_from` locks that are permanent or have already voted this epoch. /// Cannot merge `_to` locks that have already expired. /// This will burn the veNFT. Any rebases or rewards that are unclaimed /// will no longer be claimable. Claim all rebases and rewards prior to calling this. /// @param _from VeNFT to merge from. /// @param _to VeNFT to merge into. function merge(uint256 _from, uint256 _to) external; /// @notice Splits veNFT into two new veNFTS - one with oldLocked.amount - `_amount`, and the second with `_amount` /// @dev This burns the tokenId of the target veNFT /// Callable by approved or owner /// If this is called by approved, approved will not have permissions to manipulate the newly created veNFTs /// Returns the two new split veNFTs to owner /// If `from` is permanent, will automatically dedelegate. /// This will burn the veNFT. Any rebases or rewards that are unclaimed /// will no longer be claimable. Claim all rebases and rewards prior to calling this. /// @param _from VeNFT to split. /// @param _amount Amount to split from veNFT. /// @return _tokenId1 Return tokenId of veNFT with oldLocked.amount - `_amount`. /// @return _tokenId2 Return tokenId of veNFT with `_amount`. function split(uint256 _from, uint256 _amount) external returns (uint256 _tokenId1, uint256 _tokenId2); /// @notice Toggle split for a specific veNFT. /// @dev Toggle split for address(0) to enable or disable for all. /// @param _account Address to toggle split permissions /// @param _bool True to allow, false to disallow function toggleSplit(address _account, bool _bool) external; /// @notice Permanently lock a veNFT. Voting power will be equal to /// `LockedBalance.amount` with no decay. Required to delegate. /// @dev Only callable by unlocked normal veNFTs. /// @param _tokenId tokenId to lock. function lockPermanent(uint256 _tokenId) external; /// @notice Unlock a permanently locked veNFT. Voting power will decay. /// Will automatically dedelegate if delegated. /// @dev Only callable by permanently locked veNFTs. /// Cannot unlock if already voted this epoch. /// @param _tokenId tokenId to unlock. function unlockPermanent(uint256 _tokenId) external; /*/////////////////////////////////////////////////////////////// GAUGE VOTING STORAGE //////////////////////////////////////////////////////////////*/ /// @notice Get the voting power for _tokenId at the current timestamp /// @dev Returns 0 if called in the same block as a transfer. /// @param _tokenId . /// @return Voting power function balanceOfNFT(uint256 _tokenId) external view returns (uint256); /// @notice Get the voting power for _tokenId at a given timestamp /// @param _tokenId . /// @param _t Timestamp to query voting power /// @return Voting power function balanceOfNFTAt(uint256 _tokenId, uint256 _t) external view returns (uint256); /// @notice Calculate total voting power at current timestamp /// @return Total voting power at current timestamp function totalSupply() external view returns (uint256); /// @notice Calculate total voting power at a given timestamp /// @param _t Timestamp to query total voting power /// @return Total voting power at given timestamp function totalSupplyAt(uint256 _t) external view returns (uint256); /*/////////////////////////////////////////////////////////////// GAUGE VOTING LOGIC //////////////////////////////////////////////////////////////*/ /// @notice See if a queried _tokenId has actively voted /// @param _tokenId . /// @return True if voted, else false function voted(uint256 _tokenId) external view returns (bool); /// @notice Set the global state voter and distributor /// @dev This is only called once, at setup function setVoterAndDistributor(address _voter, address _distributor) external; /// @notice Set `voted` for _tokenId to true or false /// @dev Only callable by voter /// @param _tokenId . /// @param _voted . function voting(uint256 _tokenId, bool _voted) external; /*/////////////////////////////////////////////////////////////// DAO VOTING STORAGE //////////////////////////////////////////////////////////////*/ /// @notice The number of checkpoints for each tokenId function numCheckpoints(uint256 tokenId) external view returns (uint48); /// @notice A record of states for signing / validating signatures function nonces(address account) external view returns (uint256); /// @inheritdoc IVotes function delegates(uint256 delegator) external view returns (uint256); /// @notice A record of delegated token checkpoints for each account, by index /// @param tokenId . /// @param index . /// @return Checkpoint function checkpoints(uint256 tokenId, uint48 index) external view returns (Checkpoint memory); /// @inheritdoc IVotes function getPastVotes(address account, uint256 tokenId, uint256 timestamp) external view returns (uint256); /// @inheritdoc IVotes function getPastTotalSupply(uint256 timestamp) external view returns (uint256); /*/////////////////////////////////////////////////////////////// DAO VOTING LOGIC //////////////////////////////////////////////////////////////*/ /// @inheritdoc IVotes function delegate(uint256 delegator, uint256 delegatee) external; /// @inheritdoc IVotes function delegateBySig( uint256 delegator, uint256 delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s ) external; }
contracts/interfaces/v1/IGaugeV1.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IGaugeV1 { function balanceOf(address _account) external returns (uint256 _balance); function stake() external returns (address _stake); function totalSupply() external returns (uint256 _totalSupply); function getReward(address _account, address[] memory _tokens) external; function deposit(uint256 _amount, uint256 _tokenId) external; function notifyRewardAmount(address _token, uint256 _amount) external; }
contracts/interfaces/v1/IRewardsDistributorV1.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IRewardsDistributorV1 { function claimable(uint256 _tokenId) external view returns (uint256 _claimable); function claim(uint256 _tokenId) external returns (uint256 _amount); }
contracts/interfaces/v1/IVoterV1.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IVoterV1 { function governor() external returns (address _governor); function totalWeight() external returns (uint256 _totalWeight); function usedWeights(uint256 _tokenId) external returns (uint256 _weight); function votes(uint256 _tokenId, address _pool) external returns (uint256 _votes); function createGauge(address _pool) external returns (address _gauge); function gauges(address pool) external view returns (address); function distribute(address _gauge) external; function poke(uint256 _tokenId) external; function vote(uint256 _tokenId, address[] memory _pools, uint256[] memory _weights) external; }
contracts/interfaces/v1/IVotingEscrowV1.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IVotingEscrowV1 { struct Point { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block } function getApproved(uint256 _tokenId) external view returns (address); function isApprovedOrOwner(address _spender, uint256 _tokenId) external returns (bool); function locked__end(uint256 _tokenId) external view returns (uint256 _locked); function locked(uint256 _tokenId) external view returns (int128 _amount, uint256 _end); function ownerOf(uint256 _tokenId) external view returns (address _owner); function increase_amount(uint256 _tokenId, uint256 _amount) external; function increase_unlock_time(uint256 _tokenId, uint256 _duration) external; function create_lock(uint256 _amount, uint256 _end) external returns (uint256 tokenId); function create_lock_for(uint256 _amount, uint256 _end, address _to) external returns (uint256 tokenId); function approve(address who, uint256 tokenId) external; function balanceOfNFT(uint256) external view returns (uint256 amount); function user_point_epoch(uint256) external view returns (uint256); function user_point_history(uint256, uint256) external view returns (Point memory); function merge(uint256 _from, uint256 _to) external; function safeTransferFrom(address _from, address _to, uint256 _tokenId) external; }
contracts/libraries/VelodromeTimeLibrary.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; library VelodromeTimeLibrary { uint256 internal constant WEEK = 7 days; /// @dev Returns start of epoch based on current timestamp function epochStart(uint256 timestamp) internal pure returns (uint256) { unchecked { return timestamp - (timestamp % WEEK); } } /// @dev Returns start of next epoch / end of current epoch function epochNext(uint256 timestamp) internal pure returns (uint256) { unchecked { return timestamp - (timestamp % WEEK) + WEEK; } } /// @dev Returns start of voting window function epochVoteStart(uint256 timestamp) internal pure returns (uint256) { unchecked { return timestamp - (timestamp % WEEK) + 1 hours; } } /// @dev Returns end of voting window / beginning of unrestricted voting window function epochVoteEnd(uint256 timestamp) internal pure returns (uint256) { unchecked { return timestamp - (timestamp % WEEK) + WEEK - 1 hours; } } }
contracts/v1/sink/SinkManagerFacilitator.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import { IVotingEscrowV1 } from "../../interfaces/v1/IVotingEscrowV1.sol"; import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; /// @notice This contract is used to support merging into the Velodrome SinkManager contract SinkManagerFacilitator is ERC721Holder { constructor() {} function merge(IVotingEscrowV1 _ve, uint256 _from, uint256 _to) external { _ve.merge(_from, _to); } }
@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol) pragma solidity ^0.8.0; import "../IERC721.sol"; /** * @title ERC-721 Non-Fungible Token Standard, optional metadata extension * @dev See https://eips.ethereum.org/EIPS/eip-721 */ interface IERC721Metadata is IERC721 { /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); }
@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/utils/ERC721Holder.sol) pragma solidity ^0.8.0; import "../IERC721Receiver.sol"; /** * @dev Implementation of the {IERC721Receiver} interface. * * Accepts all token transfers. * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or {IERC721-setApprovalForAll}. */ contract ERC721Holder is IERC721Receiver { /** * @dev See {IERC721Receiver-onERC721Received}. * * Always returns `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received(address, address, uint256, bytes memory) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
contracts/governance/IVotes.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; /// Modified IVotes interface for tokenId based voting interface IVotes { /** * @dev Emitted when an account changes their delegate. */ event DelegateChanged(address indexed delegator, uint256 indexed fromDelegate, uint256 indexed toDelegate); /** * @dev Emitted when a token transfer or delegate change results in changes to a delegate's number of votes. */ event DelegateVotesChanged(address indexed delegate, uint256 previousBalance, uint256 newBalance); /** * @dev Returns the amount of votes that `tokenId` had at a specific moment in the past. * If the account passed in is not the owner, returns 0. */ function getPastVotes(address account, uint256 tokenId, uint256 timepoint) external view returns (uint256); /** * @dev Returns the total supply of votes available at a specific moment in the past. If the `clock()` is * configured to use block numbers, this will return the value the end of the corresponding block. * * NOTE: This value is the sum of all available votes, which is not necessarily the sum of all delegated votes. * Votes that have not been delegated are still part of total supply, even though they would not participate in a * vote. */ function getPastTotalSupply(uint256 timepoint) external view returns (uint256); /** * @dev Returns the delegate that `tokenId` has chosen. Can never be equal to the delegator's `tokenId`. * Returns 0 if not delegated. */ function delegates(uint256 tokenId) external view returns (uint256); /** * @dev Delegates votes from the sender to `delegatee`. */ function delegate(uint256 delegator, uint256 delegatee) external; /** * @dev Delegates votes from `delegator` to `delegatee`. Signer must own `delegator`. */ function delegateBySig( uint256 delegator, uint256 delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s ) external; }
@openzeppelin/contracts/access/Ownable.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol) pragma solidity ^0.8.0; import "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * By default, the owner account will be the one that deploys the contract. This * can later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the deployer as the initial owner. */ constructor() { _transferOwnership(_msgSender()); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { require(owner() == _msgSender(), "Ownable: caller is not the owner"); } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { require(newOwner != address(0), "Ownable: new owner is the zero address"); _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
@openzeppelin/contracts/interfaces/IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC165.sol) pragma solidity ^0.8.0; import "../utils/introspection/IERC165.sol";
@openzeppelin/contracts/interfaces/IERC4906.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC4906.sol) pragma solidity ^0.8.0; import "./IERC165.sol"; import "./IERC721.sol"; /// @title EIP-721 Metadata Update Extension interface IERC4906 is IERC165, IERC721 { /// @dev This event emits when the metadata of a token is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFT. event MetadataUpdate(uint256 _tokenId); /// @dev This event emits when the metadata of a range of tokens is changed. /// So that the third-party platforms such as NFT market could /// timely update the images and related attributes of the NFTs. event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); }
@openzeppelin/contracts/interfaces/IERC721.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC721.sol) pragma solidity ^0.8.0; import "../token/ERC721/IERC721.sol";
@openzeppelin/contracts/metatx/ERC2771Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.3) (metatx/ERC2771Context.sol) pragma solidity ^0.8.9; import "../utils/Context.sol"; /** * @dev Context variant with ERC2771 support. */ abstract contract ERC2771Context is Context { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable address private immutable _trustedForwarder; /// @custom:oz-upgrades-unsafe-allow constructor constructor(address trustedForwarder) { _trustedForwarder = trustedForwarder; } function isTrustedForwarder(address forwarder) public view virtual returns (bool) { return forwarder == _trustedForwarder; } function _msgSender() internal view virtual override returns (address sender) { if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) { // The assembly code is more direct than the Solidity version using `abi.decode`. /// @solidity memory-safe-assembly assembly { sender := shr(96, calldataload(sub(calldatasize(), 20))) } } else { return super._msgSender(); } } function _msgData() internal view virtual override returns (bytes calldata) { if (isTrustedForwarder(msg.sender) && msg.data.length >= 20) { return msg.data[:msg.data.length - 20]; } else { return super._msgData(); } } }
@openzeppelin/contracts/utils/Context.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
@openzeppelin/contracts/proxy/Clones.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (proxy/Clones.sol) pragma solidity ^0.8.0; /** * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for * deploying minimal proxy contracts, also known as "clones". * * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies * > a minimal bytecode implementation that delegates all calls to a known, fixed address. * * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2` * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the * deterministic method. * * _Available since v3.4._ */ library Clones { /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create opcode, which should never revert. */ function clone(address implementation) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create(0, 0x09, 0x37) } require(instance != address(0), "ERC1167: create failed"); } /** * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`. * * This function uses the create2 opcode and a `salt` to deterministically deploy * the clone. Using the same `implementation` and `salt` multiple time will revert, since * the clones cannot be deployed twice at the same address. */ function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) { /// @solidity memory-safe-assembly assembly { // Cleans the upper 96 bits of the `implementation` word, then packs the first 3 bytes // of the `implementation` address with the bytecode before the address. mstore(0x00, or(shr(0xe8, shl(0x60, implementation)), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000)) // Packs the remaining 17 bytes of `implementation` with the bytecode after the address. mstore(0x20, or(shl(0x78, implementation), 0x5af43d82803e903d91602b57fd5bf3)) instance := create2(0, 0x09, 0x37, salt) } require(instance != address(0), "ERC1167: create2 failed"); } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt, address deployer ) internal pure returns (address predicted) { /// @solidity memory-safe-assembly assembly { let ptr := mload(0x40) mstore(add(ptr, 0x38), deployer) mstore(add(ptr, 0x24), 0x5af43d82803e903d91602b57fd5bf3ff) mstore(add(ptr, 0x14), implementation) mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73) mstore(add(ptr, 0x58), salt) mstore(add(ptr, 0x78), keccak256(add(ptr, 0x0c), 0x37)) predicted := keccak256(add(ptr, 0x43), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt ) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } }
@openzeppelin/contracts/security/ReentrancyGuard.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol) pragma solidity ^0.8.0; /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } /** * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a * `nonReentrant` function in the call stack. */ function _reentrancyGuardEntered() internal view returns (bool) { return _status == _ENTERED; } }
@openzeppelin/contracts/token/ERC20/IERC20.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
@openzeppelin/contracts/token/ERC721/IERC721.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol) pragma solidity ^0.8.0; import "../../utils/introspection/IERC165.sol"; /** * @dev Required interface of an ERC721 compliant contract. */ interface IERC721 is IERC165 { /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in ``owner``'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /** * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients * are aware of the ERC721 protocol to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom(address from, address to, uint256 tokenId) external; /** * @dev Transfers `tokenId` token from `from` to `to`. * * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721 * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must * understand this adds an external call which potentially creates a reentrancy vulnerability. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 tokenId) external; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll} */ function isApprovedForAll(address owner, address operator) external view returns (bool); }
@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) pragma solidity ^0.8.0; /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); }
@openzeppelin/contracts/utils/introspection/IERC165.sol
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); }
contracts/interfaces/IMinter.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IMinter { error AlreadyNudged(); error NotEpochGovernor(); error TailEmissionsInactive(); event Mint( address indexed _sender, uint256 _weekly, uint256 _circulating_supply, bool indexed _tail ); event Nudge(uint256 indexed _period, uint256 _oldRate, uint256 _newRate); /// @notice Timestamp of start of epoch that updatePeriod was last called in function activePeriod() external returns (uint256); /// @notice Allows epoch governor to modify the tail emission rate by at most 1 basis point /// per epoch to a maximum of 100 basis points or to a minimum of 1 basis point. /// Note: the very first nudge proposal must take place the week prior /// to the tail emission schedule starting. /// @dev Throws if not epoch governor. /// Throws if not currently in tail emission schedule. /// Throws if already nudged this epoch. /// Throws if nudging above maximum rate. /// Throws if nudging below minimum rate. /// This contract is coupled to EpochGovernor as it requires three option simple majority voting. function nudge() external; /// @notice Calculates rebases according to the formula /// weekly * (ve.totalSupply / vara.totalSupply) ^ 3 / 2 /// Note that ve.totalSupply is the locked ve supply /// vara.totalSupply is the total ve supply minted /// @param _minted Amount of VELO minted this epoch /// @return _growth Rebases function calculateGrowth(uint256 _minted) external view returns (uint256 _growth); /// @notice Processes emissions and rebases. Callable once per epoch (1 week). /// @return _period Start of current epoch. function updatePeriod() external returns (uint256 _period); }
contracts/interfaces/ISinkManager.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IVara } from "./IVara.sol"; interface ISinkManager { event ConvertVELO(address indexed who, uint256 amount, uint256 timestamp); event ConvertVe( address indexed who, uint256 indexed tokenId, uint256 indexed tokenIdV2, uint256 amount, uint256 lockEnd, uint256 timestamp ); event ClaimRebaseAndGaugeRewards( address indexed who, uint256 amountResidual, uint256 amountRewarded, uint256 amountRebased, uint256 timestamp ); error ContractNotOwnerOfToken(); error GaugeAlreadySet(); error GaugeNotSet(); error GaugeNotSinkDrain(); error NFTAlreadyConverted(); error NFTNotApproved(); error NFTExpired(); error TokenIdNotSet(); error TokenIdAlreadySet(); function ownedTokenId() external view returns (uint256); function vara() external view returns (IVara); function varaV2() external view returns (IVara); /// @notice Helper utility that returns amount of token captured by epoch function captured(uint256 timestamp) external view returns (uint256 amount); /// @notice User converts their v1 VELO into v2 VELO /// @param amount Amount of VELO to convert function convertVELO(uint256 amount) external; /// @notice User converts their v1 ve into v2 ve /// @param tokenId Token ID of v1 ve /// @return tokenIdV2 Token ID of v2 ve function convertVe(uint256 tokenId) external returns (uint256 tokenIdV2); /// @notice Claim SinkManager-eligible rebase and gauge rewards to lock into the SinkManager-owned tokenId /// @dev Callable by anyone function claimRebaseAndGaugeRewards() external; }
contracts/interfaces/IVara.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; interface IVara is IERC20 { error NotMinter(); error NotOwner(); error NotMinterOrSinkManager(); error SinkManagerAlreadySet(); function mint(address, uint256) external returns (bool); function minter() external returns (address); }
contracts/interfaces/IVotingEscrow.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import {IERC721, IERC721Metadata} from "@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol"; import {IERC4906} from "@openzeppelin/contracts/interfaces/IERC4906.sol"; import {IVotes} from "../governance/IVotes.sol"; interface IVotingEscrow is IVotes, IERC4906, IERC721Metadata { struct LockedBalance { int128 amount; uint256 end; bool isPermanent; } struct UserPoint { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block uint256 permanent; } struct GlobalPoint { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block uint256 permanentLockBalance; } /// @notice A checkpoint for recorded delegated voting weights at a certain timestamp struct Checkpoint { uint256 fromTimestamp; address owner; uint256 delegatedBalance; uint256 delegatee; } enum DepositType { DEPOSIT_FOR_TYPE, CREATE_LOCK_TYPE, INCREASE_LOCK_AMOUNT, INCREASE_UNLOCK_TIME } /// @dev Different types of veNFTs: /// NORMAL - typical veNFT /// LOCKED - veNFT which is locked into a MANAGED veNFT /// MANAGED - veNFT which can accept the deposit of NORMAL veNFTs enum EscrowType { NORMAL, LOCKED, MANAGED } error AlreadyVoted(); error AmountTooBig(); error ERC721ReceiverRejectedTokens(); error ERC721TransferToNonERC721ReceiverImplementer(); error InvalidNonce(); error InvalidSignature(); error InvalidSignatureS(); error InvalidManagedNFTId(); error LockDurationNotInFuture(); error LockDurationTooLong(); error LockExpired(); error LockNotExpired(); error NoLockFound(); error NonExistentToken(); error NotApprovedOrOwner(); error NotDistributor(); error NotEmergencyCouncilOrGovernor(); error NotGovernor(); error NotGovernorOrManager(); error NotManagedNFT(); error NotManagedOrNormalNFT(); error NotLockedNFT(); error NotNormalNFT(); error NotPermanentLock(); error NotOwner(); error NotTeam(); error NotVoter(); error OwnershipChange(); error PermanentLock(); error SameAddress(); error SameNFT(); error SameState(); error SplitNoOwner(); error SplitNotAllowed(); error SignatureExpired(); error TooManyTokenIDs(); error ZeroAddress(); error ZeroAmount(); error ZeroBalance(); event Deposit( address indexed provider, uint256 indexed tokenId, DepositType indexed depositType, uint256 value, uint256 locktime, uint256 ts ); event Withdraw(address indexed provider, uint256 indexed tokenId, uint256 value, uint256 ts); event LockPermanent(address indexed _owner, uint256 indexed _tokenId, uint256 amount, uint256 _ts); event UnlockPermanent(address indexed _owner, uint256 indexed _tokenId, uint256 amount, uint256 _ts); event Supply(uint256 prevSupply, uint256 supply); event Merge( address indexed _sender, uint256 indexed _from, uint256 indexed _to, uint256 _amountFrom, uint256 _amountTo, uint256 _amountFinal, uint256 _locktime, uint256 _ts ); event Split( uint256 indexed _from, uint256 indexed _tokenId1, uint256 indexed _tokenId2, address _sender, uint256 _splitAmount1, uint256 _splitAmount2, uint256 _locktime, uint256 _ts ); event CreateManaged( address indexed _to, uint256 indexed _mTokenId, address indexed _from, address _lockedManagedReward, address _freeManagedReward ); event DepositManaged( address indexed _owner, uint256 indexed _tokenId, uint256 indexed _mTokenId, uint256 _weight, uint256 _ts ); event WithdrawManaged( address indexed _owner, uint256 indexed _tokenId, uint256 indexed _mTokenId, uint256 _weight, uint256 _ts ); event SetAllowedManager(address indexed _allowedManager); // State variables function factoryRegistry() external view returns (address); function token() external view returns (address); function distributor() external view returns (address); function voter() external view returns (address); function team() external view returns (address); function artProxy() external view returns (address); function allowedManager() external view returns (address); function tokenId() external view returns (uint256); /*/////////////////////////////////////////////////////////////// MANAGED NFT STORAGE //////////////////////////////////////////////////////////////*/ /// @dev Mapping of token id to escrow type /// Takes advantage of the fact default value is EscrowType.NORMAL function escrowType(uint256 tokenId) external view returns (EscrowType); /// @dev Mapping of token id to managed id function idToManaged(uint256 tokenId) external view returns (uint256 managedTokenId); /// @dev Mapping of user token id to managed token id to weight of token id function weights(uint256 tokenId, uint256 managedTokenId) external view returns (uint256 weight); /// @dev Mapping of managed id to deactivated state function deactivated(uint256 tokenId) external view returns (bool inactive); /// @dev Mapping from managed nft id to locked managed rewards /// `token` denominated rewards (rebases/rewards) stored in locked managed rewards contract /// to prevent co-mingling of assets function managedToLocked(uint256 tokenId) external view returns (address); /// @dev Mapping from managed nft id to free managed rewards contract /// these rewards can be freely withdrawn by users function managedToFree(uint256 tokenId) external view returns (address); /*/////////////////////////////////////////////////////////////// MANAGED NFT LOGIC //////////////////////////////////////////////////////////////*/ /// @notice Create managed NFT (a permanent lock) for use within ecosystem. /// @dev Throws if address already owns a managed NFT. /// @return _mTokenId managed token id. function createManagedLockFor(address _to) external returns (uint256 _mTokenId); /// @notice Delegates balance to managed nft /// Note that NFTs deposited into a managed NFT will be re-locked /// to the maximum lock time on withdrawal. /// Permanent locks that are deposited will automatically unlock. /// @dev Managed nft will remain max-locked as long as there is at least one /// deposit or withdrawal per week. /// Throws if deposit nft is managed. /// Throws if recipient nft is not managed. /// Throws if deposit nft is already locked. /// Throws if not called by voter. /// @param _tokenId tokenId of NFT being deposited /// @param _mTokenId tokenId of managed NFT that will receive the deposit function depositManaged(uint256 _tokenId, uint256 _mTokenId) external; /// @notice Retrieves locked rewards and withdraws balance from managed nft. /// Note that the NFT withdrawn is re-locked to the maximum lock time. /// @dev Throws if NFT not locked. /// Throws if not called by voter. /// @param _tokenId tokenId of NFT being deposited. function withdrawManaged(uint256 _tokenId) external; /// @notice Permit one address to call createManagedLockFor() that is not Voter.governor() function setAllowedManager(address _allowedManager) external; /// @notice Set Managed NFT state. Inactive NFTs cannot be deposited into. /// @param _mTokenId managed nft state to set /// @param _state true => inactive, false => active function setManagedState(uint256 _mTokenId, bool _state) external; /*/////////////////////////////////////////////////////////////// METADATA STORAGE //////////////////////////////////////////////////////////////*/ function name() external view returns (string memory); function symbol() external view returns (string memory); function version() external view returns (string memory); function decimals() external view returns (uint8); function setTeam(address _team) external; function setArtProxy(address _proxy) external; /// @inheritdoc IERC721Metadata function tokenURI(uint256 tokenId) external view returns (string memory); /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ /// @dev Mapping from owner address to mapping of index to tokenId function ownerToNFTokenIdList(address _owner, uint256 _index) external view returns (uint256 _tokenId); /// @inheritdoc IERC721 function ownerOf(uint256 tokenId) external view returns (address owner); /// @inheritdoc IERC721 function balanceOf(address owner) external view returns (uint256 balance); /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ /// @inheritdoc IERC721 function getApproved(uint256 _tokenId) external view returns (address operator); /// @inheritdoc IERC721 function isApprovedForAll(address owner, address operator) external view returns (bool); /// @notice Check whether spender is owner or an approved user for a given veNFT /// @param _spender . /// @param _tokenId . function isApprovedOrOwner(address _spender, uint256 _tokenId) external returns (bool); /*////////////////////////////////////////////////////////////// ERC721 LOGIC //////////////////////////////////////////////////////////////*/ /// @inheritdoc IERC721 function approve(address to, uint256 tokenId) external; /// @inheritdoc IERC721 function setApprovalForAll(address operator, bool approved) external; /// @inheritdoc IERC721 function transferFrom(address from, address to, uint256 tokenId) external; /// @inheritdoc IERC721 function safeTransferFrom(address from, address to, uint256 tokenId) external; /// @inheritdoc IERC721 function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external; /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 _interfaceID) external view returns (bool); /*////////////////////////////////////////////////////////////// ESCROW STORAGE //////////////////////////////////////////////////////////////*/ function epoch() external view returns (uint256); function supply() external view returns (uint256); function userPointEpoch(uint256 _tokenId) external view returns (uint256 _epoch); /// @notice time -> signed slope change function slopeChanges(uint256 _timestamp) external view returns (int128); /// @notice account -> can split function canSplit(address _account) external view returns (bool); /// @notice Global point history at a given index function pointHistory(uint256 _loc) external view returns (GlobalPoint memory); /// @notice Get the LockedBalance (amount, end) of a _tokenId /// @param _tokenId . /// @return LockedBalance of _tokenId function locked(uint256 _tokenId) external view returns (LockedBalance memory); /// @notice User -> UserPoint[userEpoch] function userPointHistory(uint256 _tokenId, uint256 _loc) external view returns (UserPoint memory); /*////////////////////////////////////////////////////////////// ESCROW LOGIC //////////////////////////////////////////////////////////////*/ /// @notice Record global data to checkpoint function checkpoint() external; /// @notice Deposit `_value` tokens for `_tokenId` and add to the lock /// @dev Anyone (even a smart contract) can deposit for someone else, but /// cannot extend their locktime and deposit for a brand new user /// @param _tokenId lock NFT /// @param _value Amount to add to user's lock function depositFor(uint256 _tokenId, uint256 _value) external; /// @notice Deposit `_value` tokens for `msg.sender` and lock for `_lockDuration` /// @param _value Amount to deposit /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week) /// @return TokenId of created veNFT function createLock(uint256 _value, uint256 _lockDuration) external returns (uint256); /// @notice Deposit `_value` tokens for `_to` and lock for `_lockDuration` /// @param _value Amount to deposit /// @param _lockDuration Number of seconds to lock tokens for (rounded down to nearest week) /// @param _to Address to deposit /// @return TokenId of created veNFT function createLockFor(uint256 _value, uint256 _lockDuration, address _to) external returns (uint256); /// @notice Deposit `_value` additional tokens for `_tokenId` without modifying the unlock time /// @param _value Amount of tokens to deposit and add to the lock function increaseAmount(uint256 _tokenId, uint256 _value) external; /// @notice Extend the unlock time for `_tokenId` /// Cannot extend lock time of permanent locks /// @param _lockDuration New number of seconds until tokens unlock function increaseUnlockTime(uint256 _tokenId, uint256 _lockDuration) external; /// @notice Withdraw all tokens for `_tokenId` /// @dev Only possible if the lock is both expired and not permanent /// This will burn the veNFT. Any rebases or rewards that are unclaimed /// will no longer be claimable. Claim all rebases and rewards prior to calling this. function withdraw(uint256 _tokenId) external; /// @notice Merges `_from` into `_to`. /// @dev Cannot merge `_from` locks that are permanent or have already voted this epoch. /// Cannot merge `_to` locks that have already expired. /// This will burn the veNFT. Any rebases or rewards that are unclaimed /// will no longer be claimable. Claim all rebases and rewards prior to calling this. /// @param _from VeNFT to merge from. /// @param _to VeNFT to merge into. function merge(uint256 _from, uint256 _to) external; /// @notice Splits veNFT into two new veNFTS - one with oldLocked.amount - `_amount`, and the second with `_amount` /// @dev This burns the tokenId of the target veNFT /// Callable by approved or owner /// If this is called by approved, approved will not have permissions to manipulate the newly created veNFTs /// Returns the two new split veNFTs to owner /// If `from` is permanent, will automatically dedelegate. /// This will burn the veNFT. Any rebases or rewards that are unclaimed /// will no longer be claimable. Claim all rebases and rewards prior to calling this. /// @param _from VeNFT to split. /// @param _amount Amount to split from veNFT. /// @return _tokenId1 Return tokenId of veNFT with oldLocked.amount - `_amount`. /// @return _tokenId2 Return tokenId of veNFT with `_amount`. function split(uint256 _from, uint256 _amount) external returns (uint256 _tokenId1, uint256 _tokenId2); /// @notice Toggle split for a specific veNFT. /// @dev Toggle split for address(0) to enable or disable for all. /// @param _account Address to toggle split permissions /// @param _bool True to allow, false to disallow function toggleSplit(address _account, bool _bool) external; /// @notice Permanently lock a veNFT. Voting power will be equal to /// `LockedBalance.amount` with no decay. Required to delegate. /// @dev Only callable by unlocked normal veNFTs. /// @param _tokenId tokenId to lock. function lockPermanent(uint256 _tokenId) external; /// @notice Unlock a permanently locked veNFT. Voting power will decay. /// Will automatically dedelegate if delegated. /// @dev Only callable by permanently locked veNFTs. /// Cannot unlock if already voted this epoch. /// @param _tokenId tokenId to unlock. function unlockPermanent(uint256 _tokenId) external; /*/////////////////////////////////////////////////////////////// GAUGE VOTING STORAGE //////////////////////////////////////////////////////////////*/ /// @notice Get the voting power for _tokenId at the current timestamp /// @dev Returns 0 if called in the same block as a transfer. /// @param _tokenId . /// @return Voting power function balanceOfNFT(uint256 _tokenId) external view returns (uint256); /// @notice Get the voting power for _tokenId at a given timestamp /// @param _tokenId . /// @param _t Timestamp to query voting power /// @return Voting power function balanceOfNFTAt(uint256 _tokenId, uint256 _t) external view returns (uint256); /// @notice Calculate total voting power at current timestamp /// @return Total voting power at current timestamp function totalSupply() external view returns (uint256); /// @notice Calculate total voting power at a given timestamp /// @param _t Timestamp to query total voting power /// @return Total voting power at given timestamp function totalSupplyAt(uint256 _t) external view returns (uint256); /*/////////////////////////////////////////////////////////////// GAUGE VOTING LOGIC //////////////////////////////////////////////////////////////*/ /// @notice See if a queried _tokenId has actively voted /// @param _tokenId . /// @return True if voted, else false function voted(uint256 _tokenId) external view returns (bool); /// @notice Set the global state voter and distributor /// @dev This is only called once, at setup function setVoterAndDistributor(address _voter, address _distributor) external; /// @notice Set `voted` for _tokenId to true or false /// @dev Only callable by voter /// @param _tokenId . /// @param _voted . function voting(uint256 _tokenId, bool _voted) external; /*/////////////////////////////////////////////////////////////// DAO VOTING STORAGE //////////////////////////////////////////////////////////////*/ /// @notice The number of checkpoints for each tokenId function numCheckpoints(uint256 tokenId) external view returns (uint48); /// @notice A record of states for signing / validating signatures function nonces(address account) external view returns (uint256); /// @inheritdoc IVotes function delegates(uint256 delegator) external view returns (uint256); /// @notice A record of delegated token checkpoints for each account, by index /// @param tokenId . /// @param index . /// @return Checkpoint function checkpoints(uint256 tokenId, uint48 index) external view returns (Checkpoint memory); /// @inheritdoc IVotes function getPastVotes(address account, uint256 tokenId, uint256 timestamp) external view returns (uint256); /// @inheritdoc IVotes function getPastTotalSupply(uint256 timestamp) external view returns (uint256); /*/////////////////////////////////////////////////////////////// DAO VOTING LOGIC //////////////////////////////////////////////////////////////*/ /// @inheritdoc IVotes function delegate(uint256 delegator, uint256 delegatee) external; /// @inheritdoc IVotes function delegateBySig( uint256 delegator, uint256 delegatee, uint256 nonce, uint256 expiry, uint8 v, bytes32 r, bytes32 s ) external; }
contracts/interfaces/v1/IGaugeV1.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IGaugeV1 { function balanceOf(address _account) external returns (uint256 _balance); function stake() external returns (address _stake); function totalSupply() external returns (uint256 _totalSupply); function getReward(address _account, address[] memory _tokens) external; function deposit(uint256 _amount, uint256 _tokenId) external; function notifyRewardAmount(address _token, uint256 _amount) external; }
contracts/interfaces/v1/IRewardsDistributorV1.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IRewardsDistributorV1 { function claimable(uint256 _tokenId) external view returns (uint256 _claimable); function claim(uint256 _tokenId) external returns (uint256 _amount); }
contracts/interfaces/v1/IVoterV1.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IVoterV1 { function governor() external returns (address _governor); function totalWeight() external returns (uint256 _totalWeight); function usedWeights(uint256 _tokenId) external returns (uint256 _weight); function votes(uint256 _tokenId, address _pool) external returns (uint256 _votes); function createGauge(address _pool) external returns (address _gauge); function gauges(address pool) external view returns (address); function distribute(address _gauge) external; function poke(uint256 _tokenId) external; function vote(uint256 _tokenId, address[] memory _pools, uint256[] memory _weights) external; }
contracts/interfaces/v1/IVotingEscrowV1.sol
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; interface IVotingEscrowV1 { struct Point { int128 bias; int128 slope; // # -dweight / dt uint256 ts; uint256 blk; // block } function getApproved(uint256 _tokenId) external view returns (address); function isApprovedOrOwner(address _spender, uint256 _tokenId) external returns (bool); function locked__end(uint256 _tokenId) external view returns (uint256 _locked); function locked(uint256 _tokenId) external view returns (int128 _amount, uint256 _end); function ownerOf(uint256 _tokenId) external view returns (address _owner); function increase_amount(uint256 _tokenId, uint256 _amount) external; function increase_unlock_time(uint256 _tokenId, uint256 _duration) external; function create_lock(uint256 _amount, uint256 _end) external returns (uint256 tokenId); function create_lock_for(uint256 _amount, uint256 _end, address _to) external returns (uint256 tokenId); function approve(address who, uint256 tokenId) external; function balanceOfNFT(uint256) external view returns (uint256 amount); function user_point_epoch(uint256) external view returns (uint256); function user_point_history(uint256, uint256) external view returns (Point memory); function merge(uint256 _from, uint256 _to) external; function safeTransferFrom(address _from, address _to, uint256 _tokenId) external; }
contracts/libraries/VelodromeTimeLibrary.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; library VelodromeTimeLibrary { uint256 internal constant WEEK = 7 days; /// @dev Returns start of epoch based on current timestamp function epochStart(uint256 timestamp) internal pure returns (uint256) { unchecked { return timestamp - (timestamp % WEEK); } } /// @dev Returns start of next epoch / end of current epoch function epochNext(uint256 timestamp) internal pure returns (uint256) { unchecked { return timestamp - (timestamp % WEEK) + WEEK; } } /// @dev Returns start of voting window function epochVoteStart(uint256 timestamp) internal pure returns (uint256) { unchecked { return timestamp - (timestamp % WEEK) + 1 hours; } } /// @dev Returns end of voting window / beginning of unrestricted voting window function epochVoteEnd(uint256 timestamp) internal pure returns (uint256) { unchecked { return timestamp - (timestamp % WEEK) + WEEK - 1 hours; } } }
contracts/v1/sink/SinkManagerFacilitator.sol
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.19; import { IVotingEscrowV1 } from "../../interfaces/v1/IVotingEscrowV1.sol"; import { ERC721Holder } from "@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol"; /// @notice This contract is used to support merging into the Velodrome SinkManager contract SinkManagerFacilitator is ERC721Holder { constructor() {} function merge(IVotingEscrowV1 _ve, uint256 _from, uint256 _to) external { _ve.merge(_from, _to); } }
Compiler Settings
{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers"]}},"optimizer":{"runs":200,"enabled":true},"libraries":{}}
Contract ABI
[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_forwarder","internalType":"address"},{"type":"address","name":"_sinkDrain","internalType":"address"},{"type":"address","name":"_facilitatorImplementation","internalType":"address"},{"type":"address","name":"_voter","internalType":"address"},{"type":"address","name":"_vara","internalType":"address"},{"type":"address","name":"_varaV2","internalType":"address"},{"type":"address","name":"_ve","internalType":"address"},{"type":"address","name":"_veV2","internalType":"address"},{"type":"address","name":"_rewardsDistributor","internalType":"address"}]},{"type":"error","name":"ContractNotOwnerOfToken","inputs":[]},{"type":"error","name":"GaugeAlreadySet","inputs":[]},{"type":"error","name":"GaugeNotSet","inputs":[]},{"type":"error","name":"GaugeNotSinkDrain","inputs":[]},{"type":"error","name":"NFTAlreadyConverted","inputs":[]},{"type":"error","name":"NFTExpired","inputs":[]},{"type":"error","name":"NFTNotApproved","inputs":[]},{"type":"error","name":"TokenIdAlreadySet","inputs":[]},{"type":"error","name":"TokenIdNotSet","inputs":[]},{"type":"event","name":"ClaimRebaseAndGaugeRewards","inputs":[{"type":"address","name":"who","internalType":"address","indexed":true},{"type":"uint256","name":"amountResidual","internalType":"uint256","indexed":false},{"type":"uint256","name":"amountRewarded","internalType":"uint256","indexed":false},{"type":"uint256","name":"amountRebased","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ConvertVELO","inputs":[{"type":"address","name":"who","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"ConvertVe","inputs":[{"type":"address","name":"who","internalType":"address","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"uint256","name":"tokenIdV2","internalType":"uint256","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"lockEnd","internalType":"uint256","indexed":false},{"type":"uint256","name":"timestamp","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}],"name":"captured","inputs":[{"type":"uint256","name":"_timestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claimRebaseAndGaugeRewards","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"conversions","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"convertVELO","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"tokenIdV2","internalType":"uint256"}],"name":"convertVe","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"facilitatorImplementation","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"facilitators","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IGaugeV1"}],"name":"gauge","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"isTrustedForwarder","inputs":[{"type":"address","name":"forwarder","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IMinter"}],"name":"minterV2","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC721Received","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"","internalType":"address"},{"type":"uint256","name":"","internalType":"uint256"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"ownedTokenId","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IRewardsDistributorV1"}],"name":"rewardsDistributor","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setOwnedTokenId","inputs":[{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setupSinkDrain","inputs":[{"type":"address","name":"_gauge","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IVara"}],"name":"vara","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IVara"}],"name":"varaV2","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IVotingEscrowV1"}],"name":"ve","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IVotingEscrow"}],"name":"veV2","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IVoterV1"}],"name":"voter","inputs":[]}]
Contract Creation Code
0x6101806040523480156200001257600080fd5b50604051620024ef380380620024ef8339810160408190526200003591620002d9565b6001600160a01b038916608052620000566200005062000224565b62000235565b60018055600680546001600160a01b03808b166001600160a01b031992831617909255600780548a8416921691909117905586811660a05285811660c052841660e0819052604080516303aa30b960e11b8152905163075461729160048082019260209290919082900301816000875af1158015620000d9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620000ff919062000394565b6001600160a01b0390811661010052838116610120819052838216610140528282166101605260c05160405163095ea7b360e01b8152600481019290925260001960248301529091169063095ea7b3906044016020604051808303816000875af115801562000172573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001989190620003b9565b5060e05160405163095ea7b360e01b81526001600160a01b03848116600483015260001960248301529091169063095ea7b3906044016020604051808303816000875af1158015620001ee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620002149190620003b9565b50505050505050505050620003dd565b60006200023062000285565b905090565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6080516000906001600160a01b031633148015620002a4575060143610155b15620002b7575060131936013560601c90565b503390565b80516001600160a01b0381168114620002d457600080fd5b919050565b60008060008060008060008060006101208a8c031215620002f957600080fd5b620003048a620002bc565b98506200031460208b01620002bc565b97506200032460408b01620002bc565b96506200033460608b01620002bc565b95506200034460808b01620002bc565b94506200035460a08b01620002bc565b93506200036460c08b01620002bc565b92506200037460e08b01620002bc565b9150620003856101008b01620002bc565b90509295985092959850929598565b600060208284031215620003a757600080fd5b620003b282620002bc565b9392505050565b600060208284031215620003cc57600080fd5b81518015158114620003b257600080fd5b60805160a05160c05160e05161010051610120516101405161016051611fef620005006000396000818161021d015281816106f5015261078601526000818161037001526112aa0152600081816101c1015281816106770152818161084a015281816108df01528181610e6701528181610f11015281816110cf0152818161115001528181611344015281816113b80152818161144d01528181611768015261193b0152600081816102e901528181610fb0015261162e0152600081816103ee0152818161120701526117f00152600081816104150152818161047b01528181610516015281816105d001526116dd0152600081816102440152818161095a01528181610d7c01526114c70152600081816102890152611c280152611fef6000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c80637482cb13116100c3578063d0de8ee21161007c578063d0de8ee214610392578063e3679450146103a5578063e4d7766b146103ae578063f2fde38b146103d6578063fcd4cf60146103e9578063fd84b53b1461041057600080fd5b80637482cb13146102e45780638da5cb5b1461030b578063a6f19c841461031c578063b1e991c11461032f578063b50c276514610342578063c865b7841461036b57600080fd5b80633f2a5540116101155780633f2a55401461021857806346c96aac1461023f5780634cab93ae14610266578063572b6c0514610279578063629b0ff4146102c9578063715018a6146102dc57600080fd5b8063150b7a02146101525780631c9893901461018e5780631f850716146101bc578063324528ff146101fb5780633b53d6f014610205575b600080fd5b610170610160366004611ca1565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020015b60405180910390f35b6101ae61019c366004611d81565b60036020526000908152604090205481565b604051908152602001610185565b6101e37f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610185565b610203610437565b005b610203610213366004611d9a565b610a24565b6101e37f000000000000000000000000000000000000000000000000000000000000000081565b6101e37f000000000000000000000000000000000000000000000000000000000000000081565b6101ae610274366004611d81565b610def565b6102b9610287366004611d9a565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0390811691161490565b6040519015158152602001610185565b6102036102d7366004611d81565b6115fb565b6102036118de565b6101e37f000000000000000000000000000000000000000000000000000000000000000081565b6000546001600160a01b03166101e3565b6008546101e3906001600160a01b031681565b6007546101e3906001600160a01b031681565b6101e3610350366004611d81565b6004602052600090815260409020546001600160a01b031681565b6101e37f000000000000000000000000000000000000000000000000000000000000000081565b6102036103a0366004611d81565b6118f2565b6101ae60055481565b6101ae6103bc366004611d81565b62093a808106900360009081526009602052604090205490565b6102036103e4366004611d9a565b6119d2565b6101e37f000000000000000000000000000000000000000000000000000000000000000081565b6101e37f000000000000000000000000000000000000000000000000000000000000000081565b6008546001600160a01b0316610460576040516361877ef360e01b815260040160405180910390fd5b6005546040516370a0823160e01b81523060048201526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906370a0823190602401602060405180830381865afa1580156104ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ee9190611dbe565b60408051600180825281830190925291925060009190602080830190803683370190505090507f00000000000000000000000000000000000000000000000000000000000000008160008151811061054857610548611dd7565b6001600160a01b0392831660209182029290920101526008546040516331279d3d60e01b81529116906331279d3d906105879030908590600401611e31565b600060405180830381600087803b1580156105a157600080fd5b505af11580156105b5573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031691506370a0823190602401602060405180830381865afa158015610620573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106449190611dbe565b905060006106528483611e73565b905081156106dc576040516350c1d7a960e11b815260048101869052602481018390527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a183af5290604401600060405180830381600087803b1580156106c357600080fd5b505af11580156106d7573d6000803e3d6000fd5b505050505b60405163d1d58b2560e01b8152600481018690526000907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063d1d58b2590602401602060405180830381865afa158015610744573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107689190611dbe565b905080156107fd5760405163379607f560e01b8152600481018790527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063379607f5906024016020604051808303816000875af11580156107d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb9190611dbe565b505b600062093a8080610812630784ce0042611e86565b61081c9190611e99565b6108269190611ebb565b604051635a2d1e0760e11b8152600481018990529091506000906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b45a3c0e906024016040805180830381865afa158015610890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b49190611ed2565b915050808211156109445760405163a4d855df60e01b815260048101899052630784ce0060248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a4d855df90604401600060405180830381600087803b15801561092b57600080fd5b505af115801561093f573d6000803e3d6000fd5b505050505b60405163032145f960e41b8152600481018990527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906332145f9090602401600060405180830381600087803b1580156109a657600080fd5b505af11580156109ba573d6000803e3d6000fd5b505050506109c6611a50565b60408051898152602081018790529081018590524260608201526001600160a01b0391909116907fac162ad79ec08307123947685e1233c9f2e5d5b672fdd396127a0443a3ac1c8a9060800160405180910390a25050505050505050565b610a2c611a5f565b6005546000819003610a515760405163295fa13d60e11b815260040160405180910390fd5b6008546001600160a01b031615610a7b5760405163291f9deb60e01b815260040160405180910390fd5b600880546001600160a01b0319166001600160a01b03841690811790915560408051633a4b66f160e01b8152905160009291633a4b66f1916004808301926020929190829003018187875af1158015610ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610afc9190611f06565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610b46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6a9190611dbe565b60405163095ea7b360e01b81526001600160a01b038681166004830152602482018390529192509083169063095ea7b3906044016020604051808303816000875af1158015610bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be19190611f23565b50600854604051631c57762b60e31b815260048101839052600060248201526001600160a01b039091169063e2bbb15890604401600060405180830381600087803b158015610c2f57600080fd5b505af1158015610c43573d6000803e3d6000fd5b506000925060019150610c539050565b604051908082528060200260200182016040528015610c7c578160200160208202803683370190505b506040805160018082528183019092529192506000919060208083019080368337505060085460408051633a4b66f160e01b815290519394506001600160a01b0390911692633a4b66f19250600480830192602092919082900301816000875af1158015610cee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d129190611f06565b82600081518110610d2557610d25611dd7565b60200260200101906001600160a01b031690816001600160a01b031681525050600181600081518110610d5a57610d5a611dd7565b6020908102919091010152604051637ac09bf760e01b81526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690637ac09bf790610db590889086908690600401611f45565b600060405180830381600087803b158015610dcf57600080fd5b505af1158015610de3573d6000803e3d6000fd5b50505050505050505050565b6000610df9611ad8565b6005546000819003610e1e5760405163295fa13d60e11b815260040160405180910390fd5b60008381526003602052604090205415610e4b57604051632fc4601360e01b815260040160405180910390fd5b60405163430c208160e01b8152306004820152602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063430c2081906044016020604051808303816000875af1158015610eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edc9190611f23565b610ef95760405163876dcc9f60e01b815260040160405180910390fd5b60405163f8a0576360e01b81526004810184905242907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f8a0576390602401602060405180830381865afa158015610f60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f849190611dbe565b11610fa257604051637bdb3cff60e11b815260040160405180910390fd5b6000610fac611a50565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a83627de6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561100e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110329190611dbe565b506007546002805460009261109e926001600160a01b0390911691849061105890611fa0565b9182905550611068600143611e73565b40604051602001611083929190918252602082015260400190565b60405160208183030381529060405280519060200120611b31565b604051632142170760e11b81526001600160a01b0384811660048301528083166024830152604482018890529192507f0000000000000000000000000000000000000000000000000000000000000000909116906342842e0e90606401600060405180830381600087803b15801561111557600080fd5b505af1158015611129573d6000803e3d6000fd5b5050604051635a2d1e0760e11b815260048101889052600092508291506001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063b45a3c0e906024016040805180830381865afa158015611196573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ba9190611ed2565b9092509050600f82900b600062093a806111d48142611e99565b6111de9190611ebb565b6111e89084611e73565b6040516340c10f1960e01b8152306004820152602481018490529091507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316906340c10f19906044016020604051808303816000875af1158015611258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127c9190611f23565b5060405163ec32e6df60e01b815260048101839052602481018290526001600160a01b0387811660448301527f0000000000000000000000000000000000000000000000000000000000000000169063ec32e6df906064016020604051808303816000875af11580156112f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113179190611dbe565b60055460405163095ea7b360e01b81526001600160a01b03888116600483015260248201929092529199507f0000000000000000000000000000000000000000000000000000000000000000169063095ea7b390604401600060405180830381600087803b15801561138857600080fd5b505af115801561139c573d6000803e3d6000fd5b505060055460405163231ee78560e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018e90526044820192909252908816925063463dcf0a9150606401600060405180830381600087803b15801561141657600080fd5b505af115801561142a573d6000803e3d6000fd5b505060055460405163095ea7b360e01b81526000600482015260248101919091527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316925063095ea7b39150604401600060405180830381600087803b15801561149b57600080fd5b505af11580156114af573d6000803e3d6000fd5b505060405163032145f960e41b8152600481018a90527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031692506332145f909150602401600060405180830381600087803b15801561151557600080fd5b505af1158015611529573d6000803e3d6000fd5b50505060008a81526003602090815260408083208c90556004909152812080546001600160a01b0319166001600160a01b0389161790558391506009906115754262093a808106900390565b815260200190815260200160002060008282546115929190611e86565b909155505060408051838152602081018590524281830152905189918b916001600160a01b038a16917f4a19e049996501b0c4add7667734ac63234004e7247d17e7df0d6dcce3674cef919081900360600190a4505050505050506115f660018055565b919050565b60055460008190036116205760405163295fa13d60e11b815260040160405180910390fd5b600061162a611a50565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663a83627de6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561168c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b09190611dbe565b506040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018590527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd906064016020604051808303816000875af1158015611726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174a9190611f23565b506040516350c1d7a960e11b815260048101839052602481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a183af5290604401600060405180830381600087803b1580156117b457600080fd5b505af11580156117c8573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b038481166004830152602482018790527f00000000000000000000000000000000000000000000000000000000000000001692506340c10f1991506044016020604051808303816000875af115801561183b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185f9190611f23565b5082600960006118744262093a808106900390565b815260200190815260200160002060008282546118919190611e86565b9091555050604080518481524260208201526001600160a01b038316917f57c3d16df660889ba8f21574179e9d1f0f795ff6f75b827ad0790583e321f8c0910160405180910390a2505050565b6118e6611a5f565b6118f06000611bd4565b565b6118fa611a5f565b6005541561191b5760405163403b2b6760e01b815260040160405180910390fd5b6040516331a9108f60e11b81526004810182905230906001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690636352211e90602401602060405180830381865afa158015611982573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a69190611f06565b6001600160a01b0316146119cd5760405163160112d960e31b815260040160405180910390fd5b600555565b6119da611a5f565b6001600160a01b038116611a445760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b611a4d81611bd4565b50565b6000611a5a611c24565b905090565b611a67611a50565b6001600160a01b0316611a826000546001600160a01b031690565b6001600160a01b0316146118f05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611a3b565b600260015403611b2a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611a3b565b6002600155565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116611bce5760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401611a3b565b92915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031633148015611c5f575060143610155b15611c71575060131936013560601c90565b503390565b6001600160a01b0381168114611a4d57600080fd5b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215611cb757600080fd5b8435611cc281611c76565b93506020850135611cd281611c76565b925060408501359150606085013567ffffffffffffffff80821115611cf657600080fd5b818701915087601f830112611d0a57600080fd5b813581811115611d1c57611d1c611c8b565b604051601f8201601f19908116603f01168101908382118183101715611d4457611d44611c8b565b816040528281528a6020848701011115611d5d57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600060208284031215611d9357600080fd5b5035919050565b600060208284031215611dac57600080fd5b8135611db781611c76565b9392505050565b600060208284031215611dd057600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b83811015611e265781516001600160a01b031687529582019590820190600101611e01565b509495945050505050565b6001600160a01b0383168152604060208201819052600090611e5590830184611ded565b949350505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611bce57611bce611e5d565b80820180821115611bce57611bce611e5d565b600082611eb657634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611bce57611bce611e5d565b60008060408385031215611ee557600080fd5b825180600f0b8114611ef657600080fd5b6020939093015192949293505050565b600060208284031215611f1857600080fd5b8151611db781611c76565b600060208284031215611f3557600080fd5b81518015158114611db757600080fd5b83815260006020606081840152611f5f6060840186611ded565b838103604085015284518082528286019183019060005b81811015611f9257835183529284019291840191600101611f76565b509098975050505050505050565b600060018201611fb257611fb2611e5d565b506001019056fea2646970667358221220a961f0abf7985f09ae3097c1ce770fcbe6d4555a7eee6c5fd64242c87e74d9a764736f6c63430008130033000000000000000000000000c6eaf7d353d9901375be2d8f9ba38dd58524d8b300000000000000000000000087e7742fe8cb0ef71f6fc21344a20fb0ce9c03620000000000000000000000004c0846c484d7a6a9639b20e1828e3337bbc8d7d7000000000000000000000000842d477f8ce0efbb669ddc2ace21816b9a841ee4000000000000000000000000e1da44c0da55b075ae8e2e4b6986adc76ac77d73000000000000000000000000b6a075e9cf5dba476994b63b60217a5cf9ab272700000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a0000000000000000000000004937fcfaf9fbd139b78d95a128425a19721c3072000000000000000000000000411bb8829a14d56356485df13cc6a00c9ddf19db
Deployed ByteCode
0x608060405234801561001057600080fd5b506004361061014d5760003560e01c80637482cb13116100c3578063d0de8ee21161007c578063d0de8ee214610392578063e3679450146103a5578063e4d7766b146103ae578063f2fde38b146103d6578063fcd4cf60146103e9578063fd84b53b1461041057600080fd5b80637482cb13146102e45780638da5cb5b1461030b578063a6f19c841461031c578063b1e991c11461032f578063b50c276514610342578063c865b7841461036b57600080fd5b80633f2a5540116101155780633f2a55401461021857806346c96aac1461023f5780634cab93ae14610266578063572b6c0514610279578063629b0ff4146102c9578063715018a6146102dc57600080fd5b8063150b7a02146101525780631c9893901461018e5780631f850716146101bc578063324528ff146101fb5780633b53d6f014610205575b600080fd5b610170610160366004611ca1565b630a85bd0160e11b949350505050565b6040516001600160e01b031990911681526020015b60405180910390f35b6101ae61019c366004611d81565b60036020526000908152604090205481565b604051908152602001610185565b6101e37f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a81565b6040516001600160a01b039091168152602001610185565b610203610437565b005b610203610213366004611d9a565b610a24565b6101e37f000000000000000000000000411bb8829a14d56356485df13cc6a00c9ddf19db81565b6101e37f000000000000000000000000842d477f8ce0efbb669ddc2ace21816b9a841ee481565b6101ae610274366004611d81565b610def565b6102b9610287366004611d9a565b7f000000000000000000000000c6eaf7d353d9901375be2d8f9ba38dd58524d8b36001600160a01b0390811691161490565b6040519015158152602001610185565b6102036102d7366004611d81565b6115fb565b6102036118de565b6101e37f000000000000000000000000871ea7a1be3dae44e5fa72eb0980a31870388d6381565b6000546001600160a01b03166101e3565b6008546101e3906001600160a01b031681565b6007546101e3906001600160a01b031681565b6101e3610350366004611d81565b6004602052600090815260409020546001600160a01b031681565b6101e37f0000000000000000000000004937fcfaf9fbd139b78d95a128425a19721c307281565b6102036103a0366004611d81565b6118f2565b6101ae60055481565b6101ae6103bc366004611d81565b62093a808106900360009081526009602052604090205490565b6102036103e4366004611d9a565b6119d2565b6101e37f000000000000000000000000b6a075e9cf5dba476994b63b60217a5cf9ab272781565b6101e37f000000000000000000000000e1da44c0da55b075ae8e2e4b6986adc76ac77d7381565b6008546001600160a01b0316610460576040516361877ef360e01b815260040160405180910390fd5b6005546040516370a0823160e01b81523060048201526000907f000000000000000000000000e1da44c0da55b075ae8e2e4b6986adc76ac77d736001600160a01b0316906370a0823190602401602060405180830381865afa1580156104ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104ee9190611dbe565b60408051600180825281830190925291925060009190602080830190803683370190505090507f000000000000000000000000e1da44c0da55b075ae8e2e4b6986adc76ac77d738160008151811061054857610548611dd7565b6001600160a01b0392831660209182029290920101526008546040516331279d3d60e01b81529116906331279d3d906105879030908590600401611e31565b600060405180830381600087803b1580156105a157600080fd5b505af11580156105b5573d6000803e3d6000fd5b50506040516370a0823160e01b8152306004820152600092507f000000000000000000000000e1da44c0da55b075ae8e2e4b6986adc76ac77d736001600160a01b031691506370a0823190602401602060405180830381865afa158015610620573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106449190611dbe565b905060006106528483611e73565b905081156106dc576040516350c1d7a960e11b815260048101869052602481018390527f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a6001600160a01b03169063a183af5290604401600060405180830381600087803b1580156106c357600080fd5b505af11580156106d7573d6000803e3d6000fd5b505050505b60405163d1d58b2560e01b8152600481018690526000907f000000000000000000000000411bb8829a14d56356485df13cc6a00c9ddf19db6001600160a01b03169063d1d58b2590602401602060405180830381865afa158015610744573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107689190611dbe565b905080156107fd5760405163379607f560e01b8152600481018790527f000000000000000000000000411bb8829a14d56356485df13cc6a00c9ddf19db6001600160a01b03169063379607f5906024016020604051808303816000875af11580156107d7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fb9190611dbe565b505b600062093a8080610812630784ce0042611e86565b61081c9190611e99565b6108269190611ebb565b604051635a2d1e0760e11b8152600481018990529091506000906001600160a01b037f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a169063b45a3c0e906024016040805180830381865afa158015610890573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108b49190611ed2565b915050808211156109445760405163a4d855df60e01b815260048101899052630784ce0060248201527f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a6001600160a01b03169063a4d855df90604401600060405180830381600087803b15801561092b57600080fd5b505af115801561093f573d6000803e3d6000fd5b505050505b60405163032145f960e41b8152600481018990527f000000000000000000000000842d477f8ce0efbb669ddc2ace21816b9a841ee46001600160a01b0316906332145f9090602401600060405180830381600087803b1580156109a657600080fd5b505af11580156109ba573d6000803e3d6000fd5b505050506109c6611a50565b60408051898152602081018790529081018590524260608201526001600160a01b0391909116907fac162ad79ec08307123947685e1233c9f2e5d5b672fdd396127a0443a3ac1c8a9060800160405180910390a25050505050505050565b610a2c611a5f565b6005546000819003610a515760405163295fa13d60e11b815260040160405180910390fd5b6008546001600160a01b031615610a7b5760405163291f9deb60e01b815260040160405180910390fd5b600880546001600160a01b0319166001600160a01b03841690811790915560408051633a4b66f160e01b8152905160009291633a4b66f1916004808301926020929190829003018187875af1158015610ad8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610afc9190611f06565b6040516370a0823160e01b81523060048201529091506000906001600160a01b038316906370a0823190602401602060405180830381865afa158015610b46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b6a9190611dbe565b60405163095ea7b360e01b81526001600160a01b038681166004830152602482018390529192509083169063095ea7b3906044016020604051808303816000875af1158015610bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be19190611f23565b50600854604051631c57762b60e31b815260048101839052600060248201526001600160a01b039091169063e2bbb15890604401600060405180830381600087803b158015610c2f57600080fd5b505af1158015610c43573d6000803e3d6000fd5b506000925060019150610c539050565b604051908082528060200260200182016040528015610c7c578160200160208202803683370190505b506040805160018082528183019092529192506000919060208083019080368337505060085460408051633a4b66f160e01b815290519394506001600160a01b0390911692633a4b66f19250600480830192602092919082900301816000875af1158015610cee573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d129190611f06565b82600081518110610d2557610d25611dd7565b60200260200101906001600160a01b031690816001600160a01b031681525050600181600081518110610d5a57610d5a611dd7565b6020908102919091010152604051637ac09bf760e01b81526001600160a01b037f000000000000000000000000842d477f8ce0efbb669ddc2ace21816b9a841ee41690637ac09bf790610db590889086908690600401611f45565b600060405180830381600087803b158015610dcf57600080fd5b505af1158015610de3573d6000803e3d6000fd5b50505050505050505050565b6000610df9611ad8565b6005546000819003610e1e5760405163295fa13d60e11b815260040160405180910390fd5b60008381526003602052604090205415610e4b57604051632fc4601360e01b815260040160405180910390fd5b60405163430c208160e01b8152306004820152602481018490527f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a6001600160a01b03169063430c2081906044016020604051808303816000875af1158015610eb8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610edc9190611f23565b610ef95760405163876dcc9f60e01b815260040160405180910390fd5b60405163f8a0576360e01b81526004810184905242907f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a6001600160a01b03169063f8a0576390602401602060405180830381865afa158015610f60573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f849190611dbe565b11610fa257604051637bdb3cff60e11b815260040160405180910390fd5b6000610fac611a50565b90507f000000000000000000000000871ea7a1be3dae44e5fa72eb0980a31870388d636001600160a01b031663a83627de6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561100e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110329190611dbe565b506007546002805460009261109e926001600160a01b0390911691849061105890611fa0565b9182905550611068600143611e73565b40604051602001611083929190918252602082015260400190565b60405160208183030381529060405280519060200120611b31565b604051632142170760e11b81526001600160a01b0384811660048301528083166024830152604482018890529192507f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a909116906342842e0e90606401600060405180830381600087803b15801561111557600080fd5b505af1158015611129573d6000803e3d6000fd5b5050604051635a2d1e0760e11b815260048101889052600092508291506001600160a01b037f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a169063b45a3c0e906024016040805180830381865afa158015611196573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111ba9190611ed2565b9092509050600f82900b600062093a806111d48142611e99565b6111de9190611ebb565b6111e89084611e73565b6040516340c10f1960e01b8152306004820152602481018490529091507f000000000000000000000000b6a075e9cf5dba476994b63b60217a5cf9ab27276001600160a01b0316906340c10f19906044016020604051808303816000875af1158015611258573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061127c9190611f23565b5060405163ec32e6df60e01b815260048101839052602481018290526001600160a01b0387811660448301527f0000000000000000000000004937fcfaf9fbd139b78d95a128425a19721c3072169063ec32e6df906064016020604051808303816000875af11580156112f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113179190611dbe565b60055460405163095ea7b360e01b81526001600160a01b03888116600483015260248201929092529199507f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a169063095ea7b390604401600060405180830381600087803b15801561138857600080fd5b505af115801561139c573d6000803e3d6000fd5b505060055460405163231ee78560e11b81526001600160a01b037f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a81166004830152602482018e90526044820192909252908816925063463dcf0a9150606401600060405180830381600087803b15801561141657600080fd5b505af115801561142a573d6000803e3d6000fd5b505060055460405163095ea7b360e01b81526000600482015260248101919091527f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a6001600160a01b0316925063095ea7b39150604401600060405180830381600087803b15801561149b57600080fd5b505af11580156114af573d6000803e3d6000fd5b505060405163032145f960e41b8152600481018a90527f000000000000000000000000842d477f8ce0efbb669ddc2ace21816b9a841ee46001600160a01b031692506332145f909150602401600060405180830381600087803b15801561151557600080fd5b505af1158015611529573d6000803e3d6000fd5b50505060008a81526003602090815260408083208c90556004909152812080546001600160a01b0319166001600160a01b0389161790558391506009906115754262093a808106900390565b815260200190815260200160002060008282546115929190611e86565b909155505060408051838152602081018590524281830152905189918b916001600160a01b038a16917f4a19e049996501b0c4add7667734ac63234004e7247d17e7df0d6dcce3674cef919081900360600190a4505050505050506115f660018055565b919050565b60055460008190036116205760405163295fa13d60e11b815260040160405180910390fd5b600061162a611a50565b90507f000000000000000000000000871ea7a1be3dae44e5fa72eb0980a31870388d636001600160a01b031663a83627de6040518163ffffffff1660e01b81526004016020604051808303816000875af115801561168c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116b09190611dbe565b506040516323b872dd60e01b81526001600160a01b038281166004830152306024830152604482018590527f000000000000000000000000e1da44c0da55b075ae8e2e4b6986adc76ac77d7316906323b872dd906064016020604051808303816000875af1158015611726573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061174a9190611f23565b506040516350c1d7a960e11b815260048101839052602481018490527f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a6001600160a01b03169063a183af5290604401600060405180830381600087803b1580156117b457600080fd5b505af11580156117c8573d6000803e3d6000fd5b50506040516340c10f1960e01b81526001600160a01b038481166004830152602482018790527f000000000000000000000000b6a075e9cf5dba476994b63b60217a5cf9ab27271692506340c10f1991506044016020604051808303816000875af115801561183b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061185f9190611f23565b5082600960006118744262093a808106900390565b815260200190815260200160002060008282546118919190611e86565b9091555050604080518481524260208201526001600160a01b038316917f57c3d16df660889ba8f21574179e9d1f0f795ff6f75b827ad0790583e321f8c0910160405180910390a2505050565b6118e6611a5f565b6118f06000611bd4565b565b6118fa611a5f565b6005541561191b5760405163403b2b6760e01b815260040160405180910390fd5b6040516331a9108f60e11b81526004810182905230906001600160a01b037f00000000000000000000000035361c9c2a324f5fb8f3aed2d7ba91ce1410893a1690636352211e90602401602060405180830381865afa158015611982573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119a69190611f06565b6001600160a01b0316146119cd5760405163160112d960e31b815260040160405180910390fd5b600555565b6119da611a5f565b6001600160a01b038116611a445760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b611a4d81611bd4565b50565b6000611a5a611c24565b905090565b611a67611a50565b6001600160a01b0316611a826000546001600160a01b031690565b6001600160a01b0316146118f05760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401611a3b565b600260015403611b2a5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606401611a3b565b6002600155565b6000763d602d80600a3d3981f3363d3d373d3d3d363d730000008360601b60e81c176000526e5af43d82803e903d91602b57fd5bf38360781b1760205281603760096000f590506001600160a01b038116611bce5760405162461bcd60e51b815260206004820152601760248201527f455243313136373a2063726561746532206661696c65640000000000000000006044820152606401611a3b565b92915050565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b60007f000000000000000000000000c6eaf7d353d9901375be2d8f9ba38dd58524d8b36001600160a01b031633148015611c5f575060143610155b15611c71575060131936013560601c90565b503390565b6001600160a01b0381168114611a4d57600080fd5b634e487b7160e01b600052604160045260246000fd5b60008060008060808587031215611cb757600080fd5b8435611cc281611c76565b93506020850135611cd281611c76565b925060408501359150606085013567ffffffffffffffff80821115611cf657600080fd5b818701915087601f830112611d0a57600080fd5b813581811115611d1c57611d1c611c8b565b604051601f8201601f19908116603f01168101908382118183101715611d4457611d44611c8b565b816040528281528a6020848701011115611d5d57600080fd5b82602086016020830137600060208483010152809550505050505092959194509250565b600060208284031215611d9357600080fd5b5035919050565b600060208284031215611dac57600080fd5b8135611db781611c76565b9392505050565b600060208284031215611dd057600080fd5b5051919050565b634e487b7160e01b600052603260045260246000fd5b600081518084526020808501945080840160005b83811015611e265781516001600160a01b031687529582019590820190600101611e01565b509495945050505050565b6001600160a01b0383168152604060208201819052600090611e5590830184611ded565b949350505050565b634e487b7160e01b600052601160045260246000fd5b81810381811115611bce57611bce611e5d565b80820180821115611bce57611bce611e5d565b600082611eb657634e487b7160e01b600052601260045260246000fd5b500490565b8082028115828204841417611bce57611bce611e5d565b60008060408385031215611ee557600080fd5b825180600f0b8114611ef657600080fd5b6020939093015192949293505050565b600060208284031215611f1857600080fd5b8151611db781611c76565b600060208284031215611f3557600080fd5b81518015158114611db757600080fd5b83815260006020606081840152611f5f6060840186611ded565b838103604085015284518082528286019183019060005b81811015611f9257835183529284019291840191600101611f76565b509098975050505050505050565b600060018201611fb257611fb2611e5d565b506001019056fea2646970667358221220a961f0abf7985f09ae3097c1ce770fcbe6d4555a7eee6c5fd64242c87e74d9a764736f6c63430008130033