Latest 25 from a total of 11,883 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw | 418135976 | 27 days ago | IN | 0 ETH | 0.00000153 | ||||
| Harvest Rewards | 418135914 | 27 days ago | IN | 0 ETH | 0.00000189 | ||||
| Withdraw | 414283374 | 38 days ago | IN | 0 ETH | 0.00001978 | ||||
| Withdraw | 402549543 | 72 days ago | IN | 0 ETH | 0.00002084 | ||||
| Harvest Rewards | 400851734 | 77 days ago | IN | 0 ETH | 0.00000083 | ||||
| Withdraw | 400850154 | 77 days ago | IN | 0 ETH | 0.00000154 | ||||
| Withdraw | 400849578 | 77 days ago | IN | 0 ETH | 0.00000173 | ||||
| Withdraw | 400848522 | 77 days ago | IN | 0 ETH | 0.00000156 | ||||
| Withdraw | 400847956 | 77 days ago | IN | 0 ETH | 0.00000213 | ||||
| Withdraw | 392264234 | 102 days ago | IN | 0 ETH | 0.00000347 | ||||
| Harvest Rewards | 392264093 | 102 days ago | IN | 0 ETH | 0.00000351 | ||||
| Withdraw | 389576014 | 110 days ago | IN | 0 ETH | 0.00000157 | ||||
| Withdraw | 388722007 | 112 days ago | IN | 0 ETH | 0.00000246 | ||||
| Withdraw | 388719364 | 112 days ago | IN | 0 ETH | 0.00000343 | ||||
| Withdraw | 387173484 | 117 days ago | IN | 0 ETH | 0.00000154 | ||||
| Withdraw | 386992719 | 117 days ago | IN | 0 ETH | 0.00000154 | ||||
| Harvest Rewards | 385245737 | 122 days ago | IN | 0 ETH | 0.0000015 | ||||
| Harvest Rewards | 378192069 | 143 days ago | IN | 0 ETH | 0.00000056 | ||||
| Withdraw | 378192012 | 143 days ago | IN | 0 ETH | 0.00000111 | ||||
| Withdraw | 376751604 | 147 days ago | IN | 0 ETH | 0.00000185 | ||||
| Withdraw | 371754998 | 161 days ago | IN | 0 ETH | 0.00000179 | ||||
| Withdraw | 364722538 | 181 days ago | IN | 0 ETH | 0.00000157 | ||||
| Harvest Rewards | 362076757 | 189 days ago | IN | 0 ETH | 0.00000174 | ||||
| Harvest Rewards | 360845038 | 193 days ago | IN | 0 ETH | 0.00000286 | ||||
| Withdraw | 360844969 | 193 days ago | IN | 0 ETH | 0.00000641 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
APTFarm
Compiler Version
v0.8.10+commit.fc410830
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import {Ownable2Step} from "openzeppelin-contracts/contracts/access/Ownable2Step.sol";
import {EnumerableMap} from "openzeppelin-contracts/contracts/utils/structs/EnumerableMap.sol";
import {ReentrancyGuard} from "openzeppelin-contracts/contracts/security/ReentrancyGuard.sol";
import {IERC20, IERC20Metadata} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {SafeERC20} from "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol";
import {IAPTFarm, IRewarder} from "./interfaces/IAPTFarm.sol";
/**
* @notice Unlike MasterChefJoeV3, the APTFarm contract gives out a set number of joe tokens per seconds to every farm configured
* These Joe tokens needs to be deposited on the contract first.
*/
contract APTFarm is Ownable2Step, ReentrancyGuard, IAPTFarm {
using EnumerableMap for EnumerableMap.AddressToUintMap;
using SafeERC20 for IERC20;
uint256 private constant ACC_TOKEN_PRECISION = 1e36;
uint256 private constant MAX_JOE_PER_SEC = 100e18;
/**
* @notice Whether if the given token already has a farm or not.
*/
EnumerableMap.AddressToUintMap private _vaultsWithFarms;
/**
* @dev Info of each individual farm.
*/
FarmInfo[] private _farmInfo;
/**
* @dev Info of each user that stakes APT tokens.
*/
mapping(uint256 => mapping(address => UserInfo)) private _userInfo;
/**
* @notice Address of the joe token.
*/
IERC20 public immutable override joe;
/**
* @notice Accounted balances of AP tokens in the farm.
*/
mapping(IERC20 => uint256) public override apTokenBalances;
/**
* @dev joePerSec is limited to 100 tokens per second to avoid overflow issues
* @param joePerSec The amount of joe tokens that will be given per second.
*/
modifier validateJoePerSec(uint256 joePerSec) {
if (joePerSec > MAX_JOE_PER_SEC) {
revert APTFarm__InvalidJoePerSec();
}
_;
}
/**
* @dev Checks if the given amount is not zero.
* @param amount The amount to validate.
*/
modifier nonZeroAmount(uint256 amount) {
if (amount == 0) {
revert APTFarm__ZeroAmount();
}
_;
}
/**
* @dev Checks if the given array is not empty.
* @param array The uint256 array to validate.
*/
modifier validateArrayLength(uint256[] calldata array) {
if (array.length == 0) {
revert APTFarm__EmptyArray();
}
_;
}
/**
* @param _joe The joe token contract address.
*/
constructor(IERC20 _joe) {
if (address(_joe) == address(0)) {
revert APTFarm__ZeroAddress();
}
joe = _joe;
}
/**
* @notice Returns the number of APTFarm farms.
*/
function farmLength() external view override returns (uint256 farms) {
farms = _farmInfo.length;
}
/**
* @notice Returns true if the given APT token has a farm.
* @param apToken Address of the APT ERC-20 token.
*/
function hasFarm(address apToken) external view override returns (bool) {
return _vaultsWithFarms.contains(apToken);
}
/**
* @notice Returns the farm id of the given APT token.
* @param apToken Address of the APT ERC-20 token.
*/
function vaultFarmId(address apToken) external view override returns (uint256) {
return _vaultsWithFarms.get(apToken);
}
/**
* @notice Returns informations about the farm at the given index.
* @param index The index of the farm.
* @return farm The farm informations.
*/
function farmInfo(uint256 index) external view override returns (FarmInfo memory farm) {
farm = _farmInfo[index];
}
/**
* @notice Returns informations about the user in the given farm.
* @param index The index of the farm.
* @param user The address of the user.
* @return info The user informations.
*/
function userInfo(uint256 index, address user) external view override returns (UserInfo memory info) {
info = _userInfo[index][user];
}
/**
* @notice Add a new APT to the farm set. Can only be called by the owner.
* @param joePerSec Initial number of joe tokens per second streamed to the farm.
* @param apToken Address of the APT ERC-20 token.
* @param rewarder Address of the rewarder delegate.
*/
function add(uint256 joePerSec, IERC20 apToken, IRewarder rewarder)
external
override
onlyOwner
validateJoePerSec(joePerSec)
{
if (address(apToken) == address(joe)) {
revert APTFarm__InvalidAPToken();
}
uint256 newPid = _farmInfo.length;
if (!_vaultsWithFarms.set(address(apToken), newPid)) {
revert APTFarm__TokenAlreadyHasFarm(address(apToken));
}
_farmInfo.push(
FarmInfo({
apToken: apToken,
lastRewardTimestamp: block.timestamp,
accJoePerShare: 0,
joePerSec: joePerSec,
rewarder: rewarder
})
);
// Sanity check to ensure apToken is an ERC20 token
apToken.balanceOf(address(this));
// Sanity check if we add a rewarder
if (address(rewarder) != address(0)) {
rewarder.onJoeReward(address(0), 0, 0);
}
emit Add(newPid, joePerSec, apToken, rewarder);
}
/**
* @notice Update the given farm's joe allocation point and `IRewarder` contract. Can only be called by the owner.
* @param pid The index of the farm. See `_farmInfo`.
* @param joePerSec New joe per sec streamed to the farm.
* @param rewarder Address of the rewarder delegate.
* @param overwrite True if _rewarder should be `set`. Otherwise `_rewarder` is ignored.
*/
function set(uint256 pid, uint256 joePerSec, IRewarder rewarder, bool overwrite)
external
override
onlyOwner
validateJoePerSec(joePerSec)
{
FarmInfo memory farm = _updateFarm(pid);
farm.joePerSec = joePerSec;
if (overwrite) {
farm.rewarder = rewarder;
rewarder.onJoeReward(address(0), 0, apTokenBalances[farm.apToken]); // sanity check
}
_farmInfo[pid] = farm;
emit Set(pid, joePerSec, overwrite ? rewarder : farm.rewarder, overwrite);
}
/**
* @notice View function to see pending joe on frontend.
* @param pid The index of the farm. See `_farmInfo`.
* @param user Address of user.
* @return pendingJoe joe reward for a given user.
* @return bonusTokenAddress The address of the bonus reward.
* @return bonusTokenSymbol The symbol of the bonus token.
* @return pendingBonusToken The amount of bonus rewards pending.
*/
function pendingTokens(uint256 pid, address user)
external
view
override
returns (
uint256 pendingJoe,
address bonusTokenAddress,
string memory bonusTokenSymbol,
uint256 pendingBonusToken
)
{
FarmInfo memory farm = _farmInfo[pid];
UserInfo storage userInfoCached = _userInfo[pid][user];
if (block.timestamp > farm.lastRewardTimestamp) {
uint256 apTokenSupply = apTokenBalances[farm.apToken];
_refreshFarmState(farm, apTokenSupply);
}
pendingJoe = (userInfoCached.amount * farm.accJoePerShare) / ACC_TOKEN_PRECISION - userInfoCached.rewardDebt
+ userInfoCached.unpaidRewards;
// If it's a double reward farm, we return info about the bonus token
IRewarder rewarder = farm.rewarder;
if (address(rewarder) != address(0)) {
bonusTokenAddress = address(rewarder.rewardToken());
(bool success, bytes memory data) =
bonusTokenAddress.staticcall(abi.encodeWithSelector(IERC20Metadata.symbol.selector));
if (success && data.length > 0) {
bonusTokenSymbol = abi.decode(data, (string));
}
pendingBonusToken = rewarder.pendingTokens(user);
}
}
/**
* @notice Deposit APT tokens to the APTFarm for joe allocation.
* @param pid The index of the farm. See `_farmInfo`.
* @param amount APT token amount to deposit.
*/
function deposit(uint256 pid, uint256 amount) external override nonReentrant nonZeroAmount(amount) {
FarmInfo memory farm = _updateFarm(pid);
UserInfo storage user = _userInfo[pid][msg.sender];
(uint256 userAmountBefore, uint256 userRewardDebt, uint256 userUnpaidRewards) =
(user.amount, user.rewardDebt, user.unpaidRewards);
uint256 balanceBefore = farm.apToken.balanceOf(address(this));
farm.apToken.safeTransferFrom(msg.sender, address(this), amount);
uint256 receivedAmount = farm.apToken.balanceOf(address(this)) - balanceBefore;
uint256 userAmount = userAmountBefore + receivedAmount;
uint256 apTokenBalanceBefore = apTokenBalances[farm.apToken];
user.rewardDebt = (userAmount * farm.accJoePerShare) / ACC_TOKEN_PRECISION;
user.amount = userAmount;
apTokenBalances[farm.apToken] = apTokenBalanceBefore + receivedAmount;
if (userAmountBefore > 0 || userUnpaidRewards > 0) {
user.unpaidRewards = _harvest(userAmountBefore, userRewardDebt, userUnpaidRewards, pid, farm.accJoePerShare);
}
IRewarder _rewarder = farm.rewarder;
if (address(_rewarder) != address(0)) {
_rewarder.onJoeReward(msg.sender, userAmount, apTokenBalanceBefore);
}
emit Deposit(msg.sender, pid, receivedAmount);
}
/**
* @notice Withdraw APT tokens from the APTFarm.
* @param pid The index of the farm. See `_farmInfo`.
* @param amount APT token amount to withdraw.
*/
function withdraw(uint256 pid, uint256 amount) external override nonReentrant nonZeroAmount(amount) {
FarmInfo memory farm = _updateFarm(pid);
UserInfo storage user = _userInfo[pid][msg.sender];
(uint256 userAmountBefore, uint256 userRewardDebt, uint256 userUnpaidRewards) =
(user.amount, user.rewardDebt, user.unpaidRewards);
if (userAmountBefore < amount) {
revert APTFarm__InsufficientDeposit(userAmountBefore, amount);
}
uint256 userAmount = userAmountBefore - amount;
uint256 apTokenBalanceBefore = apTokenBalances[farm.apToken];
user.rewardDebt = (userAmount * farm.accJoePerShare) / ACC_TOKEN_PRECISION;
user.amount = userAmount;
apTokenBalances[farm.apToken] = apTokenBalanceBefore - amount;
if (userAmountBefore > 0 || userUnpaidRewards > 0) {
user.unpaidRewards = _harvest(userAmountBefore, userRewardDebt, userUnpaidRewards, pid, farm.accJoePerShare);
}
IRewarder _rewarder = farm.rewarder;
if (address(_rewarder) != address(0)) {
_rewarder.onJoeReward(msg.sender, userAmount, apTokenBalanceBefore);
}
farm.apToken.safeTransfer(msg.sender, amount);
emit Withdraw(msg.sender, pid, amount);
}
/**
* @notice Withdraw without caring about rewards. EMERGENCY ONLY.
* @param pid The index of the farm. See `_farmInfo`.
*/
function emergencyWithdraw(uint256 pid) external override nonReentrant {
FarmInfo memory farm = _farmInfo[pid];
UserInfo storage user = _userInfo[pid][msg.sender];
uint256 amount = user.amount;
uint256 apTokenBalanceBefore = apTokenBalances[farm.apToken];
user.amount = 0;
user.rewardDebt = 0;
apTokenBalances[farm.apToken] = apTokenBalanceBefore - amount;
IRewarder _rewarder = farm.rewarder;
if (address(_rewarder) != address(0)) {
_rewarder.onJoeReward(msg.sender, 0, apTokenBalanceBefore);
}
// Note: transfer can fail or succeed if `amount` is zero.
farm.apToken.safeTransfer(msg.sender, amount);
emit EmergencyWithdraw(msg.sender, pid, amount);
}
/**
* @notice Harvest rewards from the APTFarm for all the given farms.
* @param pids The indices of the farms to harvest from.
*/
function harvestRewards(uint256[] calldata pids) external override nonReentrant validateArrayLength(pids) {
uint256 length = pids.length;
for (uint256 i = 0; i < length; i++) {
uint256 pid = pids[i];
FarmInfo memory farm = _updateFarm(pid);
UserInfo storage user = _userInfo[pid][msg.sender];
(uint256 userAmount, uint256 userRewardDebt, uint256 userUnpaidRewards) =
(user.amount, user.rewardDebt, user.unpaidRewards);
user.rewardDebt = (userAmount * farm.accJoePerShare) / ACC_TOKEN_PRECISION;
if (userAmount > 0 || userUnpaidRewards > 0) {
user.unpaidRewards = _harvest(userAmount, userRewardDebt, userUnpaidRewards, pid, farm.accJoePerShare);
}
IRewarder rewarder = farm.rewarder;
if (address(rewarder) != address(0)) {
rewarder.onJoeReward(msg.sender, userAmount, apTokenBalances[farm.apToken]);
}
}
emit BatchHarvest(msg.sender, pids);
}
/**
* @notice Allows owner to withdraw any tokens that have been sent to the APTFarm by mistake.
* @param token The address of the AP token to skim.
* @param to The address to send the AP token to.
*/
function skim(IERC20 token, address to) external override onlyOwner {
uint256 contractBalance = token.balanceOf(address(this));
uint256 totalDeposits = apTokenBalances[token];
if (contractBalance > totalDeposits) {
uint256 amount = contractBalance - totalDeposits;
token.safeTransfer(to, amount);
emit Skim(address(token), to, amount);
}
}
/**
* @dev Get the new farm state if time passed since last update.
* @dev View function that needs to be commited if effectively updating the farm.
* @param farm The farm to update.
* @param apTokenSupply The total amount of APT tokens in the farm.
*/
function _refreshFarmState(FarmInfo memory farm, uint256 apTokenSupply) internal view {
if (apTokenSupply > 0) {
uint256 secondsElapsed = block.timestamp - farm.lastRewardTimestamp;
uint256 joeReward = secondsElapsed * farm.joePerSec;
farm.accJoePerShare = farm.accJoePerShare + (joeReward * ACC_TOKEN_PRECISION) / apTokenSupply;
}
farm.lastRewardTimestamp = block.timestamp;
}
/**
* @dev Updates the farm's state if time passed since last update.
* @dev Uses `_getNewFarmState` and commit the new farm state.
* @param pid The index of the farm. See `_farmInfo`.
*/
function _updateFarm(uint256 pid) internal returns (FarmInfo memory) {
FarmInfo memory farm = _farmInfo[pid];
if (farm.lastRewardTimestamp == 0) revert APTFarm__InvalidFarmIndex();
if (block.timestamp > farm.lastRewardTimestamp) {
uint256 apTokenSupply = apTokenBalances[farm.apToken];
_refreshFarmState(farm, apTokenSupply);
_farmInfo[pid] = farm;
emit UpdateFarm(pid, farm.lastRewardTimestamp, apTokenSupply, farm.accJoePerShare);
}
return farm;
}
/**
* @dev Harvests the pending JOE rewards for the given farm.
* @param userAmount The amount of APT tokens staked by the user.
* @param userRewardDebt The reward debt of the user.
* @param pid The index of the farm. See `_farmInfo`.
* @param farmAccJoePerShare The accumulated JOE per share of the farm.
*/
function _harvest(
uint256 userAmount,
uint256 userRewardDebt,
uint256 userUnpaidRewards,
uint256 pid,
uint256 farmAccJoePerShare
) internal returns (uint256) {
uint256 pending = (userAmount * farmAccJoePerShare) / ACC_TOKEN_PRECISION - userRewardDebt + userUnpaidRewards;
uint256 contractBalance = joe.balanceOf(address(this));
if (contractBalance < pending) {
userUnpaidRewards = pending - contractBalance;
pending = contractBalance;
} else {
userUnpaidRewards = 0;
}
joe.safeTransfer(msg.sender, pending);
emit Harvest(msg.sender, pid, pending, userUnpaidRewards);
return userUnpaidRewards;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (access/Ownable2Step.sol)
pragma solidity ^0.8.0;
import "./Ownable.sol";
/**
* @dev Contract module which provides 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} and {acceptOwnership}.
*
* This module is used through inheritance. It will make available all functions
* from parent (Ownable).
*/
abstract contract Ownable2Step is Ownable {
address private _pendingOwner;
event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner);
/**
* @dev Returns the address of the pending owner.
*/
function pendingOwner() public view virtual returns (address) {
return _pendingOwner;
}
/**
* @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one.
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual override onlyOwner {
_pendingOwner = newOwner;
emit OwnershipTransferStarted(owner(), newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner.
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual override {
delete _pendingOwner;
super._transferOwnership(newOwner);
}
/**
* @dev The new owner accepts the ownership transfer.
*/
function acceptOwnership() external {
address sender = _msgSender();
require(pendingOwner() == sender, "Ownable2Step: caller is not the new owner");
_transferOwnership(sender);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableMap.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableMap.js.
pragma solidity ^0.8.0;
import "./EnumerableSet.sol";
/**
* @dev Library for managing an enumerable variant of Solidity's
* https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
* type.
*
* Maps have the following properties:
*
* - Entries are added, removed, and checked for existence in constant time
* (O(1)).
* - Entries are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableMap for EnumerableMap.UintToAddressMap;
*
* // Declare a set state variable
* EnumerableMap.UintToAddressMap private myMap;
* }
* ```
*
* The following map types are supported:
*
* - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
* - `address -> uint256` (`AddressToUintMap`) since v4.6.0
* - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
* - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
* - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableMap.
* ====
*/
library EnumerableMap {
using EnumerableSet for EnumerableSet.Bytes32Set;
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Map type with
// bytes32 keys and values.
// The Map implementation uses private functions, and user-facing
// implementations (such as Uint256ToAddressMap) are just wrappers around
// the underlying Map.
// This means that we can only create new EnumerableMaps for types that fit
// in bytes32.
struct Bytes32ToBytes32Map {
// Storage of keys
EnumerableSet.Bytes32Set _keys;
mapping(bytes32 => bytes32) _values;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(
Bytes32ToBytes32Map storage map,
bytes32 key,
bytes32 value
) internal returns (bool) {
map._values[key] = value;
return map._keys.add(key);
}
/**
* @dev Removes a key-value pair from a map. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
delete map._values[key];
return map._keys.remove(key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
return map._keys.contains(key);
}
/**
* @dev Returns the number of key-value pairs in the map. O(1).
*/
function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
return map._keys.length();
}
/**
* @dev Returns the key-value pair stored at position `index` in the map. O(1).
*
* Note that there are no guarantees on the ordering of entries inside the
* array, and it may change when more entries are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
bytes32 key = map._keys.at(index);
return (key, map._values[key]);
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
bytes32 value = map._values[key];
if (value == bytes32(0)) {
return (contains(map, key), bytes32(0));
} else {
return (true, value);
}
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");
return value;
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToBytes32Map storage map,
bytes32 key,
string memory errorMessage
) internal view returns (bytes32) {
bytes32 value = map._values[key];
require(value != 0 || contains(map, key), errorMessage);
return value;
}
// UintToUintMap
struct UintToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(
UintToUintMap storage map,
uint256 key,
uint256 value
) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the set. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key)));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
UintToUintMap storage map,
uint256 key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(key), errorMessage));
}
// UintToAddressMap
struct UintToAddressMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(
UintToAddressMap storage map,
uint256 key,
address value
) internal returns (bool) {
return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
return remove(map._inner, bytes32(key));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
return contains(map._inner, bytes32(key));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(UintToAddressMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the set. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (uint256(key), address(uint160(uint256(value))));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
return (success, address(uint160(uint256(value))));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
UintToAddressMap storage map,
uint256 key,
string memory errorMessage
) internal view returns (address) {
return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));
}
// AddressToUintMap
struct AddressToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(
AddressToUintMap storage map,
address key,
uint256 value
) internal returns (bool) {
return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(AddressToUintMap storage map, address key) internal returns (bool) {
return remove(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
return contains(map._inner, bytes32(uint256(uint160(key))));
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(AddressToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the set. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (address(uint160(uint256(key))), uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
AddressToUintMap storage map,
address key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));
}
// Bytes32ToUintMap
struct Bytes32ToUintMap {
Bytes32ToBytes32Map _inner;
}
/**
* @dev Adds a key-value pair to a map, or updates the value for an existing
* key. O(1).
*
* Returns true if the key was added to the map, that is if it was not
* already present.
*/
function set(
Bytes32ToUintMap storage map,
bytes32 key,
uint256 value
) internal returns (bool) {
return set(map._inner, key, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the key was removed from the map, that is if it was present.
*/
function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
return remove(map._inner, key);
}
/**
* @dev Returns true if the key is in the map. O(1).
*/
function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
return contains(map._inner, key);
}
/**
* @dev Returns the number of elements in the map. O(1).
*/
function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
return length(map._inner);
}
/**
* @dev Returns the element stored at position `index` in the set. O(1).
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
(bytes32 key, bytes32 value) = at(map._inner, index);
return (key, uint256(value));
}
/**
* @dev Tries to returns the value associated with `key`. O(1).
* Does not revert if `key` is not in the map.
*/
function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
(bool success, bytes32 value) = tryGet(map._inner, key);
return (success, uint256(value));
}
/**
* @dev Returns the value associated with `key`. O(1).
*
* Requirements:
*
* - `key` must be in the map.
*/
function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
return uint256(get(map._inner, key));
}
/**
* @dev Same as {get}, with a custom error message when `key` is not in the map.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryGet}.
*/
function get(
Bytes32ToUintMap storage map,
bytes32 key,
string memory errorMessage
) internal view returns (uint256) {
return uint256(get(map._inner, key, errorMessage));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
/**
* @dev Interface for the optional metadata functions from the ERC20 standard.
*
* _Available since v4.1._
*/
interface IERC20Metadata is IERC20 {
/**
* @dev Returns the name of the token.
*/
function name() external view returns (string memory);
/**
* @dev Returns the symbol of the token.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the decimals places of the token.
*/
function decimals() external view returns (uint8);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {IRewarder} from "./IRewarder.sol";
interface IAPTFarm {
error APTFarm__InvalidAPToken();
error APTFarm__ZeroAmount();
error APTFarm__EmptyArray();
error APTFarm__ZeroAddress();
error APTFarm__InvalidJoePerSec();
error APTFarm__InvalidFarmIndex();
error APTFarm__TokenAlreadyHasFarm(address apToken);
error APTFarm__InsufficientDeposit(uint256 deposit, uint256 amountWithdrawn);
event Add(uint256 indexed pid, uint256 allocPoint, IERC20 indexed apToken, IRewarder indexed rewarder);
event Set(uint256 indexed pid, uint256 allocPoint, IRewarder indexed rewarder, bool overwrite);
event Deposit(address indexed user, uint256 indexed pid, uint256 amount);
event Withdraw(address indexed user, uint256 indexed pid, uint256 amount);
event UpdateFarm(uint256 indexed pid, uint256 lastRewardTimestamp, uint256 lpSupply, uint256 accJoePerShare);
event Harvest(address indexed user, uint256 indexed pid, uint256 amount, uint256 unpaidAmount);
event BatchHarvest(address indexed user, uint256[] pids);
event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount);
event Skim(address indexed token, address indexed to, uint256 amount);
/**
* @notice Info of each APTFarm user.
* `amount` LP token amount the user has provided.
* `rewardDebt` The amount of JOE entitled to the user.
* `unpaidRewards` The amount of JOE that could not be transferred to the user.
*/
struct UserInfo {
uint256 amount;
uint256 rewardDebt;
uint256 unpaidRewards;
}
/**
* @notice Info of each APTFarm farm.
* `apToken` Address of the LP token.
* `accJoePerShare` Accumulated JOE per share.
* `lastRewardTimestamp` Last timestamp that JOE distribution occurs.
* `joePerSec` JOE tokens distributed per second.
* `rewarder` Address of the rewarder contract that handles the distribution of bonus tokens.
*/
struct FarmInfo {
IERC20 apToken;
uint256 accJoePerShare;
uint256 lastRewardTimestamp;
uint256 joePerSec;
IRewarder rewarder;
}
function joe() external view returns (IERC20 joe);
function hasFarm(address apToken) external view returns (bool hasFarm);
function vaultFarmId(address apToken) external view returns (uint256 vaultFarmId);
function apTokenBalances(IERC20 apToken) external view returns (uint256 apTokenBalance);
function farmLength() external view returns (uint256 farmLength);
function farmInfo(uint256 pid) external view returns (FarmInfo memory farmInfo);
function userInfo(uint256 pid, address user) external view returns (UserInfo memory userInfo);
function add(uint256 joePerSec, IERC20 apToken, IRewarder rewarder) external;
function set(uint256 pid, uint256 joePerSec, IRewarder rewarder, bool overwrite) external;
function pendingTokens(uint256 pid, address user)
external
view
returns (
uint256 pendingJoe,
address bonusTokenAddress,
string memory bonusTokenSymbol,
uint256 pendingBonusToken
);
function deposit(uint256 pid, uint256 amount) external;
function withdraw(uint256 pid, uint256 amount) external;
function harvestRewards(uint256[] calldata pids) external;
function emergencyWithdraw(uint256 pid) external;
function skim(IERC20 token, address to) external;
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* By default, the owner account will be the one that deploys the contract. This
* can later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.10;
import {IERC20} from "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol";
interface IRewarder {
function onJoeReward(address user, uint256 newLpAmount, uint256 aptSupply) external;
function pendingTokens(address user) external view returns (uint256 pending);
function rewardToken() external view returns (IERC20);
}// 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;
}
}{
"remappings": [
"clones-with-immutable-args/=lib/joe-v2-vault/lib/clones-with-immutable-args/src/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/joe-v2/lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-std/=lib/forge-std/src/",
"joe-dex-lens/=lib/joe-dex-lens/src/",
"joe-v2-1/=lib/joe-v2/src/",
"joe-v2-periphery/=lib/joe-v2-vault/lib/joe-v2-periphery/src/",
"joe-v2-vault/=lib/joe-v2-vault/src/",
"joe-v2/=lib/joe-v2/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/openzeppelin-contracts/contracts/",
"solrary/=lib/joe-dex-lens/lib/solrary/src/",
"lib/forge-std:ds-test/=lib/forge-std/lib/ds-test/src/",
"lib/joe-dex-lens:ds-test/=lib/joe-dex-lens/lib/forge-std/lib/ds-test/src/",
"lib/joe-dex-lens:erc4626-tests/=lib/joe-dex-lens/lib/openzeppelin-contracts/lib/erc4626-tests/",
"lib/joe-dex-lens:forge-std/=lib/joe-dex-lens/lib/forge-std/src/",
"lib/joe-dex-lens:joe-v2-1/=lib/joe-dex-lens/lib/joe-v2/src/",
"lib/joe-dex-lens:joe-v2/=lib/joe-dex-lens/lib/joe-v2/src/",
"lib/joe-dex-lens:openzeppelin-contracts/=lib/joe-dex-lens/lib/openzeppelin-contracts/",
"lib/joe-dex-lens:openzeppelin/=lib/joe-dex-lens/lib/openzeppelin-contracts/contracts/",
"lib/joe-dex-lens:solrary/=lib/joe-dex-lens/lib/solrary/src/",
"lib/joe-v2:ds-test/=lib/joe-v2/lib/forge-std/lib/ds-test/src/",
"lib/joe-v2:erc4626-tests/=lib/joe-v2/lib/openzeppelin-contracts/lib/erc4626-tests/",
"lib/joe-v2:forge-std/=lib/joe-v2/lib/forge-std/src/",
"lib/joe-v2:openzeppelin-contracts/=lib/joe-v2/lib/openzeppelin-contracts/",
"lib/joe-v2:openzeppelin/=lib/joe-v2/lib/openzeppelin-contracts/contracts/",
"lib/joe-v2-vault:clones-with-immutable-args/=lib/joe-v2-vault/lib/clones-with-immutable-args/src/",
"lib/joe-v2-vault:ds-test/=lib/joe-v2-vault/lib/forge-std/lib/ds-test/src/",
"lib/joe-v2-vault:erc4626-tests/=lib/joe-v2-vault/lib/joe-v2/lib/openzeppelin-contracts/lib/erc4626-tests/",
"lib/joe-v2-vault:forge-std/=lib/joe-v2-vault/lib/forge-std/src/",
"lib/joe-v2-vault:joe-v2-periphery/=lib/joe-v2-vault/lib/joe-v2-periphery/src/",
"lib/joe-v2-vault:joe-v2/=lib/joe-v2-vault/lib/joe-v2/src/",
"lib/joe-v2-vault:openzeppelin-contracts-upgradeable/=lib/joe-v2-vault/lib/openzeppelin-contracts-upgradeable/",
"lib/joe-v2-vault:openzeppelin-contracts/=lib/joe-v2-vault/lib/openzeppelin-contracts/",
"lib/joe-v2-vault:openzeppelin-upgradeable/=lib/joe-v2-vault/lib/openzeppelin-contracts-upgradeable/contracts/",
"lib/joe-v2-vault:openzeppelin/=lib/joe-v2-vault/lib/openzeppelin-contracts/contracts/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs"
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IERC20","name":"_joe","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"APTFarm__EmptyArray","type":"error"},{"inputs":[{"internalType":"uint256","name":"deposit","type":"uint256"},{"internalType":"uint256","name":"amountWithdrawn","type":"uint256"}],"name":"APTFarm__InsufficientDeposit","type":"error"},{"inputs":[],"name":"APTFarm__InvalidAPToken","type":"error"},{"inputs":[],"name":"APTFarm__InvalidFarmIndex","type":"error"},{"inputs":[],"name":"APTFarm__InvalidJoePerSec","type":"error"},{"inputs":[{"internalType":"address","name":"apToken","type":"address"}],"name":"APTFarm__TokenAlreadyHasFarm","type":"error"},{"inputs":[],"name":"APTFarm__ZeroAddress","type":"error"},{"inputs":[],"name":"APTFarm__ZeroAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":true,"internalType":"contract IERC20","name":"apToken","type":"address"},{"indexed":true,"internalType":"contract IRewarder","name":"rewarder","type":"address"}],"name":"Add","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"pids","type":"uint256[]"}],"name":"BatchHarvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"EmergencyWithdraw","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"unpaidAmount","type":"uint256"}],"name":"Harvest","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"allocPoint","type":"uint256"},{"indexed":true,"internalType":"contract IRewarder","name":"rewarder","type":"address"},{"indexed":false,"internalType":"bool","name":"overwrite","type":"bool"}],"name":"Set","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Skim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastRewardTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accJoePerShare","type":"uint256"}],"name":"UpdateFarm","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"joePerSec","type":"uint256"},{"internalType":"contract IERC20","name":"apToken","type":"address"},{"internalType":"contract IRewarder","name":"rewarder","type":"address"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"name":"apTokenBalances","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"farmInfo","outputs":[{"components":[{"internalType":"contract IERC20","name":"apToken","type":"address"},{"internalType":"uint256","name":"accJoePerShare","type":"uint256"},{"internalType":"uint256","name":"lastRewardTimestamp","type":"uint256"},{"internalType":"uint256","name":"joePerSec","type":"uint256"},{"internalType":"contract IRewarder","name":"rewarder","type":"address"}],"internalType":"struct IAPTFarm.FarmInfo","name":"farm","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"farmLength","outputs":[{"internalType":"uint256","name":"farms","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"pids","type":"uint256[]"}],"name":"harvestRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"apToken","type":"address"}],"name":"hasFarm","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"joe","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"pendingTokens","outputs":[{"internalType":"uint256","name":"pendingJoe","type":"uint256"},{"internalType":"address","name":"bonusTokenAddress","type":"address"},{"internalType":"string","name":"bonusTokenSymbol","type":"string"},{"internalType":"uint256","name":"pendingBonusToken","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"joePerSec","type":"uint256"},{"internalType":"contract IRewarder","name":"rewarder","type":"address"},{"internalType":"bool","name":"overwrite","type":"bool"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"}],"name":"skim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"},{"internalType":"address","name":"user","type":"address"}],"name":"userInfo","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"unpaidRewards","type":"uint256"}],"internalType":"struct IAPTFarm.UserInfo","name":"info","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"apToken","type":"address"}],"name":"vaultFarmId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a06040523480156200001157600080fd5b5060405162002599380380620025998339810160408190526200003491620000f8565b6200003f336200007e565b60016002556001600160a01b0381166200006c5760405163dd3fd5e560e01b815260040160405180910390fd5b6001600160a01b03166080526200012a565b600180546001600160a01b0319169055620000a581620000a8602090811b6200162a17901c565b50565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6000602082840312156200010b57600080fd5b81516001600160a01b03811681146200012357600080fd5b9392505050565b60805161243e6200015b600039600081816102e101528181610d67015281816118c90152611964015261243e6000f3fe608060405234801561001057600080fd5b506004361061012c5760003560e01c80638a48a515116100ad578063b985a3a011610071578063b985a3a0146102dc578063e2bbb15814610303578063e30c397814610316578063f2fde38b14610327578063ffcd42631461033a57600080fd5b80638a48a515146102475780638da5cb5b1461024f5780639032a7441461027457806393f1a40b14610294578063ab7de098146102c957600080fd5b8063715018a6116100f4578063715018a6146101a557806371e10b4f146101ad57806379ba5097146101d05780637d21c967146101d857806388bba42f1461023457600080fd5b80632a4561151461013157806333eec66c14610146578063441a3e701461016c5780635312ea8e1461017f578063712b772f14610192575b600080fd5b61014461013f366004611f4d565b61035d565b005b610159610154366004611fd7565b610538565b6040519081526020015b60405180910390f35b61014461017a366004611ff4565b61054b565b61014461018d366004612016565b61075d565b6101446101a036600461202f565b6108fa565b610144610a08565b6101c06101bb366004611fd7565b610a1c565b6040519015158152602001610163565b610144610a29565b6101eb6101e6366004612016565b610aa0565b604051610163919081516001600160a01b039081168252602080840151908301526040808401519083015260608084015190830152608092830151169181019190915260a00190565b610144610242366004612076565b610b1b565b600654610159565b6000546001600160a01b03165b6040516001600160a01b039091168152602001610163565b610159610282366004611fd7565b60086020526000908152604090205481565b6102a76102a23660046120c0565b610cc5565b6040805182518152602080840151908201529181015190820152606001610163565b6101446102d73660046120e5565b610d32565b61025c7f000000000000000000000000000000000000000000000000000000000000000081565b610144610311366004611ff4565b61103c565b6001546001600160a01b031661025c565b610144610335366004611fd7565b61130e565b61034d6103483660046120c0565b61137f565b604051610163949392919061217f565b61036561167a565b81818061038557604051630751bbfd60e41b815260040160405180910390fd5b8260005b818110156104e35760008686838181106103a5576103a56121ba565b90506020020135905060006103b9826116d2565b600083815260076020908152604080832033845282529091208054600182015460028301549385015194955091939092906ec097ce7bc90715b34b9f10000000009061040590856121e6565b61040f9190612205565b6001850155821515806104225750600081115b1561043e57610438838383898960200151611869565b60028501555b60808501516001600160a01b038116156104c95785516001600160a01b0390811660009081526008602052604090819020549051632f42225960e21b81529183169163bd088964916104969133918991600401612227565b600060405180830381600087803b1580156104b057600080fd5b505af11580156104c4573d6000803e3d6000fd5b505050505b5050505050505080806104db90612248565b915050610389565b50336001600160a01b03167f672035d5c6b584aaca0cbb0a127e92656163e2dd362713b114fd41350220e368868660405161051f929190612263565b60405180910390a25050506105346001600255565b5050565b60006105456003836119d4565b92915050565b61055361167a565b808061057257604051637510b3bf60e11b815260040160405180910390fd5b600061057d846116d2565b600085815260076020908152604080832033845290915290208054600182015460028301549394509192909190868310156105da57604051631f2d6a6160e31b815260048101849052602481018890526044015b60405180910390fd5b60006105e6888561229f565b86516001600160a01b031660009081526008602090815260409091205490880151919250906ec097ce7bc90715b34b9f10000000009061062690846121e6565b6106309190612205565b6001870155818655610642898261229f565b87516001600160a01b03166000908152600860205260409020558415158061066a5750600083115b15610686576106808585858d8b60200151611869565b60028701555b60808701516001600160a01b038116156106fd57604051632f42225960e21b81526001600160a01b0382169063bd088964906106ca90339087908790600401612227565b600060405180830381600087803b1580156106e457600080fd5b505af11580156106f8573d6000803e3d6000fd5b505050505b8751610713906001600160a01b0316338c6119f0565b6040518a81528b9033907ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689060200160405180910390a35050505050505050506105346001600255565b61076561167a565b60006006828154811061077a5761077a6121ba565b600091825260208083206040805160a081018252600590940290910180546001600160a01b039081168552600180830154868601526002830154868501526003830154606087015260049092015481166080860152878652600784528286203387528452828620805486519092168752600890945291852054858455908301949094559193509161080b828261229f565b84516001600160a01b0390811660009081526008602052604090209190915560808501519081161561089b57604051632f42225960e21b81526001600160a01b0382169063bd088964906108689033906000908790600401612227565b600060405180830381600087803b15801561088257600080fd5b505af1158015610896573d6000803e3d6000fd5b505050505b84516108b1906001600160a01b031633856119f0565b604051838152869033907fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae05959060200160405180910390a350505050506108f76001600255565b50565b610902611a58565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015610949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096d91906122b6565b6001600160a01b03841660009081526008602052604090205490915080821115610a0257600061099d828461229f565b90506109b36001600160a01b03861685836119f0565b836001600160a01b0316856001600160a01b03167f2ae72b44f59d038340fca5739135a1d51fc5ab720bb02d983e4c5ff4119ca7b8836040516109f891815260200190565b60405180910390a3505b50505050565b610a10611a58565b610a1a6000611ab2565b565b6000610545600383611acb565b60015433906001600160a01b03168114610a975760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016105d1565b6108f781611ab2565b610aa8611f0c565b60068281548110610abb57610abb6121ba565b60009182526020918290206040805160a081018252600590930290910180546001600160a01b0390811684526001820154948401949094526002810154918301919091526003810154606083015260040154909116608082015292915050565b610b23611a58565b8268056bc75e2d63100000811115610b4e576040516304044aa160e51b815260040160405180910390fd5b6000610b59866116d2565b6060810186905290508215610be5576001600160a01b03808516608083018190528251909116600090815260086020526040808220549051632f42225960e21b815263bd08896492610bb2929091829190600401612227565b600060405180830381600087803b158015610bcc57600080fd5b505af1158015610be0573d6000803e3d6000fd5b505050505b8060068781548110610bf957610bf96121ba565b600091825260209182902083516005929092020180546001600160a01b03199081166001600160a01b03938416178255928401516001820155604084015160028201556060840151600382015560809093015160049093018054909216921691909117905582610c6d578060800151610c6f565b835b6001600160a01b0316867fa54644aae5c48c5971516f334e4fe8ecbc7930e23f34877d4203c6551e67ffaa8786604051610cb59291909182521515602082015260400190565b60405180910390a3505050505050565b610ce960405180606001604052806000815260200160008152602001600081525090565b5060009182526007602090815260408084206001600160a01b03909316845291815291819020815160608101835281548152600182015493810193909352600201549082015290565b610d3a611a58565b8268056bc75e2d63100000811115610d65576040516304044aa160e51b815260040160405180910390fd5b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316836001600160a01b03161415610db857604051637ff7590b60e01b815260040160405180910390fd5b600654610dc760038583611ae0565b610def57604051631a491d0960e31b81526001600160a01b03851660048201526024016105d1565b6040805160a0810182526001600160a01b0386811680835260006020840181815242858701908152606086018c81528a861660808801908152600680546001810182559552965160059094027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f810180549588166001600160a01b031996871617905592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4084015590517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d41830155517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4282015593517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d43909401805494909316931692909217905590516370a0823160e01b81523060048201526370a0823190602401602060405180830381865afa158015610f4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7391906122b6565b506001600160a01b03831615610fe757604051632f42225960e21b81526001600160a01b0384169063bd08896490610fb49060009081908190600401612227565b600060405180830381600087803b158015610fce57600080fd5b505af1158015610fe2573d6000803e3d6000fd5b505050505b826001600160a01b0316846001600160a01b0316827f4b16bd2431ad24dc020ab0e1de7fcb6563dead6a24fb10089d6c23e97a70381f8860405161102d91815260200190565b60405180910390a45050505050565b61104461167a565b808061106357604051637510b3bf60e11b815260040160405180910390fd5b600061106e846116d2565b6000858152600760209081526040808320338452909152808220805460018201546002830154865194516370a0823160e01b815230600482015296975092959194909390916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156110e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110991906122b6565b8651909150611123906001600160a01b031633308b611afe565b85516040516370a0823160e01b815230600482015260009183916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561116f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119391906122b6565b61119d919061229f565b905060006111ab82876122cf565b88516001600160a01b0316600090815260086020908152604090912054908a0151919250906ec097ce7bc90715b34b9f1000000000906111eb90846121e6565b6111f59190612205565b600189015581885561120783826122cf565b89516001600160a01b03166000908152600860205260409020558615158061122f5750600085115b1561124b576112458787878f8d60200151611869565b60028901555b60808901516001600160a01b038116156112c257604051632f42225960e21b81526001600160a01b0382169063bd0889649061128f90339087908790600401612227565b600060405180830381600087803b1580156112a957600080fd5b505af11580156112bd573d6000803e3d6000fd5b505050505b6040518481528d9033907f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159060200160405180910390a350505050505050505050506105346001600255565b611316611a58565b600180546001600160a01b0383166001600160a01b031990911681179091556113476000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60008060606000806006878154811061139a5761139a6121ba565b600091825260208083206040805160a081018252600590940290910180546001600160a01b039081168552600182015485850152600282015485840190815260038301546060870152600490920154811660808601528c865260078452828620908c16865290925290922091519092504211156114375781516001600160a01b03166000908152600860205260409020546114358382611b36565b505b60028101546001820154602084015183546ec097ce7bc90715b34b9f100000000091611462916121e6565b61146c9190612205565b611476919061229f565b61148091906122cf565b60808301519096506001600160a01b0381161561161e57806001600160a01b031663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f991906122e7565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b179052905191975060009182916001600160a01b038a16916115409190612304565b600060405180830381855afa9150503d806000811461157b576040519150601f19603f3d011682016040523d82523d6000602084013e611580565b606091505b5091509150818015611593575060008151115b156115af57808060200190518101906115ac9190612336565b96505b60405163c031a66f60e01b81526001600160a01b038b8116600483015284169063c031a66f90602401602060405180830381865afa1580156115f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161991906122b6565b955050505b50505092959194509250565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6002805414156116cc5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105d1565b60028055565b6116da611f0c565b6000600683815481106116ef576116ef6121ba565b60009182526020918290206040805160a081018252600590930290910180546001600160a01b0390811684526001820154948401949094526002810154918301829052600381015460608401526004015490921660808201529150611767576040516342e6c96d60e01b815260040160405180910390fd5b80604001514211156105455780516001600160a01b03166000908152600860205260409020546117978282611b36565b81600685815481106117ab576117ab6121ba565b6000918252602091829020835160059092020180546001600160a01b039283166001600160a01b0319918216178255848401516001830155604080860151600284015560608601516003840155608090950151600490920180549290931691161790558382015190840151915186927fbcadd57793bf0e364c6e89020676e1e8dd5bf1e207decb5f2d1a1aa81ef1a6379261185a92909186919283526020830191909152604082015260600190565b60405180910390a25092915050565b60008084866ec097ce7bc90715b34b9f1000000000611888868b6121e6565b6118929190612205565b61189c919061229f565b6118a691906122cf565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa158015611910573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193491906122b6565b90508181101561195257611948818361229f565b9550809150611957565b600095505b61198b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001633846119f0565b6040805183815260208101889052869133917f4534f107610758c3931de9ad1e176476fcfb8c74adf920167e1d54ee84fcfe76910160405180910390a350939695505050505050565b60006119e9836001600160a01b038416611ba9565b9392505050565b6040516001600160a01b038316602482015260448101829052611a5390849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611c19565b505050565b6000546001600160a01b03163314610a1a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105d1565b600180546001600160a01b03191690556108f78161162a565b60006119e9836001600160a01b038416611ceb565b6000611af6846001600160a01b03851684611cf7565b949350505050565b6040516001600160a01b0380851660248301528316604482015260648101829052610a029085906323b872dd60e01b90608401611a1c565b8015611b9f576000826040015142611b4e919061229f565b90506000836060015182611b6291906121e6565b905082611b7e6ec097ce7bc90715b34b9f1000000000836121e6565b611b889190612205565b8460200151611b9791906122cf565b602085015250505b5042604090910152565b600081815260028301602052604081205480151580611bcd5750611bcd8484611ceb565b6119e95760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b6579000060448201526064016105d1565b6000611c6e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d149092919063ffffffff16565b805190915015611a535780806020019051810190611c8c91906123d8565b611a535760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105d1565b60006119e98383611d23565b60008281526002840160205260408120829055611af68484611d3b565b6060611af68484600085611d47565b600081815260018301602052604081205415156119e9565b60006119e98383611e22565b606082471015611da85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105d1565b600080866001600160a01b03168587604051611dc49190612304565b60006040518083038185875af1925050503d8060008114611e01576040519150601f19603f3d011682016040523d82523d6000602084013e611e06565b606091505b5091509150611e1787838387611e71565b979650505050505050565b6000818152600183016020526040812054611e6957508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610545565b506000610545565b60608315611edd578251611ed6576001600160a01b0385163b611ed65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105d1565b5081611af6565b611af68383815115611ef25781518083602001fd5b8060405162461bcd60e51b81526004016105d191906123f5565b6040518060a0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160006001600160a01b031681525090565b60008060208385031215611f6057600080fd5b823567ffffffffffffffff80821115611f7857600080fd5b818501915085601f830112611f8c57600080fd5b813581811115611f9b57600080fd5b8660208260051b8501011115611fb057600080fd5b60209290920196919550909350505050565b6001600160a01b03811681146108f757600080fd5b600060208284031215611fe957600080fd5b81356119e981611fc2565b6000806040838503121561200757600080fd5b50508035926020909101359150565b60006020828403121561202857600080fd5b5035919050565b6000806040838503121561204257600080fd5b823561204d81611fc2565b9150602083013561205d81611fc2565b809150509250929050565b80151581146108f757600080fd5b6000806000806080858703121561208c57600080fd5b843593506020850135925060408501356120a581611fc2565b915060608501356120b581612068565b939692955090935050565b600080604083850312156120d357600080fd5b82359150602083013561205d81611fc2565b6000806000606084860312156120fa57600080fd5b83359250602084013561210c81611fc2565b9150604084013561211c81611fc2565b809150509250925092565b60005b8381101561214257818101518382015260200161212a565b83811115610a025750506000910152565b6000815180845261216b816020860160208601612127565b601f01601f19169290920160200192915050565b8481526001600160a01b03841660208201526080604082018190526000906121a990830185612153565b905082606083015295945050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615612200576122006121d0565b500290565b60008261222257634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b039390931683526020830191909152604082015260600190565b600060001982141561225c5761225c6121d0565b5060010190565b6020808252810182905260006001600160fb1b0383111561228357600080fd5b8260051b80856040850137600092016040019182525092915050565b6000828210156122b1576122b16121d0565b500390565b6000602082840312156122c857600080fd5b5051919050565b600082198211156122e2576122e26121d0565b500190565b6000602082840312156122f957600080fd5b81516119e981611fc2565b60008251612316818460208701612127565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561234857600080fd5b815167ffffffffffffffff8082111561236057600080fd5b818401915084601f83011261237457600080fd5b81518181111561238657612386612320565b604051601f8201601f19908116603f011681019083821181831017156123ae576123ae612320565b816040528281528760208487010111156123c757600080fd5b611e17836020830160208801612127565b6000602082840312156123ea57600080fd5b81516119e981612068565b6020815260006119e9602083018461215356fea264697066735822122080eb8e1041477d2db30ca533d60dad7ac2d4e91a99ba23f4625ef3ae7129960f64736f6c634300080a0033000000000000000000000000371c7ec6d8039ff7933a2aa28eb827ffe1f52f07
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061012c5760003560e01c80638a48a515116100ad578063b985a3a011610071578063b985a3a0146102dc578063e2bbb15814610303578063e30c397814610316578063f2fde38b14610327578063ffcd42631461033a57600080fd5b80638a48a515146102475780638da5cb5b1461024f5780639032a7441461027457806393f1a40b14610294578063ab7de098146102c957600080fd5b8063715018a6116100f4578063715018a6146101a557806371e10b4f146101ad57806379ba5097146101d05780637d21c967146101d857806388bba42f1461023457600080fd5b80632a4561151461013157806333eec66c14610146578063441a3e701461016c5780635312ea8e1461017f578063712b772f14610192575b600080fd5b61014461013f366004611f4d565b61035d565b005b610159610154366004611fd7565b610538565b6040519081526020015b60405180910390f35b61014461017a366004611ff4565b61054b565b61014461018d366004612016565b61075d565b6101446101a036600461202f565b6108fa565b610144610a08565b6101c06101bb366004611fd7565b610a1c565b6040519015158152602001610163565b610144610a29565b6101eb6101e6366004612016565b610aa0565b604051610163919081516001600160a01b039081168252602080840151908301526040808401519083015260608084015190830152608092830151169181019190915260a00190565b610144610242366004612076565b610b1b565b600654610159565b6000546001600160a01b03165b6040516001600160a01b039091168152602001610163565b610159610282366004611fd7565b60086020526000908152604090205481565b6102a76102a23660046120c0565b610cc5565b6040805182518152602080840151908201529181015190820152606001610163565b6101446102d73660046120e5565b610d32565b61025c7f000000000000000000000000371c7ec6d8039ff7933a2aa28eb827ffe1f52f0781565b610144610311366004611ff4565b61103c565b6001546001600160a01b031661025c565b610144610335366004611fd7565b61130e565b61034d6103483660046120c0565b61137f565b604051610163949392919061217f565b61036561167a565b81818061038557604051630751bbfd60e41b815260040160405180910390fd5b8260005b818110156104e35760008686838181106103a5576103a56121ba565b90506020020135905060006103b9826116d2565b600083815260076020908152604080832033845282529091208054600182015460028301549385015194955091939092906ec097ce7bc90715b34b9f10000000009061040590856121e6565b61040f9190612205565b6001850155821515806104225750600081115b1561043e57610438838383898960200151611869565b60028501555b60808501516001600160a01b038116156104c95785516001600160a01b0390811660009081526008602052604090819020549051632f42225960e21b81529183169163bd088964916104969133918991600401612227565b600060405180830381600087803b1580156104b057600080fd5b505af11580156104c4573d6000803e3d6000fd5b505050505b5050505050505080806104db90612248565b915050610389565b50336001600160a01b03167f672035d5c6b584aaca0cbb0a127e92656163e2dd362713b114fd41350220e368868660405161051f929190612263565b60405180910390a25050506105346001600255565b5050565b60006105456003836119d4565b92915050565b61055361167a565b808061057257604051637510b3bf60e11b815260040160405180910390fd5b600061057d846116d2565b600085815260076020908152604080832033845290915290208054600182015460028301549394509192909190868310156105da57604051631f2d6a6160e31b815260048101849052602481018890526044015b60405180910390fd5b60006105e6888561229f565b86516001600160a01b031660009081526008602090815260409091205490880151919250906ec097ce7bc90715b34b9f10000000009061062690846121e6565b6106309190612205565b6001870155818655610642898261229f565b87516001600160a01b03166000908152600860205260409020558415158061066a5750600083115b15610686576106808585858d8b60200151611869565b60028701555b60808701516001600160a01b038116156106fd57604051632f42225960e21b81526001600160a01b0382169063bd088964906106ca90339087908790600401612227565b600060405180830381600087803b1580156106e457600080fd5b505af11580156106f8573d6000803e3d6000fd5b505050505b8751610713906001600160a01b0316338c6119f0565b6040518a81528b9033907ff279e6a1f5e320cca91135676d9cb6e44ca8a08c0b88342bcdb1144f6511b5689060200160405180910390a35050505050505050506105346001600255565b61076561167a565b60006006828154811061077a5761077a6121ba565b600091825260208083206040805160a081018252600590940290910180546001600160a01b039081168552600180830154868601526002830154868501526003830154606087015260049092015481166080860152878652600784528286203387528452828620805486519092168752600890945291852054858455908301949094559193509161080b828261229f565b84516001600160a01b0390811660009081526008602052604090209190915560808501519081161561089b57604051632f42225960e21b81526001600160a01b0382169063bd088964906108689033906000908790600401612227565b600060405180830381600087803b15801561088257600080fd5b505af1158015610896573d6000803e3d6000fd5b505050505b84516108b1906001600160a01b031633856119f0565b604051838152869033907fbb757047c2b5f3974fe26b7c10f732e7bce710b0952a71082702781e62ae05959060200160405180910390a350505050506108f76001600255565b50565b610902611a58565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015610949573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061096d91906122b6565b6001600160a01b03841660009081526008602052604090205490915080821115610a0257600061099d828461229f565b90506109b36001600160a01b03861685836119f0565b836001600160a01b0316856001600160a01b03167f2ae72b44f59d038340fca5739135a1d51fc5ab720bb02d983e4c5ff4119ca7b8836040516109f891815260200190565b60405180910390a3505b50505050565b610a10611a58565b610a1a6000611ab2565b565b6000610545600383611acb565b60015433906001600160a01b03168114610a975760405162461bcd60e51b815260206004820152602960248201527f4f776e61626c6532537465703a2063616c6c6572206973206e6f7420746865206044820152683732bb9037bbb732b960b91b60648201526084016105d1565b6108f781611ab2565b610aa8611f0c565b60068281548110610abb57610abb6121ba565b60009182526020918290206040805160a081018252600590930290910180546001600160a01b0390811684526001820154948401949094526002810154918301919091526003810154606083015260040154909116608082015292915050565b610b23611a58565b8268056bc75e2d63100000811115610b4e576040516304044aa160e51b815260040160405180910390fd5b6000610b59866116d2565b6060810186905290508215610be5576001600160a01b03808516608083018190528251909116600090815260086020526040808220549051632f42225960e21b815263bd08896492610bb2929091829190600401612227565b600060405180830381600087803b158015610bcc57600080fd5b505af1158015610be0573d6000803e3d6000fd5b505050505b8060068781548110610bf957610bf96121ba565b600091825260209182902083516005929092020180546001600160a01b03199081166001600160a01b03938416178255928401516001820155604084015160028201556060840151600382015560809093015160049093018054909216921691909117905582610c6d578060800151610c6f565b835b6001600160a01b0316867fa54644aae5c48c5971516f334e4fe8ecbc7930e23f34877d4203c6551e67ffaa8786604051610cb59291909182521515602082015260400190565b60405180910390a3505050505050565b610ce960405180606001604052806000815260200160008152602001600081525090565b5060009182526007602090815260408084206001600160a01b03909316845291815291819020815160608101835281548152600182015493810193909352600201549082015290565b610d3a611a58565b8268056bc75e2d63100000811115610d65576040516304044aa160e51b815260040160405180910390fd5b7f000000000000000000000000371c7ec6d8039ff7933a2aa28eb827ffe1f52f076001600160a01b0316836001600160a01b03161415610db857604051637ff7590b60e01b815260040160405180910390fd5b600654610dc760038583611ae0565b610def57604051631a491d0960e31b81526001600160a01b03851660048201526024016105d1565b6040805160a0810182526001600160a01b0386811680835260006020840181815242858701908152606086018c81528a861660808801908152600680546001810182559552965160059094027ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f810180549588166001600160a01b031996871617905592517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4084015590517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d41830155517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d4282015593517ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d43909401805494909316931692909217905590516370a0823160e01b81523060048201526370a0823190602401602060405180830381865afa158015610f4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7391906122b6565b506001600160a01b03831615610fe757604051632f42225960e21b81526001600160a01b0384169063bd08896490610fb49060009081908190600401612227565b600060405180830381600087803b158015610fce57600080fd5b505af1158015610fe2573d6000803e3d6000fd5b505050505b826001600160a01b0316846001600160a01b0316827f4b16bd2431ad24dc020ab0e1de7fcb6563dead6a24fb10089d6c23e97a70381f8860405161102d91815260200190565b60405180910390a45050505050565b61104461167a565b808061106357604051637510b3bf60e11b815260040160405180910390fd5b600061106e846116d2565b6000858152600760209081526040808320338452909152808220805460018201546002830154865194516370a0823160e01b815230600482015296975092959194909390916001600160a01b03909116906370a0823190602401602060405180830381865afa1580156110e5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061110991906122b6565b8651909150611123906001600160a01b031633308b611afe565b85516040516370a0823160e01b815230600482015260009183916001600160a01b03909116906370a0823190602401602060405180830381865afa15801561116f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061119391906122b6565b61119d919061229f565b905060006111ab82876122cf565b88516001600160a01b0316600090815260086020908152604090912054908a0151919250906ec097ce7bc90715b34b9f1000000000906111eb90846121e6565b6111f59190612205565b600189015581885561120783826122cf565b89516001600160a01b03166000908152600860205260409020558615158061122f5750600085115b1561124b576112458787878f8d60200151611869565b60028901555b60808901516001600160a01b038116156112c257604051632f42225960e21b81526001600160a01b0382169063bd0889649061128f90339087908790600401612227565b600060405180830381600087803b1580156112a957600080fd5b505af11580156112bd573d6000803e3d6000fd5b505050505b6040518481528d9033907f90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a159060200160405180910390a350505050505050505050506105346001600255565b611316611a58565b600180546001600160a01b0383166001600160a01b031990911681179091556113476000546001600160a01b031690565b6001600160a01b03167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e2270060405160405180910390a350565b60008060606000806006878154811061139a5761139a6121ba565b600091825260208083206040805160a081018252600590940290910180546001600160a01b039081168552600182015485850152600282015485840190815260038301546060870152600490920154811660808601528c865260078452828620908c16865290925290922091519092504211156114375781516001600160a01b03166000908152600860205260409020546114358382611b36565b505b60028101546001820154602084015183546ec097ce7bc90715b34b9f100000000091611462916121e6565b61146c9190612205565b611476919061229f565b61148091906122cf565b60808301519096506001600160a01b0381161561161e57806001600160a01b031663f7c618c16040518163ffffffff1660e01b8152600401602060405180830381865afa1580156114d5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114f991906122e7565b60408051600481526024810182526020810180516001600160e01b03166395d89b4160e01b179052905191975060009182916001600160a01b038a16916115409190612304565b600060405180830381855afa9150503d806000811461157b576040519150601f19603f3d011682016040523d82523d6000602084013e611580565b606091505b5091509150818015611593575060008151115b156115af57808060200190518101906115ac9190612336565b96505b60405163c031a66f60e01b81526001600160a01b038b8116600483015284169063c031a66f90602401602060405180830381865afa1580156115f5573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061161991906122b6565b955050505b50505092959194509250565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6002805414156116cc5760405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064016105d1565b60028055565b6116da611f0c565b6000600683815481106116ef576116ef6121ba565b60009182526020918290206040805160a081018252600590930290910180546001600160a01b0390811684526001820154948401949094526002810154918301829052600381015460608401526004015490921660808201529150611767576040516342e6c96d60e01b815260040160405180910390fd5b80604001514211156105455780516001600160a01b03166000908152600860205260409020546117978282611b36565b81600685815481106117ab576117ab6121ba565b6000918252602091829020835160059092020180546001600160a01b039283166001600160a01b0319918216178255848401516001830155604080860151600284015560608601516003840155608090950151600490920180549290931691161790558382015190840151915186927fbcadd57793bf0e364c6e89020676e1e8dd5bf1e207decb5f2d1a1aa81ef1a6379261185a92909186919283526020830191909152604082015260600190565b60405180910390a25092915050565b60008084866ec097ce7bc90715b34b9f1000000000611888868b6121e6565b6118929190612205565b61189c919061229f565b6118a691906122cf565b6040516370a0823160e01b81523060048201529091506000906001600160a01b037f000000000000000000000000371c7ec6d8039ff7933a2aa28eb827ffe1f52f0716906370a0823190602401602060405180830381865afa158015611910573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061193491906122b6565b90508181101561195257611948818361229f565b9550809150611957565b600095505b61198b6001600160a01b037f000000000000000000000000371c7ec6d8039ff7933a2aa28eb827ffe1f52f071633846119f0565b6040805183815260208101889052869133917f4534f107610758c3931de9ad1e176476fcfb8c74adf920167e1d54ee84fcfe76910160405180910390a350939695505050505050565b60006119e9836001600160a01b038416611ba9565b9392505050565b6040516001600160a01b038316602482015260448101829052611a5390849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b031990931692909217909152611c19565b505050565b6000546001600160a01b03163314610a1a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016105d1565b600180546001600160a01b03191690556108f78161162a565b60006119e9836001600160a01b038416611ceb565b6000611af6846001600160a01b03851684611cf7565b949350505050565b6040516001600160a01b0380851660248301528316604482015260648101829052610a029085906323b872dd60e01b90608401611a1c565b8015611b9f576000826040015142611b4e919061229f565b90506000836060015182611b6291906121e6565b905082611b7e6ec097ce7bc90715b34b9f1000000000836121e6565b611b889190612205565b8460200151611b9791906122cf565b602085015250505b5042604090910152565b600081815260028301602052604081205480151580611bcd5750611bcd8484611ceb565b6119e95760405162461bcd60e51b815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b6579000060448201526064016105d1565b6000611c6e826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316611d149092919063ffffffff16565b805190915015611a535780806020019051810190611c8c91906123d8565b611a535760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016105d1565b60006119e98383611d23565b60008281526002840160205260408120829055611af68484611d3b565b6060611af68484600085611d47565b600081815260018301602052604081205415156119e9565b60006119e98383611e22565b606082471015611da85760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b60648201526084016105d1565b600080866001600160a01b03168587604051611dc49190612304565b60006040518083038185875af1925050503d8060008114611e01576040519150601f19603f3d011682016040523d82523d6000602084013e611e06565b606091505b5091509150611e1787838387611e71565b979650505050505050565b6000818152600183016020526040812054611e6957508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155610545565b506000610545565b60608315611edd578251611ed6576001600160a01b0385163b611ed65760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016105d1565b5081611af6565b611af68383815115611ef25781518083602001fd5b8060405162461bcd60e51b81526004016105d191906123f5565b6040518060a0016040528060006001600160a01b0316815260200160008152602001600081526020016000815260200160006001600160a01b031681525090565b60008060208385031215611f6057600080fd5b823567ffffffffffffffff80821115611f7857600080fd5b818501915085601f830112611f8c57600080fd5b813581811115611f9b57600080fd5b8660208260051b8501011115611fb057600080fd5b60209290920196919550909350505050565b6001600160a01b03811681146108f757600080fd5b600060208284031215611fe957600080fd5b81356119e981611fc2565b6000806040838503121561200757600080fd5b50508035926020909101359150565b60006020828403121561202857600080fd5b5035919050565b6000806040838503121561204257600080fd5b823561204d81611fc2565b9150602083013561205d81611fc2565b809150509250929050565b80151581146108f757600080fd5b6000806000806080858703121561208c57600080fd5b843593506020850135925060408501356120a581611fc2565b915060608501356120b581612068565b939692955090935050565b600080604083850312156120d357600080fd5b82359150602083013561205d81611fc2565b6000806000606084860312156120fa57600080fd5b83359250602084013561210c81611fc2565b9150604084013561211c81611fc2565b809150509250925092565b60005b8381101561214257818101518382015260200161212a565b83811115610a025750506000910152565b6000815180845261216b816020860160208601612127565b601f01601f19169290920160200192915050565b8481526001600160a01b03841660208201526080604082018190526000906121a990830185612153565b905082606083015295945050505050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b6000816000190483118215151615612200576122006121d0565b500290565b60008261222257634e487b7160e01b600052601260045260246000fd5b500490565b6001600160a01b039390931683526020830191909152604082015260600190565b600060001982141561225c5761225c6121d0565b5060010190565b6020808252810182905260006001600160fb1b0383111561228357600080fd5b8260051b80856040850137600092016040019182525092915050565b6000828210156122b1576122b16121d0565b500390565b6000602082840312156122c857600080fd5b5051919050565b600082198211156122e2576122e26121d0565b500190565b6000602082840312156122f957600080fd5b81516119e981611fc2565b60008251612316818460208701612127565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561234857600080fd5b815167ffffffffffffffff8082111561236057600080fd5b818401915084601f83011261237457600080fd5b81518181111561238657612386612320565b604051601f8201601f19908116603f011681019083821181831017156123ae576123ae612320565b816040528281528760208487010111156123c757600080fd5b611e17836020830160208801612127565b6000602082840312156123ea57600080fd5b81516119e981612068565b6020815260006119e9602083018461215356fea264697066735822122080eb8e1041477d2db30ca533d60dad7ac2d4e91a99ba23f4625ef3ae7129960f64736f6c634300080a0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000371c7ec6d8039ff7933a2aa28eb827ffe1f52f07
-----Decoded View---------------
Arg [0] : _joe (address): 0x371c7ec6D8039ff7933a2AA28EB827Ffe1F52f07
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000371c7ec6d8039ff7933a2aa28eb827ffe1f52f07
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.