Source Code
Latest 25 from a total of 16,194 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw And Har... | 2012470 | 1327 days ago | IN | 0 MOVR | 0.00018229 | ||||
| Withdraw And Har... | 1984788 | 1332 days ago | IN | 0 MOVR | 0.00022041 | ||||
| Withdraw And Har... | 1676205 | 1396 days ago | IN | 0 MOVR | 0.00018229 | ||||
| Harvest | 1676199 | 1396 days ago | IN | 0 MOVR | 0.0002448 | ||||
| Withdraw And Har... | 1672529 | 1397 days ago | IN | 0 MOVR | 0.00014239 | ||||
| Deposit | 1672398 | 1397 days ago | IN | 0 MOVR | 0.00027798 | ||||
| Withdraw | 1670742 | 1397 days ago | IN | 0 MOVR | 0.00011151 | ||||
| Withdraw And Har... | 1670742 | 1397 days ago | IN | 0 MOVR | 0.00017632 | ||||
| Withdraw | 1669793 | 1398 days ago | IN | 0 MOVR | 0.00022211 | ||||
| Withdraw And Har... | 1669790 | 1398 days ago | IN | 0 MOVR | 0.00021427 | ||||
| Harvest All Rewa... | 1669788 | 1398 days ago | IN | 0 MOVR | 0.00024929 | ||||
| Withdraw And Har... | 1667686 | 1398 days ago | IN | 0 MOVR | 0.00026021 | ||||
| Withdraw | 1667292 | 1398 days ago | IN | 0 MOVR | 0.00014217 | ||||
| Withdraw And Har... | 1667290 | 1398 days ago | IN | 0 MOVR | 0.00017142 | ||||
| Harvest | 1667288 | 1398 days ago | IN | 0 MOVR | 0.00019584 | ||||
| Withdraw And Har... | 1666123 | 1399 days ago | IN | 0 MOVR | 0.00018229 | ||||
| Harvest | 1666118 | 1399 days ago | IN | 0 MOVR | 0.0002448 | ||||
| Harvest All Rewa... | 1649954 | 1404 days ago | IN | 0 MOVR | 0.00011922 | ||||
| Withdraw And Har... | 1639375 | 1407 days ago | IN | 0 MOVR | 0.00025633 | ||||
| Withdraw And Har... | 1638511 | 1407 days ago | IN | 0 MOVR | 0.00014583 | ||||
| Withdraw And Har... | 1638506 | 1407 days ago | IN | 0 MOVR | 0.00017141 | ||||
| Harvest | 1638504 | 1407 days ago | IN | 0 MOVR | 0.00015604 | ||||
| Harvest | 1630406 | 1409 days ago | IN | 0 MOVR | 0.00010439 | ||||
| Withdraw And Har... | 1630406 | 1409 days ago | IN | 0 MOVR | 0.00026021 | ||||
| Harvest All Rewa... | 1627030 | 1410 days ago | IN | 0 MOVR | 0.00009537 |
View more zero value Internal Transactions in Advanced View mode
Cross-Chain Transactions
Loading...
Loading
Contract Name:
OneSwapChef
Compiler Version
v0.8.4+commit.c7e474f2
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "../interfaces/IRewarder.sol";
/* OneSwapChef is a fork from Sushi's MiniChef v2
*/
contract OneSwapChef is Ownable {
using SafeERC20 for IERC20;
struct UserInfo {
uint256 amount;
int256 rewardDebt;
}
struct PoolInfo {
uint256 accRewardPerShare;
uint256 lastRewardTime;
uint256 allocPoint;
}
IERC20 public reward;
/// @notice Info of each MCV2 pool.
PoolInfo[] public poolInfo;
/// @notice Address of the LP token for each MCV2 pool.
IERC20[] public lpToken;
/// @notice Address of each `IRewarder` contract in MCV2.
IRewarder[] public rewarder;
/// @notice Info of each user that stakes LP tokens.
mapping(uint256 => mapping(address => UserInfo)) public userInfo;
/// @dev Total allocation points. Must be the sum of all allocation points in all pools.
uint256 public totalAllocPoint = 0;
uint256 public rewardPerSecond;
uint256 private constant ACC_REWARD_PRECISION = 1e12;
constructor(IERC20 _reward) {
reward = _reward;
}
/* ========== PUBLIC FUNCTIONS ========== */
/// @notice Returns the number of MCV2 pools.
function poolLength() public view returns (uint256 pools) {
pools = poolInfo.length;
}
/// @notice View function to see pending reward on frontend.
/// @param _pid The index of the pool. See `poolInfo`.
/// @param _user Address of user.
/// @return pending reward for a given user.
function pendingReward(uint256 _pid, address _user) external view returns (uint256 pending) {
PoolInfo memory pool = poolInfo[_pid];
UserInfo storage user = userInfo[_pid][_user];
uint256 accRewardPerShare = pool.accRewardPerShare;
uint256 lpSupply = lpToken[_pid].balanceOf(address(this));
if (block.timestamp > pool.lastRewardTime && lpSupply != 0) {
uint256 time = block.timestamp - pool.lastRewardTime;
uint256 rewardAmount = (time * rewardPerSecond * pool.allocPoint) / totalAllocPoint;
accRewardPerShare += (rewardAmount * ACC_REWARD_PRECISION) / lpSupply;
}
pending = uint256(int256((user.amount * accRewardPerShare) / ACC_REWARD_PRECISION) - user.rewardDebt);
}
/// @notice Update reward variables of the given pool.
/// @param pid The index of the pool. See `poolInfo`.
/// @return pool Returns the pool that was updated.
function updatePool(uint256 pid) public returns (PoolInfo memory pool) {
pool = poolInfo[pid];
if (block.timestamp > pool.lastRewardTime) {
uint256 lpSupply = lpToken[pid].balanceOf(address(this));
if (lpSupply > 0) {
uint256 time = block.timestamp - pool.lastRewardTime;
uint256 rewardAmount = (time * rewardPerSecond * pool.allocPoint) / totalAllocPoint;
pool.accRewardPerShare += (rewardAmount * ACC_REWARD_PRECISION) / lpSupply;
}
pool.lastRewardTime = block.timestamp;
poolInfo[pid] = pool;
emit LogUpdatePool(pid, pool.lastRewardTime, lpSupply, pool.accRewardPerShare);
}
}
/// @notice Update reward variables for all pools. Be careful of gas spending!
/// @param pids Pool IDs of all to be updated. Make sure to update all active pools.
function massUpdatePools(uint256[] calldata pids) external {
uint256 len = pids.length;
for (uint256 i = 0; i < len; ++i) {
updatePool(pids[i]);
}
}
/// @notice Deposit LP tokens to MCV2 for reward allocation.
/// @param pid The index of the pool. See `poolInfo`.
/// @param amount LP token amount to deposit.
/// @param to The receiver of `amount` deposit benefit.
function deposit(
uint256 pid,
uint256 amount,
address to
) public {
PoolInfo memory pool = updatePool(pid);
UserInfo storage user = userInfo[pid][to];
// Effects
user.amount += amount;
user.rewardDebt += int256((amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION);
// Interactions
IRewarder _rewarder = rewarder[pid];
if (address(_rewarder) != address(0)) {
_rewarder.onReward(pid, to, to, 0, user.amount);
}
lpToken[pid].safeTransferFrom(msg.sender, address(this), amount);
emit Deposit(msg.sender, pid, amount, to);
}
/// @notice Withdraw LP tokens from MCV2.
/// @param pid The index of the pool. See `poolInfo`.
/// @param amount LP token amount to withdraw.
/// @param to Receiver of the LP tokens.
function withdraw(
uint256 pid,
uint256 amount,
address to
) public {
PoolInfo memory pool = updatePool(pid);
UserInfo storage user = userInfo[pid][msg.sender];
// Effects
user.rewardDebt -= int256((amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION);
user.amount -= amount;
// Interactions
IRewarder _rewarder = rewarder[pid];
if (address(_rewarder) != address(0)) {
_rewarder.onReward(pid, msg.sender, to, 0, user.amount);
}
lpToken[pid].safeTransfer(to, amount);
emit Withdraw(msg.sender, pid, amount, to);
}
/// @notice Harvest proceeds for transaction sender to `to`.
/// @param pid The index of the pool. See `poolInfo`.
/// @param to Receiver of rewards.
function harvest(uint256 pid, address to) public {
PoolInfo memory pool = updatePool(pid);
UserInfo storage user = userInfo[pid][msg.sender];
int256 accumulatedReward = int256((user.amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION);
uint256 _pendingReward = uint256(accumulatedReward - user.rewardDebt);
// Effects
user.rewardDebt = accumulatedReward;
// Interactions
if (_pendingReward != 0) {
reward.safeTransfer(to, _pendingReward);
}
IRewarder _rewarder = rewarder[pid];
if (address(_rewarder) != address(0)) {
_rewarder.onReward(pid, msg.sender, to, _pendingReward, user.amount);
}
emit Harvest(msg.sender, pid, _pendingReward);
}
/// @notice Withdraw LP tokens from MCV2 and harvest proceeds for transaction sender to `to`.
/// @param pid The index of the pool. See `poolInfo`.
/// @param amount LP token amount to withdraw.
/// @param to Receiver of the LP tokens and rewards.
function withdrawAndHarvest(
uint256 pid,
uint256 amount,
address to
) public {
PoolInfo memory pool = updatePool(pid);
UserInfo storage user = userInfo[pid][msg.sender];
int256 accumulatedReward = int256((user.amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION);
uint256 _pendingReward = uint256(accumulatedReward - user.rewardDebt);
// Effects
user.rewardDebt = accumulatedReward - int256((amount * pool.accRewardPerShare) / ACC_REWARD_PRECISION);
user.amount -= amount;
// Interactions
if (_pendingReward != 0) {
reward.safeTransfer(to, _pendingReward);
}
IRewarder _rewarder = rewarder[pid];
if (address(_rewarder) != address(0)) {
_rewarder.onReward(pid, msg.sender, to, _pendingReward, user.amount);
}
lpToken[pid].safeTransfer(to, amount);
emit Withdraw(msg.sender, pid, amount, to);
emit Harvest(msg.sender, pid, _pendingReward);
}
/// @notice Withdraw without caring about rewards. EMERGENCY ONLY.
/// @param pid The index of the pool. See `poolInfo`.
/// @param to Receiver of the LP tokens.
function emergencyWithdraw(uint256 pid, address to) public {
UserInfo storage user = userInfo[pid][msg.sender];
uint256 amount = user.amount;
user.amount = 0;
user.rewardDebt = 0;
IRewarder _rewarder = rewarder[pid];
if (address(_rewarder) != address(0)) {
_rewarder.onReward(pid, msg.sender, to, 0, 0);
}
// Note: transfer can fail or succeed if `amount` is zero.
lpToken[pid].safeTransfer(to, amount);
emit EmergencyWithdraw(msg.sender, pid, amount, to);
}
function harvestAllRewards(address to) external {
uint256 length = poolInfo.length;
for (uint256 pid = 0; pid < length; ++pid) {
if (userInfo[pid][msg.sender].amount > 0) {
harvest(pid, to);
}
}
}
/* ========== INTERNAL FUNCTIONS ========== */
function checkPoolDuplicate(IERC20 _lpToken) internal view {
uint256 length = poolInfo.length;
for (uint256 pid = 0; pid < length; ++pid) {
require(lpToken[pid] != _lpToken, "add: existing pool?");
}
}
/* ========== RESTRICTED FUNCTIONS ========== */
/// @notice Add a new LP to the pool. Can only be called by the owner.
/// DO NOT add the same LP token more than once. Rewards will be messed up if you do.
/// @param allocPoint AP of the new pool.
/// @param _lpToken Address of the LP ERC-20 token.
/// @param _rewarder Address of the rewarder delegate.
function add(
uint256 allocPoint,
IERC20 _lpToken,
IRewarder _rewarder
) public onlyOwner {
checkPoolDuplicate(_lpToken);
totalAllocPoint += allocPoint;
lpToken.push(_lpToken);
rewarder.push(_rewarder);
poolInfo.push(PoolInfo({allocPoint: allocPoint, lastRewardTime: block.timestamp, accRewardPerShare: 0}));
emit LogPoolAddition(lpToken.length - 1, allocPoint, _lpToken, _rewarder);
}
/// @notice Update the given pool's reward allocation point and `IRewarder` contract. Can only be called by the owner.
/// @param _pid The index of the pool. See `poolInfo`.
/// @param _allocPoint New AP of the pool.
/// @param _rewarder Address of the rewarder delegate.
/// @param overwrite True if _rewarder should be `set`. Otherwise `_rewarder` is ignored.
function set(
uint256 _pid,
uint256 _allocPoint,
IRewarder _rewarder,
bool overwrite
) public onlyOwner {
totalAllocPoint = totalAllocPoint - poolInfo[_pid].allocPoint + _allocPoint;
poolInfo[_pid].allocPoint = _allocPoint;
if (overwrite) {
rewarder[_pid] = _rewarder;
}
emit LogSetPool(_pid, _allocPoint, overwrite ? _rewarder : rewarder[_pid], overwrite);
}
/// @notice Sets the reward per second to be distributed. Can only be called by the owner.
/// @param _rewardPerSecond The amount of reward to be distributed per second.
function setRewardPerSecond(uint256 _rewardPerSecond) public onlyOwner {
rewardPerSecond = _rewardPerSecond;
emit LogRewardPerSecond(_rewardPerSecond);
}
/* =============== EVENTS ==================== */
event Deposit(address indexed user, uint256 indexed pid, uint256 amount, address indexed to);
event Withdraw(address indexed user, uint256 indexed pid, uint256 amount, address indexed to);
event EmergencyWithdraw(address indexed user, uint256 indexed pid, uint256 amount, address indexed to);
event Harvest(address indexed user, uint256 indexed pid, uint256 amount);
event LogPoolAddition(uint256 indexed pid, uint256 allocPoint, IERC20 indexed lpToken, IRewarder indexed rewarder);
event LogSetPool(uint256 indexed pid, uint256 allocPoint, IRewarder indexed rewarder, bool overwrite);
event LogUpdatePool(uint256 indexed pid, uint256 lastRewardTime, uint256 lpSupply, uint256 accRewardPerShare);
event LogRewardPerSecond(uint256 rewardPerSecond);
}// SPDX-License-Identifier: MIT
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() {
_setOwner(_msgSender());
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
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 {
_setOwner(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");
_setOwner(newOwner);
}
function _setOwner(address newOwner) private {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `recipient`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address recipient, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `sender` to `recipient` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) external returns (bool);
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../IERC20.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));
}
}
/**
* @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.4;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IRewarder {
function onReward(
uint256 pid,
address user,
address recipient,
uint256 rewardAmount,
uint256 newLpAmount
) external;
function pendingTokens(
uint256 pid,
address user,
uint256 rewardAmount
) external view returns (IERC20[] memory, uint256[] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize, which returns 0 for contracts in
// construction, since the code is only stored at the end of the
// constructor execution.
uint256 size;
assembly {
size := extcodesize(account)
}
return size > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCall(target, data, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
require(isContract(target), "Address: call to non-contract");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
require(isContract(target), "Address: static call to non-contract");
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
require(isContract(target), "Address: delegate call to non-contract");
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResult(success, returndata, errorMessage);
}
/**
* @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason 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 {
// 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
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract StakingRewardFund is Ownable {
using SafeERC20 for IERC20;
IERC20 public ONESWAP = IERC20(0x3516a7588C2E6FFA66C9507eF51853eb85d76e5B);
mapping(address => bool) public vaults;
modifier onlyVaults() {
require(vaults[_msgSender()], "Only requesters can call this function");
_;
}
function transfer(address _to, uint256 _amount) external onlyVaults {
require(_to != address(0), "invalid address");
require(_amount > 0, "invalid amount");
require(_amount <= ONESWAP.balanceOf(address(this)), "> balance");
ONESWAP.safeTransfer(_to, _amount);
}
// Restrictive functions
function addVault(address _newVault) external onlyOwner {
require(_newVault != address(0), "Invalid address");
require(!vaults[_newVault], "Vault existed");
vaults[_newVault] = true;
emit VaultAdded(_newVault);
}
function removeVault(address _vault) external onlyOwner {
require(vaults[_vault], "Vault not existed");
delete vaults[_vault];
emit VaultRemoved(_vault);
}
function rescueFund(uint256 _amount) external onlyOwner {
require(_amount > 0, "Invalid amount");
ONESWAP.safeTransfer(_msgSender(), _amount);
}
// Events
event VaultAdded(address indexed vault);
event VaultRemoved(address indexed vault);
}// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
import "../interfaces/IStakingRewardFund.sol";
contract OneSwapStaking is Ownable, Initializable {
using SafeMath for uint256;
using SafeERC20 for IERC20;
struct UserInfo {
uint256 amount;
}
IERC20 public oneSwap;
IStakingRewardFund public rewardFund;
uint256 public rewardPerSecond;
uint256 public maxCap;
uint256 public totalStaked;
uint256 public startLockTime;
uint256 public endLockTime;
bool public forceUnlocked;
mapping(address => UserInfo) public userInfo;
/* ========== Modifiers =============== */
function initialize(
IERC20 _oneSwap,
uint256 _maxCap,
uint256 _startLockTime,
uint256 _endLockTime
) external initializer {
require(_startLockTime < _endLockTime, "Start lock time must be less than end lock time");
oneSwap = _oneSwap;
maxCap = _maxCap;
startLockTime = _startLockTime;
endLockTime = _endLockTime;
}
/* ========== PUBLIC FUNCTIONS ========== */
function getTotalReward() public view returns (uint256) {
uint256 _rewardPerSecond = rewardPerSecond;
if (block.timestamp <= startLockTime) return 0;
return endLockTime.sub(startLockTime).mul(_rewardPerSecond);
}
function getUserReward(address _addr) public view returns (uint256) {
UserInfo storage user = userInfo[_addr];
uint256 totalReward = getTotalReward();
return user.amount.mul(totalReward).div(totalStaked);
}
/// @notice Deposit 1SWAP token to contract for reward allocation.
/// @param amount 1SWAP token amount to deposit.
function deposit(uint256 amount) external {
require(amount > 0, "Invalid amount");
require(totalStaked.add(amount) <= maxCap, ">maxCap");
require(block.timestamp < startLockTime, "Vault has already started");
UserInfo storage user = userInfo[_msgSender()];
// Effects
user.amount = user.amount.add(amount);
totalStaked = totalStaked.add(amount);
// Interactions
oneSwap.safeTransferFrom(_msgSender(), address(this), amount);
emit Deposit(_msgSender(), amount, _msgSender());
}
function earlyWithdraw(uint256 amount) external {
require(block.timestamp < startLockTime, "Vault has already started");
require(amount > 0, "invalid amount");
UserInfo storage user = userInfo[_msgSender()];
require(user.amount >= amount, "more than user staked amount");
// Effects
totalStaked = totalStaked.sub(amount);
user.amount = user.amount.sub(amount);
// Interactions
oneSwap.safeTransfer(_msgSender(), amount);
emit Withdraw(_msgSender(), amount, _msgSender());
}
/// @notice Withdraw 1SWAP token from contract and harvest proceeds for transaction sender to `to`.
function withdraw() external {
require(block.timestamp > endLockTime || forceUnlocked, "!locked");
UserInfo storage user = userInfo[_msgSender()];
uint256 _rewardAmount = getUserReward(_msgSender());
// Effects
uint256 amount = user.amount;
user.amount = 0;
// Interactions
if (_rewardAmount > 0) {
rewardFund.transfer(_msgSender(), _rewardAmount);
}
if (amount > 0) {
oneSwap.safeTransfer(_msgSender(), amount);
}
emit Withdraw(_msgSender(), amount, _msgSender());
emit Harvest(_msgSender(), _rewardAmount);
}
/// @notice Withdraw without caring about rewards. Still require after locked time;
function emergencyWithdraw() external {
require(block.timestamp > endLockTime || forceUnlocked, "!locked");
UserInfo storage user = userInfo[_msgSender()];
uint256 amount = user.amount;
user.amount = 0;
// Note: transfer can fail or succeed if `amount` is zero.
oneSwap.safeTransfer(_msgSender(), amount);
emit EmergencyWithdraw(_msgSender(), amount, _msgSender());
}
/* ========== RESTRICTED FUNCTIONS ========== */
/// @notice Sets the reward per second to be distributed. Can only be called by the owner.
/// @param _rewardPerSecond The amount of reward to be distributed per second.
function setRewardPerSecond(uint256 _rewardPerSecond) external onlyOwner {
if (_rewardPerSecond < rewardPerSecond) {
require(block.timestamp < startLockTime, "Only can reduce RewardPerSecond before started");
}
require(block.timestamp < endLockTime, "Only can update RewardPerSecond before ended");
rewardPerSecond = _rewardPerSecond;
emit UpdateRewardPerSecond(_rewardPerSecond);
}
function setRewardFund(address _fund) external onlyOwner {
require(_fund != address(0), "Address is invalid");
rewardFund = IStakingRewardFund(_fund);
emit UpdateRewardFund(_fund);
}
function toggleForceUnlocked(bool _unlocked) external onlyOwner {
forceUnlocked = _unlocked;
emit ForceUnlockedToggle(_unlocked);
}
function setDepositCap(uint256 _newCap) external onlyOwner {
require(_newCap >= totalStaked, "New cap cannot be lower than total staked amount");
maxCap = _newCap;
emit MaxCapUpdated(_newCap);
}
/* =============== EVENTS ==================== */
event Deposit(address indexed user, uint256 amount, address indexed to);
event Withdraw(address indexed user, uint256 amount, address indexed to);
event EmergencyWithdraw(address indexed user, uint256 amount, address indexed to);
event Harvest(address indexed user, uint256 amount);
event UpdateRewardPerSecond(uint256 rewardPerSecond);
event UpdateRewardFund(address indexed fund);
event ForceUnlockedToggle(bool _unlocked);
event MaxCapUpdated(uint256 _newCap);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*/
abstract contract Initializable {
/**
* @dev Indicates that the contract has been initialized.
*/
bool private _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool private _initializing;
/**
* @dev Modifier to protect an initializer function from being invoked twice.
*/
modifier initializer() {
require(_initializing || !_initialized, "Initializable: contract is already initialized");
bool isTopLevelCall = !_initializing;
if (isTopLevelCall) {
_initializing = true;
_initialized = true;
}
_;
if (isTopLevelCall) {
_initializing = false;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// CAUTION
// This version of SafeMath should only be used with Solidity 0.8 or later,
// because it relies on the compiler's built in overflow checks.
/**
* @dev Wrappers over Solidity's arithmetic operations.
*
* NOTE: `SafeMath` is no longer needed starting with Solidity 0.8. The compiler
* now has built in overflow checking.
*/
library SafeMath {
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the substraction of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*
* _Available since v3.4._
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*
* _Available since v3.4._
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the addition of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `+` operator.
*
* Requirements:
*
* - Addition cannot overflow.
*/
function add(uint256 a, uint256 b) internal pure returns (uint256) {
return a + b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting on
* overflow (when the result is negative).
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
return a - b;
}
/**
* @dev Returns the multiplication of two unsigned integers, reverting on
* overflow.
*
* Counterpart to Solidity's `*` operator.
*
* Requirements:
*
* - Multiplication cannot overflow.
*/
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
return a * b;
}
/**
* @dev Returns the integer division of two unsigned integers, reverting on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator.
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(uint256 a, uint256 b) internal pure returns (uint256) {
return a / b;
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting when dividing by zero.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(uint256 a, uint256 b) internal pure returns (uint256) {
return a % b;
}
/**
* @dev Returns the subtraction of two unsigned integers, reverting with custom message on
* overflow (when the result is negative).
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {trySub}.
*
* Counterpart to Solidity's `-` operator.
*
* Requirements:
*
* - Subtraction cannot overflow.
*/
function sub(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b <= a, errorMessage);
return a - b;
}
}
/**
* @dev Returns the integer division of two unsigned integers, reverting with custom message on
* division by zero. The result is rounded towards zero.
*
* Counterpart to Solidity's `/` operator. Note: this function uses a
* `revert` opcode (which leaves remaining gas untouched) while Solidity
* uses an invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function div(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a / b;
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
* reverting with custom message when dividing by zero.
*
* CAUTION: This function is deprecated because it requires allocating memory for the error
* message unnecessarily. For custom revert reasons use {tryMod}.
*
* Counterpart to Solidity's `%` operator. This function uses a `revert`
* opcode (which leaves remaining gas untouched) while Solidity uses an
* invalid opcode to revert (consuming all remaining gas).
*
* Requirements:
*
* - The divisor cannot be zero.
*/
function mod(
uint256 a,
uint256 b,
string memory errorMessage
) internal pure returns (uint256) {
unchecked {
require(b > 0, errorMessage);
return a % b;
}
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IStakingRewardFund {
function transfer(address _to, uint256 _amount) external;
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./OwnerPausable.sol";
import "./StableSwapStorage.sol";
import "../interfaces/IStableSwap.sol";
contract StableSwap is OwnerPausable, ReentrancyGuard, Initializable, IStableSwap {
using StableSwapStorage for StableSwapStorage.SwapStorage;
using SafeERC20 for IERC20;
/// constants
uint256 public constant MIN_RAMP_TIME = 1 days;
uint256 public constant MAX_A = 1e6; // max_a with precision
uint256 public constant MAX_A_CHANGE = 10;
uint256 public constant MAX_ADMIN_FEE = 1e10; // 100%
uint256 public constant MAX_SWAP_FEE = 1e8; // 1%
/// STATE VARS
StableSwapStorage.SwapStorage public swapStorage;
address public feeDistributor;
address public feeController;
mapping(address => uint8) public tokenIndexes;
modifier deadlineCheck(uint256 _deadline) {
require(block.timestamp <= _deadline, "timeout");
_;
}
modifier onlyFeeControllerOrOwner() {
require(msg.sender == feeController || msg.sender == owner(), "!feeControllerOrOwner");
_;
}
function initialize(
address[] memory _coins,
uint8[] memory _decimals,
string memory lpTokenName,
string memory lpTokenSymbol,
uint256 _A,
uint256 _fee,
uint256 _adminFee,
address _feeDistributor
) external onlyOwner initializer {
require(_coins.length == _decimals.length, "coinsLength != decimalsLength");
require(_feeDistributor != address(0), "feeDistributor = empty");
uint256 numberOfCoins = _coins.length;
uint256[] memory rates = new uint256[](numberOfCoins);
IERC20[] memory coins = new IERC20[](numberOfCoins);
for (uint256 i = 0; i < numberOfCoins; i++) {
require(_coins[i] != address(0), "invalidTokenAddress");
require(_decimals[i] <= StableSwapStorage.POOL_TOKEN_COMMON_DECIMALS, "invalidDecimals");
rates[i] = 10**(StableSwapStorage.POOL_TOKEN_COMMON_DECIMALS - _decimals[i]);
coins[i] = IERC20(_coins[i]);
tokenIndexes[address(coins[i])] = uint8(i);
}
require(_A < MAX_A, "> maxA");
require(_fee <= MAX_SWAP_FEE, "> maxSwapFee");
require(_adminFee <= MAX_ADMIN_FEE, "> maxAdminFee");
swapStorage.lpToken = new LPToken(lpTokenName, lpTokenSymbol);
swapStorage.balances = new uint256[](numberOfCoins);
swapStorage.tokenMultipliers = rates;
swapStorage.pooledTokens = coins;
swapStorage.initialA = _A * StableSwapStorage.A_PRECISION;
swapStorage.futureA = _A * StableSwapStorage.A_PRECISION;
swapStorage.fee = _fee;
swapStorage.adminFee = _adminFee;
feeDistributor = _feeDistributor;
}
/// PUBLIC FUNCTIONS
function addLiquidity(
uint256[] memory amounts,
uint256 minMintAmount,
uint256 deadline
) external override whenNotPaused nonReentrant deadlineCheck(deadline) returns (uint256) {
return swapStorage.addLiquidity(amounts, minMintAmount);
}
function swap(
uint8 fromIndex,
uint8 toIndex,
uint256 inAmount,
uint256 minOutAmount,
uint256 deadline
) external override whenNotPaused nonReentrant deadlineCheck(deadline) returns (uint256) {
return swapStorage.swap(fromIndex, toIndex, inAmount, minOutAmount);
}
function removeLiquidity(
uint256 lpAmount,
uint256[] memory minAmounts,
uint256 deadline
) external override nonReentrant deadlineCheck(deadline) returns (uint256[] memory) {
return swapStorage.removeLiquidity(lpAmount, minAmounts);
}
function removeLiquidityOneToken(
uint256 lpAmount,
uint8 index,
uint256 minAmount,
uint256 deadline
) external override nonReentrant whenNotPaused deadlineCheck(deadline) returns (uint256) {
return swapStorage.removeLiquidityOneToken(lpAmount, index, minAmount);
}
function removeLiquidityImbalance(
uint256[] memory amounts,
uint256 maxBurnAmount,
uint256 deadline
) external override nonReentrant whenNotPaused deadlineCheck(deadline) returns (uint256) {
return swapStorage.removeLiquidityImbalance(amounts, maxBurnAmount);
}
/// VIEW FUNCTIONS
function getVirtualPrice() external view override returns (uint256) {
return swapStorage.getVirtualPrice();
}
function getA() external view override returns (uint256) {
return swapStorage.getA();
}
function getAPrecise() external view override returns (uint256) {
return swapStorage.getAPrecise();
}
function getTokens() external view override returns (IERC20[] memory) {
return swapStorage.pooledTokens;
}
function getToken(uint8 index) external view override returns (IERC20) {
return swapStorage.pooledTokens[index];
}
function getLpToken() external view override returns (IERC20) {
return swapStorage.lpToken;
}
function getTokenIndex(address token) external view override returns (uint8 index) {
index = tokenIndexes[token];
require(address(swapStorage.pooledTokens[index]) == token, "tokenNotFound");
}
function getTokenPrecisionMultipliers() external view returns (uint256[] memory) {
return swapStorage.tokenMultipliers;
}
function getTokenBalances() external view override returns (uint256[] memory) {
return swapStorage.balances;
}
function getTokenBalance(uint8 index) external view override returns (uint256) {
return swapStorage.balances[index];
}
function getNumberOfTokens() external view override returns (uint256) {
return swapStorage.pooledTokens.length;
}
function getAdminBalances() external view override returns (uint256[] memory adminBalances) {
uint256 length = swapStorage.pooledTokens.length;
adminBalances = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
adminBalances[i] = swapStorage.getAdminBalance(i);
}
}
function getAdminBalance(uint8 index) external view override returns (uint256) {
return swapStorage.getAdminBalance((index));
}
function calculateTokenAmount(uint256[] calldata amounts, bool deposit) external view override returns (uint256) {
return swapStorage.calculateTokenAmount(amounts, deposit);
}
function calculateSwap(
uint8 inIndex,
uint8 outIndex,
uint256 inAmount
) external view override returns (uint256) {
return swapStorage.calculateSwap(inIndex, outIndex, inAmount);
}
function calculateRemoveLiquidity(uint256 amount) external view override returns (uint256[] memory) {
return swapStorage.calculateRemoveLiquidity(amount);
}
function calculateRemoveLiquidityOneToken(uint256 amount, uint8 index) external view override returns (uint256) {
return swapStorage.calculateRemoveLiquidityOneToken(amount, index);
}
/// RESTRICTED FUNCTION
/**
* @notice Sets the admin fee
* @dev adminFee cannot be higher than 100% of the swap fee
* swap fee cannot be higher than 1% of each swap
* @param newSwapFee new swap fee to be applied on future transactions
* @param newAdminFee new admin fee to be applied on future transactions
*/
function setFee(uint256 newSwapFee, uint256 newAdminFee) external onlyOwner {
require(newSwapFee <= MAX_SWAP_FEE, "> maxSwapFee");
require(newAdminFee <= MAX_ADMIN_FEE, "> maxAdminFee");
swapStorage.adminFee = newAdminFee;
swapStorage.fee = newSwapFee;
emit NewFee(newSwapFee, newAdminFee);
}
/**
* @notice Start ramping up or down A parameter towards given futureA_ and futureTime_
* Checks if the change is too rapid, and commits the new A value only when it falls under
* the limit range.
* @param futureA the new A to ramp towards
* @param futureATime timestamp when the new A should be reached
*/
function rampA(uint256 futureA, uint256 futureATime) external onlyOwner {
require(block.timestamp >= swapStorage.initialATime + (1 days), "< rampDelay"); // please wait 1 days before start a new ramping
require(futureATime >= block.timestamp + (MIN_RAMP_TIME), "< minRampTime");
require(0 < futureA && futureA < MAX_A, "outOfRange");
uint256 initialAPrecise = swapStorage.getAPrecise();
uint256 futureAPrecise = futureA * StableSwapStorage.A_PRECISION;
if (futureAPrecise < initialAPrecise) {
require(futureAPrecise * (MAX_A_CHANGE) >= initialAPrecise, "> maxChange");
} else {
require(futureAPrecise <= initialAPrecise * (MAX_A_CHANGE), "> maxChange");
}
swapStorage.initialA = initialAPrecise;
swapStorage.futureA = futureAPrecise;
swapStorage.initialATime = block.timestamp;
swapStorage.futureATime = futureATime;
emit RampA(initialAPrecise, futureAPrecise, block.timestamp, futureATime);
}
function stopRampA() external onlyOwner {
require(swapStorage.futureATime > block.timestamp, "alreadyStopped");
uint256 currentA = swapStorage.getAPrecise();
swapStorage.initialA = currentA;
swapStorage.futureA = currentA;
swapStorage.initialATime = block.timestamp;
swapStorage.futureATime = block.timestamp;
emit StopRampA(currentA, block.timestamp);
}
function setFeeController(address _feeController) external onlyOwner {
require(_feeController != address(0), "zeroAddress");
feeController = _feeController;
emit FeeControllerChanged(_feeController);
}
function setFeeDistributor(address _feeDistributor) external onlyOwner {
require(_feeDistributor != address(0), "zeroAddress");
feeDistributor = _feeDistributor;
emit FeeDistributorChanged(_feeDistributor);
}
function withdrawAdminFee() external override onlyFeeControllerOrOwner {
for (uint256 i = 0; i < swapStorage.pooledTokens.length; i++) {
IERC20 token = swapStorage.pooledTokens[i];
uint256 balance = token.balanceOf(address(this)) - (swapStorage.balances[i]);
if (balance != 0) {
token.safeTransfer(feeDistributor, balance);
emit CollectProtocolFee(address(token), balance);
}
}
}
}// SPDX-License-Identifier: MIT
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 make it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// On the first call to nonReentrant, _notEntered will be true
require(_status != _ENTERED, "ReentrancyGuard: reentrant call");
// Any calls to nonReentrant after this point will fail
_status = _ENTERED;
_;
// 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
pragma solidity 0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
abstract contract OwnerPausable is Ownable, Pausable {
function pause() external onlyOwner {
_pause();
}
function unpause() external onlyOwner {
_unpause();
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "./LPToken.sol";
/**
* StableSwap main algorithm
*/
library StableSwapStorage {
using SafeERC20 for IERC20;
event AddLiquidity(
address indexed provider,
uint256[] token_amounts,
uint256[] fees,
uint256 invariant,
uint256 token_supply
);
event TokenExchange(
address indexed buyer,
uint256 sold_id,
uint256 tokens_sold,
uint256 bought_id,
uint256 tokens_bought
);
event RemoveLiquidity(address indexed provider, uint256[] token_amounts, uint256[] fees, uint256 token_supply);
event RemoveLiquidityOne(address indexed provider, uint256 index, uint256 token_amount, uint256 coin_amount);
event RemoveLiquidityImbalance(
address indexed provider,
uint256[] token_amounts,
uint256[] fees,
uint256 invariant,
uint256 token_supply
);
uint256 public constant FEE_DENOMINATOR = 1e10;
// uint256 public constant PRECISION = 1e18;
/// @dev protect from division loss when run approximation loop. We cannot divide at the end because of overflow,
/// so we add some (small) PRECISION when divide in each iteration
uint256 public constant A_PRECISION = 100;
/// @dev max iteration of converge calccuate
uint256 internal constant MAX_ITERATION = 256;
uint256 public constant POOL_TOKEN_COMMON_DECIMALS = 18;
struct SwapStorage {
IERC20[] pooledTokens;
LPToken lpToken;
/// @dev token i multiplier to reach POOL_TOKEN_COMMON_DECIMALS
uint256[] tokenMultipliers;
/// @dev effective balance which might different from token balance of the contract 'cause it hold admin fee as well
uint256[] balances;
/// @dev swap fee ratio. Charge on any action which move balance state far from the ideal state
uint256 fee;
/// @dev admin fee in ratio of swap fee.
uint256 adminFee;
/// @dev observation of A, multiplied with A_PRECISION
uint256 initialA;
uint256 futureA;
uint256 initialATime;
uint256 futureATime;
}
/**
* @notice Deposit coins into the pool
* @param amounts List of amounts of coins to deposit
* @param minMintAmount Minimum amount of LP tokens to mint from the deposit
* @return mintAmount Amount of LP tokens received by depositing
*/
function addLiquidity(
SwapStorage storage self,
uint256[] memory amounts,
uint256 minMintAmount
) external returns (uint256 mintAmount) {
uint256 nCoins = self.pooledTokens.length;
require(amounts.length == nCoins, "invalidAmountsLength");
uint256[] memory fees = new uint256[](nCoins);
uint256 _fee = _feePerToken(self);
uint256 tokenSupply = self.lpToken.totalSupply();
uint256 amp = _getAPrecise(self);
uint256 D0 = 0;
if (tokenSupply > 0) {
D0 = _getD(_xp(self.balances, self.tokenMultipliers), amp);
}
uint256[] memory newBalances = self.balances;
for (uint256 i = 0; i < nCoins; i++) {
if (tokenSupply == 0) {
require(amounts[i] > 0, "initialDepositRequireAllTokens");
}
// get real transfer in amount
newBalances[i] += _doTransferIn(self.pooledTokens[i], amounts[i]);
}
uint256 D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp);
assert(D1 > D0); // double check
if (tokenSupply == 0) {
self.balances = newBalances;
mintAmount = D1;
} else {
uint256 diff = 0;
for (uint256 i = 0; i < nCoins; i++) {
diff = _distance((D1 * self.balances[i]) / D0, newBalances[i]);
fees[i] = (_fee * diff) / FEE_DENOMINATOR;
self.balances[i] = newBalances[i] - ((fees[i] * self.adminFee) / FEE_DENOMINATOR);
newBalances[i] -= fees[i];
}
D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp);
mintAmount = (tokenSupply * (D1 - D0)) / D0;
}
require(mintAmount >= minMintAmount, "> slippage");
self.lpToken.mint(msg.sender, mintAmount);
emit AddLiquidity(msg.sender, amounts, fees, D1, mintAmount);
}
function swap(
SwapStorage storage self,
uint256 i,
uint256 j,
uint256 inAmount,
uint256 minOutAmount
) external returns (uint256) {
IERC20 inCoin = self.pooledTokens[i];
uint256[] memory normalizedBalances = _xp(self);
inAmount = _doTransferIn(inCoin, inAmount);
uint256 x = normalizedBalances[i] + (inAmount * self.tokenMultipliers[i]);
uint256 y = _getY(self, i, j, x, normalizedBalances);
uint256 dy = normalizedBalances[j] - y - 1; // iliminate rouding errors
uint256 dy_fee = (dy * self.fee) / FEE_DENOMINATOR;
dy = (dy - dy_fee) / self.tokenMultipliers[j]; // denormalize
require(dy >= minOutAmount, "> slippage");
uint256 _adminFee = (dy_fee * self.adminFee) / FEE_DENOMINATOR / self.tokenMultipliers[j];
// update balances
self.balances[i] += inAmount;
self.balances[j] -= dy + _adminFee;
self.pooledTokens[j].safeTransfer(msg.sender, dy);
emit TokenExchange(msg.sender, i, inAmount, j, dy);
return dy;
}
function removeLiquidity(
SwapStorage storage self,
uint256 lpAmount,
uint256[] memory minAmounts
) external returns (uint256[] memory amounts) {
uint256 totalSupply = self.lpToken.totalSupply();
require(lpAmount <= totalSupply);
uint256 nCoins = self.pooledTokens.length;
uint256[] memory fees = new uint256[](nCoins);
amounts = _calculateRemoveLiquidity(self, lpAmount);
for (uint256 i = 0; i < amounts.length; i++) {
require(amounts[i] >= minAmounts[i], "> slippage");
self.balances[i] = self.balances[i] - amounts[i];
self.pooledTokens[i].safeTransfer(msg.sender, amounts[i]);
}
self.lpToken.burnFrom(msg.sender, lpAmount);
emit RemoveLiquidity(msg.sender, amounts, fees, totalSupply - lpAmount);
}
function removeLiquidityOneToken(
SwapStorage storage self,
uint256 lpAmount,
uint256 index,
uint256 minAmount
) external returns (uint256) {
uint256 totalSupply = self.lpToken.totalSupply();
require(totalSupply > 0, "totalSupply = 0");
uint256 numTokens = self.pooledTokens.length;
require(lpAmount <= self.lpToken.balanceOf(msg.sender), "> balance");
require(lpAmount <= totalSupply, "> totalSupply");
require(index < numTokens, "tokenNotFound");
uint256 dyFee;
uint256 dy;
(dy, dyFee) = _calculateRemoveLiquidityOneToken(self, lpAmount, index);
require(dy >= minAmount, "> slippage");
self.balances[index] -= (dy + (dyFee * self.adminFee) / FEE_DENOMINATOR);
self.lpToken.burnFrom(msg.sender, lpAmount);
self.pooledTokens[index].safeTransfer(msg.sender, dy);
emit RemoveLiquidityOne(msg.sender, index, lpAmount, dy);
return dy;
}
function removeLiquidityImbalance(
SwapStorage storage self,
uint256[] memory amounts,
uint256 maxBurnAmount
) external returns (uint256 burnAmount) {
uint256 nCoins = self.pooledTokens.length;
require(amounts.length == nCoins, "invalidAmountsLength");
uint256 totalSupply = self.lpToken.totalSupply();
require(totalSupply != 0, "totalSupply = 0");
uint256 _fee = _feePerToken(self);
uint256 amp = _getAPrecise(self);
uint256[] memory newBalances = self.balances;
uint256 D0 = _getD(_xp(self), amp);
for (uint256 i = 0; i < nCoins; i++) {
newBalances[i] -= amounts[i];
}
uint256 D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp);
uint256[] memory fees = new uint256[](nCoins);
for (uint256 i = 0; i < nCoins; i++) {
uint256 idealBalance = (D1 * self.balances[i]) / D0;
uint256 diff = _distance(newBalances[i], idealBalance);
fees[i] = (_fee * diff) / FEE_DENOMINATOR;
self.balances[i] = newBalances[i] - ((fees[i] * self.adminFee) / FEE_DENOMINATOR);
newBalances[i] -= fees[i];
}
// recalculate invariant with fee charged balances
D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp);
burnAmount = ((D0 - D1) * totalSupply) / D0;
assert(burnAmount > 0);
require(burnAmount <= maxBurnAmount, "> slippage");
self.lpToken.burnFrom(msg.sender, burnAmount);
for (uint256 i = 0; i < nCoins; i++) {
if (amounts[i] != 0) {
self.pooledTokens[i].safeTransfer(msg.sender, amounts[i]);
}
}
emit RemoveLiquidityImbalance(msg.sender, amounts, fees, D1, totalSupply - burnAmount);
}
/// VIEW FUNCTIONS
function getAPrecise(SwapStorage storage self) external view returns (uint256) {
return _getAPrecise(self);
}
/**
* Returns portfolio virtual price (for calculating profit)
* scaled up by 1e18
*/
function getVirtualPrice(SwapStorage storage self) external view returns (uint256) {
uint256 D = _getD(_xp(self), _getAPrecise(self));
uint256 tokenSupply = self.lpToken.totalSupply();
return (D * 10**POOL_TOKEN_COMMON_DECIMALS) / tokenSupply;
}
function getAdminBalance(SwapStorage storage self, uint256 index) external view returns (uint256) {
require(index < self.pooledTokens.length, "indexOutOfRange");
return self.pooledTokens[index].balanceOf(address(this)) - (self.balances[index]);
}
/**
* Estimate amount of LP token minted or burned at deposit or withdrawal
* without taking fees into account
*/
function calculateTokenAmount(
SwapStorage storage self,
uint256[] memory amounts,
bool deposit
) external view returns (uint256) {
uint256 nCoins = self.pooledTokens.length;
require(amounts.length == nCoins, "invalidAmountsLength");
uint256 amp = _getAPrecise(self);
uint256 D0 = _getD(_xp(self), amp);
uint256[] memory newBalances = self.balances;
for (uint256 i = 0; i < nCoins; i++) {
if (deposit) {
newBalances[i] += amounts[i];
} else {
newBalances[i] -= amounts[i];
}
}
uint256 D1 = _getD(_xp(newBalances, self.tokenMultipliers), amp);
uint256 totalSupply = self.lpToken.totalSupply();
if (totalSupply == 0) {
return D1; // first depositor take it all
}
uint256 diff = deposit ? D1 - D0 : D0 - D1;
return (diff * self.lpToken.totalSupply()) / D0;
}
function getA(SwapStorage storage self) external view returns (uint256) {
return _getAPrecise(self) / A_PRECISION;
}
function calculateSwap(
SwapStorage storage self,
uint256 inIndex,
uint256 outIndex,
uint256 inAmount
) external view returns (uint256) {
uint256[] memory normalizedBalances = _xp(self);
uint256 newInBalance = normalizedBalances[inIndex] + (inAmount * self.tokenMultipliers[inIndex]);
uint256 outBalance = _getY(self, inIndex, outIndex, newInBalance, normalizedBalances);
uint256 outAmount = (normalizedBalances[outIndex] - outBalance - 1) / self.tokenMultipliers[outIndex];
uint256 _fee = (self.fee * outAmount) / FEE_DENOMINATOR;
return outAmount - _fee;
}
function calculateRemoveLiquidity(SwapStorage storage self, uint256 amount)
external
view
returns (uint256[] memory)
{
return _calculateRemoveLiquidity(self, amount);
}
function calculateRemoveLiquidityOneToken(
SwapStorage storage self,
uint256 lpAmount,
uint256 tokenIndex
) external view returns (uint256 amount) {
(amount, ) = _calculateRemoveLiquidityOneToken(self, lpAmount, tokenIndex);
}
/// INTERNAL FUNCTIONS
/**
* Ramping A up or down, return A with precision of A_PRECISION
*/
function _getAPrecise(SwapStorage storage self) internal view returns (uint256) {
if (block.timestamp >= self.futureATime) {
return self.futureA;
}
if (self.futureA > self.initialA) {
return
self.initialA +
((self.futureA - self.initialA) * (block.timestamp - self.initialATime)) /
(self.futureATime - self.initialATime);
}
return
self.initialA -
((self.initialA - self.futureA) * (block.timestamp - self.initialATime)) /
(self.futureATime - self.initialATime);
}
/**
* normalized balances of each tokens.
*/
function _xp(uint256[] memory balances, uint256[] memory rates) internal pure returns (uint256[] memory) {
for (uint256 i = 0; i < balances.length; i++) {
rates[i] = (rates[i] * balances[i]);
}
return rates;
}
function _xp(SwapStorage storage self) internal view returns (uint256[] memory) {
return _xp(self.balances, self.tokenMultipliers);
}
/**
* Calculate D for *NORMALIZED* balances of each tokens
* @param xp normalized balances of token
*/
function _getD(uint256[] memory xp, uint256 amp) internal pure returns (uint256) {
uint256 nCoins = xp.length;
uint256 sum = _sumOf(xp);
if (sum == 0) {
return 0;
}
uint256 Dprev = 0;
uint256 D = sum;
uint256 Ann = amp * nCoins;
for (uint256 i = 0; i < MAX_ITERATION; i++) {
uint256 D_P = D;
for (uint256 j = 0; j < xp.length; j++) {
D_P = (D_P * D) / (xp[j] * nCoins);
}
Dprev = D;
D =
(((Ann * sum) / A_PRECISION + D_P * nCoins) * D) /
(((Ann - A_PRECISION) * D) / A_PRECISION + (nCoins + 1) * D_P);
if (_distance(D, Dprev) <= 1) {
return D;
}
}
// Convergence should occur in 4 loops or less. If this is reached, there may be something wrong
// with the pool. If this were to occur repeatedly, LPs should withdraw via `removeLiquidity()`
// function which does not rely on D.
revert("invariantCalculationFailed");
}
/**
* calculate new balance of when swap
* Done by solving quadratic equation iteratively.
* x_1**2 + x_1 * (sum' - (A*n**n - 1) * D / (A * n**n)) = D ** (n + 1) / (n ** (2 * n) * prod' * A)
* x_1**2 + b*x_1 = c
* x_1 = (x_1**2 + c) / (2*x_1 + b)
* @param inIndex index of token to swap in
* @param outIndex index of token to swap out
* @param inBalance new balance (normalized) of input token if the swap success
* @return NORMALIZED balance of output token if the swap success
*/
function _getY(
SwapStorage storage self,
uint256 inIndex,
uint256 outIndex,
uint256 inBalance,
uint256[] memory normalizedBalances
) internal view returns (uint256) {
require(inIndex != outIndex, "sameToken");
uint256 nCoins = self.pooledTokens.length;
require(inIndex < nCoins && outIndex < nCoins, "indexOutOfRange");
uint256 amp = _getAPrecise(self);
uint256 Ann = amp * nCoins;
uint256 D = _getD(normalizedBalances, amp);
uint256 sum = 0; // sum of new balances except output token
uint256 c = D;
for (uint256 i = 0; i < nCoins; i++) {
if (i == outIndex) {
continue;
}
uint256 x = i == inIndex ? inBalance : normalizedBalances[i];
sum += x;
c = (c * D) / (x * nCoins);
}
c = (c * D * A_PRECISION) / (Ann * nCoins);
uint256 b = sum + (D * A_PRECISION) / Ann;
uint256 lastY = 0;
uint256 y = D;
for (uint256 index = 0; index < MAX_ITERATION; index++) {
lastY = y;
y = (y * y + c) / (2 * y + b - D);
if (_distance(lastY, y) <= 1) {
return y;
}
}
revert("yCalculationFailed");
}
function _calculateRemoveLiquidity(SwapStorage storage self, uint256 amount)
internal
view
returns (uint256[] memory)
{
uint256 totalSupply = self.lpToken.totalSupply();
require(amount <= totalSupply, "Cannot exceed total supply");
uint256[] memory amounts = new uint256[](self.pooledTokens.length);
for (uint256 i = 0; i < self.pooledTokens.length; i++) {
amounts[i] = (self.balances[i] * (amount)) / (totalSupply);
}
return amounts;
}
function _calculateRemoveLiquidityOneToken(
SwapStorage storage self,
uint256 tokenAmount,
uint256 index
) internal view returns (uint256 dy, uint256 fee) {
require(index < self.pooledTokens.length, "indexOutOfRange");
uint256 amp = _getAPrecise(self);
uint256[] memory xp = _xp(self);
uint256 D0 = _getD(xp, amp);
uint256 D1 = D0 - (tokenAmount * D0) / self.lpToken.totalSupply();
uint256 newY = _getYD(self, amp, index, xp, D1);
uint256[] memory reducedXP = xp;
uint256 _fee = _feePerToken(self);
for (uint256 i = 0; i < self.pooledTokens.length; i++) {
uint256 expectedDx = 0;
if (i == index) {
expectedDx = (xp[i] * D1) / D0 - newY;
} else {
expectedDx = xp[i] - (xp[i] * D1) / D0;
}
reducedXP[i] -= (_fee * expectedDx) / FEE_DENOMINATOR;
}
dy = reducedXP[index] - _getYD(self, amp, index, reducedXP, D1);
dy = (dy - 1) / self.tokenMultipliers[index];
fee = ((xp[index] - newY) / self.tokenMultipliers[index]) - dy;
}
function _feePerToken(SwapStorage storage self) internal view returns (uint256) {
uint256 nCoins = self.pooledTokens.length;
return (self.fee * nCoins) / (4 * (nCoins - 1));
}
function _getYD(
SwapStorage storage self,
uint256 A,
uint256 index,
uint256[] memory xp,
uint256 D
) internal view returns (uint256) {
uint256 nCoins = self.pooledTokens.length;
assert(index < nCoins);
uint256 Ann = A * nCoins;
uint256 c = D;
uint256 s = 0;
uint256 _x = 0;
uint256 yPrev = 0;
for (uint256 i = 0; i < nCoins; i++) {
if (i == index) {
continue;
}
_x = xp[i];
s += _x;
c = (c * D) / (_x * nCoins);
}
c = (c * D * A_PRECISION) / (Ann * nCoins);
uint256 b = s + (D * A_PRECISION) / Ann;
uint256 y = D;
for (uint256 i = 0; i < MAX_ITERATION; i++) {
yPrev = y;
y = (y * y + c) / (2 * y + b - D);
if (_distance(yPrev, y) <= 1) {
return y;
}
}
revert("invariantCalculationFailed");
}
function _doTransferIn(IERC20 token, uint256 amount) internal returns (uint256) {
uint256 priorBalance = token.balanceOf(address(this));
token.safeTransferFrom(msg.sender, address(this), amount);
return token.balanceOf(address(this)) - priorBalance;
}
function _sumOf(uint256[] memory x) internal pure returns (uint256 sum) {
sum = 0;
for (uint256 i = 0; i < x.length; i++) {
sum += x[i];
}
}
function _distance(uint256 x, uint256 y) internal pure returns (uint256) {
return x > y ? x - y : y - x;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IStableSwap {
/// EVENTS
event AddLiquidity(
address indexed provider,
uint256[] tokenAmounts,
uint256[] fees,
uint256 invariant,
uint256 tokenSupply
);
event TokenExchange(
address indexed buyer,
uint256 soldId,
uint256 tokensSold,
uint256 boughtId,
uint256 tokensBought
);
event RemoveLiquidity(address indexed provider, uint256[] tokenAmounts, uint256[] fees, uint256 tokenSupply);
event RemoveLiquidityOne(address indexed provider, uint256 tokenIndex, uint256 tokenAmount, uint256 coinAmount);
event RemoveLiquidityImbalance(
address indexed provider,
uint256[] tokenAmounts,
uint256[] fees,
uint256 invariant,
uint256 tokenSupply
);
event RampA(uint256 oldA, uint256 newA, uint256 initialTime, uint256 futureTime);
event StopRampA(uint256 A, uint256 timestamp);
event NewFee(uint256 fee, uint256 adminFee);
event CollectProtocolFee(address token, uint256 amount);
event FeeControllerChanged(address newController);
event FeeDistributorChanged(address newController);
// pool data view functions
function getLpToken() external view returns (IERC20 lpToken);
function getA() external view returns (uint256);
function getAPrecise() external view returns (uint256);
function getToken(uint8 index) external view returns (IERC20);
function getTokens() external view returns (IERC20[] memory);
function getTokenIndex(address tokenAddress) external view returns (uint8);
function getTokenBalance(uint8 index) external view returns (uint256);
function getTokenBalances() external view returns (uint256[] memory);
function getNumberOfTokens() external view returns (uint256);
function getVirtualPrice() external view returns (uint256);
function calculateTokenAmount(uint256[] calldata amounts, bool deposit) external view returns (uint256);
function calculateSwap(
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx
) external view returns (uint256);
function calculateRemoveLiquidity(uint256 amount) external view returns (uint256[] memory);
function calculateRemoveLiquidityOneToken(uint256 tokenAmount, uint8 tokenIndex)
external
view
returns (uint256 availableTokenAmount);
function getAdminBalances() external view returns (uint256[] memory adminBalances);
function getAdminBalance(uint8 index) external view returns (uint256);
// state modifying functions
function swap(
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx,
uint256 minDy,
uint256 deadline
) external returns (uint256);
function addLiquidity(
uint256[] calldata amounts,
uint256 minToMint,
uint256 deadline
) external returns (uint256);
function removeLiquidity(
uint256 amount,
uint256[] calldata minAmounts,
uint256 deadline
) external returns (uint256[] memory);
function removeLiquidityOneToken(
uint256 tokenAmount,
uint8 tokenIndex,
uint256 minAmount,
uint256 deadline
) external returns (uint256);
function removeLiquidityImbalance(
uint256[] calldata amounts,
uint256 maxBurnAmount,
uint256 deadline
) external returns (uint256);
function withdrawAdminFee() external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../utils/Context.sol";
/**
* @dev Contract module which allows children to implement an emergency stop
* mechanism that can be triggered by an authorized account.
*
* This module is used through inheritance. It will make available the
* modifiers `whenNotPaused` and `whenPaused`, which can be applied to
* the functions of your contract. Note that they will not be pausable by
* simply including this module, only once the modifiers are put in place.
*/
abstract contract Pausable is Context {
/**
* @dev Emitted when the pause is triggered by `account`.
*/
event Paused(address account);
/**
* @dev Emitted when the pause is lifted by `account`.
*/
event Unpaused(address account);
bool private _paused;
/**
* @dev Initializes the contract in unpaused state.
*/
constructor() {
_paused = false;
}
/**
* @dev Returns true if the contract is paused, and false otherwise.
*/
function paused() public view virtual returns (bool) {
return _paused;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
*
* Requirements:
*
* - The contract must not be paused.
*/
modifier whenNotPaused() {
require(!paused(), "Pausable: paused");
_;
}
/**
* @dev Modifier to make a function callable only when the contract is paused.
*
* Requirements:
*
* - The contract must be paused.
*/
modifier whenPaused() {
require(paused(), "Pausable: not paused");
_;
}
/**
* @dev Triggers stopped state.
*
* Requirements:
*
* - The contract must not be paused.
*/
function _pause() internal virtual whenNotPaused {
_paused = true;
emit Paused(_msgSender());
}
/**
* @dev Returns to normal state.
*
* Requirements:
*
* - The contract must be paused.
*/
function _unpause() internal virtual whenPaused {
_paused = false;
emit Unpaused(_msgSender());
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "../interfaces/IStableSwap.sol";
contract LPToken is Ownable, ERC20Burnable {
IStableSwap public swap;
constructor(string memory _name, string memory _symbol) ERC20(_name, _symbol) {
swap = IStableSwap(msg.sender);
}
function mint(address _to, uint256 _amount) external onlyOwner {
require(_amount > 0, "zeroMintAmount");
_mint(_to, _amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "../ERC20.sol";
import "../../../utils/Context.sol";
/**
* @dev Extension of {ERC20} that allows token holders to destroy both their own
* tokens and those that they have an allowance for, in a way that can be
* recognized off-chain (via event analysis).
*/
abstract contract ERC20Burnable is Context, ERC20 {
/**
* @dev Destroys `amount` tokens from the caller.
*
* See {ERC20-_burn}.
*/
function burn(uint256 amount) public virtual {
_burn(_msgSender(), amount);
}
/**
* @dev Destroys `amount` tokens from `account`, deducting from the caller's
* allowance.
*
* See {ERC20-_burn} and {ERC20-allowance}.
*
* Requirements:
*
* - the caller must have allowance for ``accounts``'s tokens of at least
* `amount`.
*/
function burnFrom(address account, uint256 amount) public virtual {
uint256 currentAllowance = allowance(account, _msgSender());
require(currentAllowance >= amount, "ERC20: burn amount exceeds allowance");
unchecked {
_approve(account, _msgSender(), currentAllowance - amount);
}
_burn(account, amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";
/**
* @dev Implementation of the {IERC20} interface.
*
* This implementation is agnostic to the way tokens are created. This means
* that a supply mechanism has to be added in a derived contract using {_mint}.
* For a generic mechanism see {ERC20PresetMinterPauser}.
*
* TIP: For a detailed writeup see our guide
* https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
* to implement supply mechanisms].
*
* We have followed general OpenZeppelin Contracts guidelines: functions revert
* instead returning `false` on failure. This behavior is nonetheless
* conventional and does not conflict with the expectations of ERC20
* applications.
*
* Additionally, an {Approval} event is emitted on calls to {transferFrom}.
* This allows applications to reconstruct the allowance for all accounts just
* by listening to said events. Other implementations of the EIP may not emit
* these events, as it isn't required by the specification.
*
* Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
* functions have been added to mitigate the well-known issues around setting
* allowances. See {IERC20-approve}.
*/
contract ERC20 is Context, IERC20, IERC20Metadata {
mapping(address => uint256) private _balances;
mapping(address => mapping(address => uint256)) private _allowances;
uint256 private _totalSupply;
string private _name;
string private _symbol;
/**
* @dev Sets the values for {name} and {symbol}.
*
* The default value of {decimals} is 18. To select a different value for
* {decimals} you should overload it.
*
* All two of these values are immutable: they can only be set once during
* construction.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev Returns the name of the token.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the symbol of the token, usually a shorter version of the
* name.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the number of decimals used to get its user representation.
* For example, if `decimals` equals `2`, a balance of `505` tokens should
* be displayed to a user as `5.05` (`505 / 10 ** 2`).
*
* Tokens usually opt for a value of 18, imitating the relationship between
* Ether and Wei. This is the value {ERC20} uses, unless this function is
* overridden;
*
* NOTE: This information is only used for _display_ purposes: it in
* no way affects any of the arithmetic of the contract, including
* {IERC20-balanceOf} and {IERC20-transfer}.
*/
function decimals() public view virtual override returns (uint8) {
return 18;
}
/**
* @dev See {IERC20-totalSupply}.
*/
function totalSupply() public view virtual override returns (uint256) {
return _totalSupply;
}
/**
* @dev See {IERC20-balanceOf}.
*/
function balanceOf(address account) public view virtual override returns (uint256) {
return _balances[account];
}
/**
* @dev See {IERC20-transfer}.
*
* Requirements:
*
* - `recipient` cannot be the zero address.
* - the caller must have a balance of at least `amount`.
*/
function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
_transfer(_msgSender(), recipient, amount);
return true;
}
/**
* @dev See {IERC20-allowance}.
*/
function allowance(address owner, address spender) public view virtual override returns (uint256) {
return _allowances[owner][spender];
}
/**
* @dev See {IERC20-approve}.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function approve(address spender, uint256 amount) public virtual override returns (bool) {
_approve(_msgSender(), spender, amount);
return true;
}
/**
* @dev See {IERC20-transferFrom}.
*
* Emits an {Approval} event indicating the updated allowance. This is not
* required by the EIP. See the note at the beginning of {ERC20}.
*
* Requirements:
*
* - `sender` and `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
* - the caller must have allowance for ``sender``'s tokens of at least
* `amount`.
*/
function transferFrom(
address sender,
address recipient,
uint256 amount
) public virtual override returns (bool) {
_transfer(sender, recipient, amount);
uint256 currentAllowance = _allowances[sender][_msgSender()];
require(currentAllowance >= amount, "ERC20: transfer amount exceeds allowance");
unchecked {
_approve(sender, _msgSender(), currentAllowance - amount);
}
return true;
}
/**
* @dev Atomically increases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
*/
function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
_approve(_msgSender(), spender, _allowances[_msgSender()][spender] + addedValue);
return true;
}
/**
* @dev Atomically decreases the allowance granted to `spender` by the caller.
*
* This is an alternative to {approve} that can be used as a mitigation for
* problems described in {IERC20-approve}.
*
* Emits an {Approval} event indicating the updated allowance.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `spender` must have allowance for the caller of at least
* `subtractedValue`.
*/
function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
uint256 currentAllowance = _allowances[_msgSender()][spender];
require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
unchecked {
_approve(_msgSender(), spender, currentAllowance - subtractedValue);
}
return true;
}
/**
* @dev Moves `amount` of tokens from `sender` to `recipient`.
*
* This internal function is equivalent to {transfer}, and can be used to
* e.g. implement automatic token fees, slashing mechanisms, etc.
*
* Emits a {Transfer} event.
*
* Requirements:
*
* - `sender` cannot be the zero address.
* - `recipient` cannot be the zero address.
* - `sender` must have a balance of at least `amount`.
*/
function _transfer(
address sender,
address recipient,
uint256 amount
) internal virtual {
require(sender != address(0), "ERC20: transfer from the zero address");
require(recipient != address(0), "ERC20: transfer to the zero address");
_beforeTokenTransfer(sender, recipient, amount);
uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
unchecked {
_balances[sender] = senderBalance - amount;
}
_balances[recipient] += amount;
emit Transfer(sender, recipient, amount);
_afterTokenTransfer(sender, recipient, amount);
}
/** @dev Creates `amount` tokens and assigns them to `account`, increasing
* the total supply.
*
* Emits a {Transfer} event with `from` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
*/
function _mint(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: mint to the zero address");
_beforeTokenTransfer(address(0), account, amount);
_totalSupply += amount;
_balances[account] += amount;
emit Transfer(address(0), account, amount);
_afterTokenTransfer(address(0), account, amount);
}
/**
* @dev Destroys `amount` tokens from `account`, reducing the
* total supply.
*
* Emits a {Transfer} event with `to` set to the zero address.
*
* Requirements:
*
* - `account` cannot be the zero address.
* - `account` must have at least `amount` tokens.
*/
function _burn(address account, uint256 amount) internal virtual {
require(account != address(0), "ERC20: burn from the zero address");
_beforeTokenTransfer(account, address(0), amount);
uint256 accountBalance = _balances[account];
require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
unchecked {
_balances[account] = accountBalance - amount;
}
_totalSupply -= amount;
emit Transfer(account, address(0), amount);
_afterTokenTransfer(account, address(0), amount);
}
/**
* @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
*
* This internal function is equivalent to `approve`, and can be used to
* e.g. set automatic allowances for certain subsystems, etc.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `owner` cannot be the zero address.
* - `spender` cannot be the zero address.
*/
function _approve(
address owner,
address spender,
uint256 amount
) internal virtual {
require(owner != address(0), "ERC20: approve from the zero address");
require(spender != address(0), "ERC20: approve to the zero address");
_allowances[owner][spender] = amount;
emit Approval(owner, spender, amount);
}
/**
* @dev Hook that is called before any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* will be transferred to `to`.
* - when `from` is zero, `amount` tokens will be minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens will be burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _beforeTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
/**
* @dev Hook that is called after any transfer of tokens. This includes
* minting and burning.
*
* Calling conditions:
*
* - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
* has been transferred to `to`.
* - when `from` is zero, `amount` tokens have been minted for `to`.
* - when `to` is zero, `amount` of ``from``'s tokens have been burned.
* - `from` and `to` are never both zero.
*
* To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
*/
function _afterTokenTransfer(
address from,
address to,
uint256 amount
) internal virtual {}
}// SPDX-License-Identifier: MIT
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
pragma solidity 0.8.4;
import "../interfaces/IStableSwap.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract StableSwapRouter {
using SafeERC20 for IERC20;
function convert(
IStableSwap fromPool,
IStableSwap toPool,
uint256 amount,
uint256 minToMint,
uint256 deadline
) external returns (uint256) {
uint256 fromPoolLength = fromPool.getNumberOfTokens();
uint256 toPoolLength = toPool.getNumberOfTokens();
require(address(fromPool) != address(toPool), "fromPool = toPool");
require(fromPoolLength == toPoolLength, "poolTokensLengthMissmatch");
IERC20 fromToken = fromPool.getLpToken();
IERC20 toToken = toPool.getLpToken();
uint256[] memory min_amounts = new uint256[](fromPoolLength);
// validate token
for (uint8 i = 0; i < fromPoolLength; i++) {
IERC20 coin = fromPool.getToken(i);
toPool.getTokenIndex(address(coin));
}
fromToken.transferFrom(msg.sender, address(this), amount);
fromToken.safeIncreaseAllowance(address(fromPool), amount);
fromPool.removeLiquidity(amount, min_amounts, deadline);
uint256[] memory meta_amounts = new uint256[](toPoolLength);
for (uint8 i = 0; i < toPoolLength; i++) {
IERC20 coin = toPool.getToken(i);
uint256 addBalance = coin.balanceOf(address(this));
coin.safeIncreaseAllowance(address(toPool), addBalance);
meta_amounts[i] = addBalance;
}
toPool.addLiquidity(meta_amounts, minToMint, deadline);
uint256 lpAmount = toToken.balanceOf(address(this));
toToken.transfer(msg.sender, lpAmount);
return lpAmount;
}
function addLiquidity(
IStableSwap pool,
IStableSwap basePool,
uint256[] memory meta_amounts,
uint256[] memory base_amounts,
uint256 minToMint,
uint256 deadline
) external returns (uint256) {
IERC20 token = IERC20(pool.getLpToken());
require(base_amounts.length == basePool.getNumberOfTokens(), "invalidBaseAmountsLength");
require(meta_amounts.length == pool.getNumberOfTokens(), "invalidMetaAmountsLength");
bool deposit_base = false;
for (uint8 i = 0; i < base_amounts.length; i++) {
uint256 amount = base_amounts[i];
if (amount > 0) {
deposit_base = true;
IERC20 coin = basePool.getToken(i);
coin.safeTransferFrom(msg.sender, address(this), amount);
uint256 transferred = coin.balanceOf(address(this));
coin.safeIncreaseAllowance(address(basePool), transferred);
base_amounts[i] = transferred;
}
}
if (deposit_base) {
basePool.addLiquidity(base_amounts, 0, deadline);
}
for (uint8 i = 0; i < meta_amounts.length; i++) {
IERC20 coin = pool.getToken(i);
if (meta_amounts[i] > 0) {
coin.safeTransferFrom(msg.sender, address(this), meta_amounts[i]);
}
uint256 transferred = coin.balanceOf(address(this));
coin.safeIncreaseAllowance(address(pool), transferred);
meta_amounts[i] = transferred;
}
pool.addLiquidity(meta_amounts, minToMint, deadline);
uint256 lpAmount = token.balanceOf(address(this));
token.transfer(msg.sender, lpAmount);
return lpAmount;
}
function removeLiquidity(
IStableSwap pool,
IStableSwap basePool,
uint256 _amount,
uint256[] calldata min_amounts_meta,
uint256[] calldata min_amounts_base,
uint256 deadline
) external returns (uint256[] memory amounts, uint256[] memory base_amounts) {
IERC20 token = pool.getLpToken();
IERC20 baseToken = basePool.getLpToken();
token.transferFrom(msg.sender, address(this), _amount);
token.safeIncreaseAllowance(address(pool), _amount);
pool.removeLiquidity(_amount, min_amounts_meta, deadline);
uint256 _base_amount = baseToken.balanceOf(address(this));
baseToken.safeIncreaseAllowance(address(basePool), _base_amount);
basePool.removeLiquidity(_base_amount, min_amounts_base, deadline);
// Transfer all coins out
amounts = new uint256[](pool.getNumberOfTokens());
for (uint8 i = 0; i < pool.getNumberOfTokens(); i++) {
IERC20 coin = pool.getToken(i);
amounts[i] = coin.balanceOf(address(this));
if (amounts[i] > 0) {
coin.safeTransfer(msg.sender, amounts[i]);
}
}
base_amounts = new uint256[](basePool.getNumberOfTokens());
for (uint8 i = 0; i < basePool.getNumberOfTokens(); i++) {
IERC20 coin = basePool.getToken(i);
base_amounts[i] = coin.balanceOf(address(this));
if (base_amounts[i] > 0) {
coin.safeTransfer(msg.sender, base_amounts[i]);
}
}
}
function removeBaseLiquidityOneToken(
IStableSwap pool,
IStableSwap basePool,
uint256 _token_amount,
uint8 i,
uint256 _min_amount,
uint256 deadline
) external returns (uint256) {
IERC20 token = pool.getLpToken();
IERC20 baseToken = basePool.getLpToken();
uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken));
token.transferFrom(msg.sender, address(this), _token_amount);
token.approve(address(pool), _token_amount);
pool.removeLiquidityOneToken(_token_amount, baseTokenIndex, 0, deadline);
uint256 _base_amount = baseToken.balanceOf(address(this));
baseToken.approve(address(basePool), _base_amount);
basePool.removeLiquidityOneToken(_base_amount, i, _min_amount, deadline);
IERC20 coin = basePool.getToken(i);
uint256 coin_amount = coin.balanceOf(address(this));
coin.safeTransfer(msg.sender, coin_amount);
return coin_amount;
}
function swapFromBase(
IStableSwap pool,
IStableSwap basePool,
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx,
uint256 minDy,
uint256 deadline
) external returns (uint256) {
IERC20 baseToken = basePool.getLpToken();
uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken));
uint256[] memory base_amounts = new uint256[](basePool.getNumberOfTokens());
base_amounts[tokenIndexFrom] = dx;
IERC20 coin = basePool.getToken(tokenIndexFrom);
coin.safeTransferFrom(msg.sender, address(this), dx);
coin.safeIncreaseAllowance(address(basePool), dx);
uint256 baseLpAmount = basePool.addLiquidity(base_amounts, 0, deadline);
if (baseTokenIndex != tokenIndexTo) {
baseToken.safeIncreaseAllowance(address(pool), baseLpAmount);
pool.swap(baseTokenIndex, tokenIndexTo, baseLpAmount, minDy, deadline);
}
IERC20 coinTo = pool.getToken(tokenIndexTo);
uint256 amountOut = coinTo.balanceOf(address(this));
coinTo.safeTransfer(msg.sender, amountOut);
return amountOut;
}
function swapToBase(
IStableSwap pool,
IStableSwap basePool,
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx,
uint256 minDy,
uint256 deadline
) external returns (uint256) {
IERC20 baseToken = basePool.getLpToken();
uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken));
IERC20 coin = pool.getToken(tokenIndexFrom);
coin.safeTransferFrom(msg.sender, address(this), dx);
uint256 tokenLPAmount = dx;
if (baseTokenIndex != tokenIndexFrom) {
coin.safeIncreaseAllowance(address(pool), dx);
tokenLPAmount = pool.swap(tokenIndexFrom, baseTokenIndex, dx, 0, deadline);
}
baseToken.safeIncreaseAllowance(address(basePool), tokenLPAmount);
basePool.removeLiquidityOneToken(tokenLPAmount, tokenIndexTo, minDy, deadline);
IERC20 coinTo = basePool.getToken(tokenIndexTo);
uint256 amountOut = coinTo.balanceOf(address(this));
coinTo.safeTransfer(msg.sender, amountOut);
return amountOut;
}
// =========== VIEW ===========
function calculateConvert(
IStableSwap fromPool,
IStableSwap toPool,
uint256 amount
) external view returns (uint256) {
uint256 fromPoolLength = fromPool.getNumberOfTokens();
uint256[] memory amounts = fromPool.calculateRemoveLiquidity(amount);
uint256[] memory meta_amounts = new uint256[](fromPoolLength);
for (uint8 i = 0; i < fromPoolLength; i++) {
IERC20 fromCoin = fromPool.getToken(i);
uint256 toCoinIndex = toPool.getTokenIndex(address(fromCoin));
meta_amounts[toCoinIndex] = amounts[i];
}
return toPool.calculateTokenAmount(meta_amounts, true);
}
function calculateTokenAmount(
IStableSwap pool,
IStableSwap basePool,
uint256[] memory meta_amounts,
uint256[] memory base_amounts,
bool is_deposit
) external view returns (uint256) {
IERC20 baseToken = basePool.getLpToken();
uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken));
uint256 _base_tokens = basePool.calculateTokenAmount(base_amounts, is_deposit);
meta_amounts[baseTokenIndex] = meta_amounts[baseTokenIndex] + _base_tokens;
return pool.calculateTokenAmount(meta_amounts, is_deposit);
}
function calculateRemoveLiquidity(
IStableSwap pool,
IStableSwap basePool,
uint256 amount
) external view returns (uint256[] memory meta_amounts, uint256[] memory base_amounts) {
IERC20 baseToken = basePool.getLpToken();
uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken));
meta_amounts = pool.calculateRemoveLiquidity(amount);
uint256 lpAmount = meta_amounts[baseTokenIndex];
meta_amounts[baseTokenIndex] = 0;
base_amounts = basePool.calculateRemoveLiquidity(lpAmount);
}
function calculateRemoveBaseLiquidityOneToken(
IStableSwap pool,
IStableSwap basePool,
uint256 _token_amount,
uint8 iBase
) external view returns (uint256 availableTokenAmount) {
IERC20 baseToken = basePool.getLpToken();
uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken));
uint256 _base_tokens = pool.calculateRemoveLiquidityOneToken(_token_amount, baseTokenIndex);
availableTokenAmount = basePool.calculateRemoveLiquidityOneToken(_base_tokens, iBase);
}
function calculateSwapFromBase(
IStableSwap pool,
IStableSwap basePool,
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx
) external view returns (uint256) {
IERC20 baseToken = basePool.getLpToken();
uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken));
uint256[] memory base_amounts = new uint256[](basePool.getNumberOfTokens());
base_amounts[tokenIndexFrom] = dx;
uint256 baseLpAmount = basePool.calculateTokenAmount(base_amounts, true);
if (baseTokenIndex == tokenIndexTo) {
return baseLpAmount;
}
return pool.calculateSwap(baseTokenIndex, tokenIndexTo, baseLpAmount);
}
function calculateSwapToBase(
IStableSwap pool,
IStableSwap basePool,
uint8 tokenIndexFrom,
uint8 tokenIndexTo,
uint256 dx
) external view returns (uint256) {
IERC20 baseToken = basePool.getLpToken();
uint8 baseTokenIndex = pool.getTokenIndex(address(baseToken));
uint256 tokenLPAmount = dx;
if (baseTokenIndex != tokenIndexFrom) {
tokenLPAmount = pool.calculateSwap(tokenIndexFrom, baseTokenIndex, dx);
}
return basePool.calculateRemoveLiquidityOneToken(tokenLPAmount, tokenIndexTo);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "../interfaces/IUniswapV2Pair.sol";
contract PriceLens {
uint256 public constant PRECISION = 1e18;
function consultUniswapV2LPToken(
IUniswapV2Pair lpToken,
address token0Route,
address token1Route,
address chainlinkAddress0,
address chainlinkAddress1
) external view returns (uint256) {
address token0 = lpToken.token0();
address token1 = lpToken.token1();
uint256 token0Part = calculatePartOfLP(lpToken, token0, token0Route);
uint256 token1Part = calculatePartOfLP(lpToken, token1, token1Route);
token0Part = getChainlinkPrice(chainlinkAddress0, token0Part);
token1Part = getChainlinkPrice(chainlinkAddress1, token1Part);
uint256 totalSupply = lpToken.totalSupply();
uint256 decimals = lpToken.decimals();
uint256 totalAmount = token0Part + token1Part;
return (totalAmount * 10**decimals) / totalSupply;
}
/**
* calculate token price from series of Uniswap pair and chainlink price feed.
* Once swap route is empty
* @param token address of token to consult
* @param pair swap route to get price
* @param chainlinkAddress chainlink price feed
*/
function consultToken(
address token,
address pair,
address chainlinkAddress
) public view returns (uint256) {
require(pair != address(0) || chainlinkAddress != address(0), "route empty");
uint256 amountOut = consultTokenToToken(token, pair);
if (chainlinkAddress == address(0)) {
return amountOut;
}
return getChainlinkPrice(chainlinkAddress, amountOut);
}
// internal function
function consultTokenToToken(address tokenIn, address pairAddress) internal view returns (uint256) {
address tokenOut = address(0);
if (pairAddress == address(0)) {
return PRECISION;
}
uint256 amountIn = 10**ERC20(tokenIn).decimals();
IUniswapV2Pair pair = IUniswapV2Pair(pairAddress);
(uint112 reserve0, uint112 reserve1, ) = pair.getReserves();
uint256 amountOut;
if (tokenIn == pair.token0()) {
tokenOut = pair.token1();
amountOut = getAmountOut(amountIn, reserve0, reserve1);
} else {
assert(tokenIn == pair.token1());
tokenOut = pair.token0();
amountOut = getAmountOut(amountIn, reserve1, reserve0);
}
uint8 tokenOutDecimals = ERC20(tokenOut).decimals();
return (amountOut * PRECISION) / 10**tokenOutDecimals;
}
// UniswapV2Libarary.getAmountOut
function getAmountOut(
uint256 amountIn,
uint256 reserveIn,
uint256 reserveOut
) internal pure returns (uint256 amountOut) {
require(amountIn > 0, "UniswapV2Library: INSUFFICIENT_INPUT_AMOUNT");
require(reserveIn > 0 && reserveOut > 0, "UniswapV2Library: INSUFFICIENT_LIQUIDITY");
uint256 numerator = amountIn * reserveOut;
uint256 denominator = reserveIn + amountIn;
amountOut = numerator / denominator;
}
function getChainlinkPrice(address _priceFeedAddress, uint256 _amountIn) internal view returns (uint256) {
assert(_priceFeedAddress != address(0));
AggregatorV3Interface _priceFeed = AggregatorV3Interface(_priceFeedAddress);
(, int256 _price, , , ) = _priceFeed.latestRoundData();
uint8 _decimals = _priceFeed.decimals();
return (uint256(_price) * _amountIn) / (10**_decimals);
}
function calculatePartOfLP(
IUniswapV2Pair lpToken,
address underlyingAddress,
address token0Route
) internal view returns (uint256) {
ERC20 underlying = ERC20(underlyingAddress);
uint256 decimals = underlying.decimals();
uint256 balance = underlying.balanceOf(address(lpToken));
uint256 price = consultTokenToToken(address(underlying), token0Route);
return (balance * price) / 10**decimals;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface AggregatorV3Interface {
function decimals()
external
view
returns (
uint8
);
function description()
external
view
returns (
string memory
);
function version()
external
view
returns (
uint256
);
// getRoundData and latestRoundData should both raise "No data present"
// if they do not have data to report, instead of returning unset values
// which could be misinterpreted as actual reported values.
function getRoundData(
uint80 _roundId
)
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
function latestRoundData()
external
view
returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
);
}// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0;
interface IUniswapV2Pair {
event Approval(address indexed owner, address indexed spender, uint256 value);
event Transfer(address indexed from, address indexed to, uint256 value);
function name() external pure returns (string memory);
function symbol() external pure returns (string memory);
function decimals() external pure returns (uint8);
function totalSupply() external view returns (uint256);
function balanceOf(address owner) external view returns (uint256);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 value) external returns (bool);
function transfer(address to, uint256 value) external returns (bool);
function transferFrom(
address from,
address to,
uint256 value
) external returns (bool);
function DOMAIN_SEPARATOR() external view returns (bytes32);
function PERMIT_TYPEHASH() external pure returns (bytes32);
function nonces(address owner) external view returns (uint256);
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
event Mint(address indexed sender, uint256 amount0, uint256 amount1);
event Burn(address indexed sender, uint256 amount0, uint256 amount1, address indexed to);
event Swap(
address indexed sender,
uint256 amount0In,
uint256 amount1In,
uint256 amount0Out,
uint256 amount1Out,
address indexed to
);
event Sync(uint112 reserve0, uint112 reserve1);
function MINIMUM_LIQUIDITY() external pure returns (uint256);
function factory() external view returns (address);
function token0() external view returns (address);
function token1() external view returns (address);
function getReserves()
external
view
returns (
uint112 reserve0,
uint112 reserve1,
uint32 blockTimestampLast
);
function price0CumulativeLast() external view returns (uint256);
function price1CumulativeLast() external view returns (uint256);
function kLast() external view returns (uint256);
function mint(address to) external returns (uint256 liquidity);
function burn(address to) external returns (uint256 amount0, uint256 amount1);
function swap(
uint256 amount0Out,
uint256 amount1Out,
address to,
bytes calldata data
) external;
function skim(address to) external;
function sync() external;
function initialize(address, address) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MockERC20 is ERC20 {
uint8 internal decimals_;
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) ERC20(_name, _symbol) {
decimals_ = _decimals;
}
function mint(uint256 _amount) public {
_mint(msg.sender, _amount);
}
function decimals() public view virtual override returns (uint8) {
return decimals_;
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract TreasuryFund is Ownable {
using SafeERC20 for IERC20;
IERC20 public ONESWAP = IERC20(0x3516a7588C2E6FFA66C9507eF51853eb85d76e5B);
uint256 private constant DURATION = 2 * 365 * 24 * 3600; // 2 years
uint256 private constant START = 1632229200; // Sep 21st 2021 - 01:00PM UTC
uint256 private constant ALLOCATION = 100_000_000 ether;
uint256 private constant ONESWAP_PER_SECOND = ALLOCATION / DURATION;
uint256 public claimed_amount;
function currentBalance() public view returns (uint256) {
return ONESWAP.balanceOf(address(this));
}
function vestedBalance() public view returns (uint256) {
if (block.timestamp <= START) {
return 0;
}
return ONESWAP_PER_SECOND * (block.timestamp - START);
}
function claimable() public view returns (uint256) {
return vestedBalance() - claimed_amount;
}
function transfer(address _receiver, uint256 _amount) public onlyOwner {
require(_receiver != address(0), "Invalid address");
require(_amount > 0, "invalid amount");
require(_amount <= currentBalance(), "> balance");
require(claimed_amount + _amount <= vestedBalance(), "> vestedAmount");
claimed_amount = claimed_amount + _amount;
ONESWAP.safeTransfer(_receiver, _amount);
}
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract LiquidityMiningFund is Ownable {
using SafeERC20 for IERC20;
IERC20 public ONESWAP = IERC20(0x3516a7588C2E6FFA66C9507eF51853eb85d76e5B);
uint256 public claimed_amount;
mapping(address => bool) public pools;
function currentBalance() public view returns (uint256) {
return ONESWAP.balanceOf(address(this));
}
function transfer(address _poolAddress, uint256 _amount) external onlyOwner {
require(_poolAddress != address(0), "Invalid address");
require(_amount > 0, "invalid amount");
require(_amount <= currentBalance(), "> balance");
require(pools[_poolAddress], "Pool was not whitelisted");
claimed_amount = claimed_amount + _amount;
ONESWAP.safeTransfer(_poolAddress, _amount);
emit FundTransfer(_poolAddress, _amount);
}
function addPool(address _poolAddress) external onlyOwner {
require(!pools[_poolAddress], "Pool existed");
pools[_poolAddress] = true;
emit PoolAdded(_poolAddress);
}
function removePool(address _poolAddress) external onlyOwner {
require(pools[_poolAddress], "Pool note existed");
delete pools[_poolAddress];
emit PoolRemoved(_poolAddress);
}
event FundTransfer(address indexed _receiver, uint256 _amount);
event PoolAdded(address indexed _poolAddress);
event PoolRemoved(address indexed _poolAddress);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract EcoSystemFund is Ownable {
using SafeERC20 for IERC20;
IERC20 public ONESWAP = IERC20(0x3516a7588C2E6FFA66C9507eF51853eb85d76e5B);
uint256 public claimed_amount;
function currentBalance() public view returns (uint256) {
return ONESWAP.balanceOf(address(this));
}
function transfer(address _receiver, uint256 _amount) external onlyOwner {
require(_receiver != address(0), "Invalid address");
require(_amount > 0, "invalid amount");
require(_amount <= currentBalance(), "> balance");
claimed_amount = claimed_amount + _amount;
ONESWAP.safeTransfer(_receiver, _amount);
emit FundClaimed(_receiver, _amount);
}
event FundClaimed(address indexed _receiver, uint256 _amount);
}// SPDX-License-Identifier: MIT
pragma solidity 0.8.4;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
contract DevFund is Ownable {
using SafeERC20 for IERC20;
IERC20 public ONESWAP = IERC20(0x3516a7588C2E6FFA66C9507eF51853eb85d76e5B);
uint256 private constant DURATION = 3 * 365 * 24 * 3600; // 3 years
uint256 private constant START = 1637452800; // Nov 21st 2021 - 00:00 UTC
uint256 private constant ALLOCATION = 250_000_000 ether;
uint256 private constant ONESWAP_PER_SECOND = ALLOCATION / DURATION;
uint256 public claimed_amount;
function currentBalance() public view returns (uint256) {
return ONESWAP.balanceOf(address(this));
}
function vestedBalance() public view returns (uint256) {
if (block.timestamp <= START) {
return 0;
}
return ONESWAP_PER_SECOND * (block.timestamp - START);
}
function claimable() public view returns (uint256) {
return vestedBalance() - claimed_amount;
}
function transfer(address _receiver, uint256 _amount) public onlyOwner {
require(_receiver != address(0), "Invalid address");
require(_amount > 0, "invalid amount");
require(_amount <= currentBalance(), "> balance");
require(claimed_amount + _amount <= vestedBalance(), "> vestedAmount");
claimed_amount = claimed_amount + _amount;
ONESWAP.safeTransfer(_receiver, _amount);
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract IERC20","name":"_reward","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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":true,"internalType":"address","name":"to","type":"address"}],"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"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"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"}],"name":"Harvest","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 IERC20","name":"lpToken","type":"address"},{"indexed":true,"internalType":"contract IRewarder","name":"rewarder","type":"address"}],"name":"LogPoolAddition","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"rewardPerSecond","type":"uint256"}],"name":"LogRewardPerSecond","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":"LogSetPool","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lastRewardTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lpSupply","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"accRewardPerShare","type":"uint256"}],"name":"LogUpdatePool","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":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"contract IERC20","name":"_lpToken","type":"address"},{"internalType":"contract IRewarder","name":"_rewarder","type":"address"}],"name":"add","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"deposit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"harvest","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"harvestAllRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"lpToken","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"pids","type":"uint256[]"}],"name":"massUpdatePools","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingReward","outputs":[{"internalType":"uint256","name":"pending","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfo","outputs":[{"internalType":"uint256","name":"accRewardPerShare","type":"uint256"},{"internalType":"uint256","name":"lastRewardTime","type":"uint256"},{"internalType":"uint256","name":"allocPoint","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"poolLength","outputs":[{"internalType":"uint256","name":"pools","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reward","outputs":[{"internalType":"contract IERC20","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardPerSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"rewarder","outputs":[{"internalType":"contract IRewarder","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"contract IRewarder","name":"_rewarder","type":"address"},{"internalType":"bool","name":"overwrite","type":"bool"}],"name":"set","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardPerSecond","type":"uint256"}],"name":"setRewardPerSecond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"totalAllocPoint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"}],"name":"updatePool","outputs":[{"components":[{"internalType":"uint256","name":"accRewardPerShare","type":"uint256"},{"internalType":"uint256","name":"lastRewardTime","type":"uint256"},{"internalType":"uint256","name":"allocPoint","type":"uint256"}],"internalType":"struct OneSwapChef.PoolInfo","name":"pool","type":"tuple"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"address","name":"","type":"address"}],"name":"userInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"int256","name":"rewardDebt","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"pid","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"withdrawAndHarvest","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405260006006553480156200001657600080fd5b5060405162001e4738038062001e478339810160408190526200003991620000ba565b62000044336200006a565b600180546001600160a01b0319166001600160a01b0392909216919091179055620000ea565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b600060208284031215620000cc578081fd5b81516001600160a01b0381168114620000e3578182fd5b9392505050565b611d4d80620000fa6000396000f3fe608060405234801561001057600080fd5b506004361061014d5760003560e01c806378ed5d1f116100c357806398969e821161007c57806398969e8214610303578063ab7de09814610316578063c346253d14610329578063d1abb9071461033c578063f2fde38b1461034f578063fbe6cf6a1461036257600080fd5b806378ed5d1f1461026957806388bba42f1461027c5780638da5cb5b1461028f5780638dbdbe6d146102a05780638f10369a146102b357806393f1a40b146102bc57600080fd5b8063228cb73311610115578063228cb733146101c85780632f940c70146101f357806351eb05a61461020657806357a5b58c1461023b57806366da58151461024e578063715018a61461026157600080fd5b8063081e3eda146101525780630ad58d2f146101695780631526fe271461017e57806317caf6f1146101ac57806318fccc76146101b5575b600080fd5b6002545b6040519081526020015b60405180910390f35b61017c610177366004611a80565b610375565b005b61019161018c3660046119e0565b61052e565b60408051938452602084019290925290820152606001610160565b61015660065481565b61017c6101c3366004611a10565b610561565b6001546101db906001600160a01b031681565b6040516001600160a01b039091168152602001610160565b61017c610201366004611a10565b6106ca565b6102196102143660046119e0565b610815565b6040805182518152602080840151908201529181015190820152606001610160565b61017c610249366004611954565b610a59565b61017c61025c3660046119e0565b610aab565b61017c610b19565b6101db6102773660046119e0565b610b4f565b61017c61028a366004611aad565b610b79565b6000546001600160a01b03166101db565b61017c6102ae366004611a80565b610d18565b61015660075481565b6102ee6102ca366004611a10565b60056020908152600092835260408084209091529082529020805460019091015482565b60408051928352602083019190915201610160565b610156610311366004611a10565b610ec9565b61017c610324366004611a3f565b6110a5565b6101db6103373660046119e0565b61125b565b61017c61034a366004611a80565b61126b565b61017c61035d366004611938565b611488565b61017c610370366004611938565b611523565b600061038084610815565b6000858152600560209081526040808320338452909152902081519192509064e8d4a51000906103b09086611c22565b6103ba9190611c02565b8160010160008282546103cd9190611c41565b90915550508054849082906000906103e6908490611c80565b9250508190555060006004868154811061041057634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316905080156104965781546040516344af0fa760e01b81526001600160a01b038316916344af0fa791610463918a9133918a9160009190600401611b7a565b600060405180830381600087803b15801561047d57600080fd5b505af1158015610491573d6000803e3d6000fd5b505050505b6104d88486600389815481106104bc57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316919061156f565b836001600160a01b031686336001600160a01b03167f8166bf25f8a2b7ed3c85049207da4358d16edbed977d23fa2ee6f0dde3ec21328860405161051e91815260200190565b60405180910390a4505050505050565b6002818154811061053e57600080fd5b600091825260209091206003909102018054600182015460029092015490925083565b600061056c83610815565b6000848152600560209081526040808320338452909152812082518154939450909264e8d4a510009161059e91611c22565b6105a89190611c02565b905060008260010154826105bc9190611c41565b60018401839055905080156105e2576001546105e2906001600160a01b0316868361156f565b60006004878154811061060557634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b03169050801561068a5783546040516344af0fa760e01b81526001600160a01b038316916344af0fa791610657918b9133918c91899190600401611b7a565b600060405180830381600087803b15801561067157600080fd5b505af1158015610685573d6000803e3d6000fd5b505050505b604051828152879033907f71bab65ced2e5750775a0613be067df48ef06cf92a496ebf7663ae06609249549060200160405180910390a350505050505050565b6000828152600560209081526040808320338452909152812080548282556001820183905560048054929391928690811061071557634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b03169050801561079a576040516344af0fa760e01b81526001600160a01b038216906344af0fa790610767908890339089906000908190600401611b7a565b600060405180830381600087803b15801561078157600080fd5b505af1158015610795573d6000803e3d6000fd5b505050505b6107c08483600388815481106104bc57634e487b7160e01b600052603260045260246000fd5b836001600160a01b031685336001600160a01b03167f2cac5e20e1541d836381527a43f651851e302817b71dc8e810284e69210c1c6b8560405161080691815260200190565b60405180910390a45050505050565b61083960405180606001604052806000815260200160008152602001600081525090565b6002828154811061085a57634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051606081018252600390930290910180548352600181015493830184905260020154908201529150421115610a54576000600383815481106108ba57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b15801561090657600080fd5b505afa15801561091a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093e91906119f8565b905080156109b75760008260200151426109589190611c80565b905060006006548460400151600754846109729190611c22565b61097c9190611c22565b6109869190611c02565b90508261099864e8d4a5100083611c22565b6109a29190611c02565b845185906109b1908390611bea565b90525050505b42602083015260028054839190859081106109e257634e487b7160e01b600052603260045260246000fd5b600091825260209182902083516003929092020190815582820151600182015560409283015160029091015583810151845183519182529181018490529182015283907fcb7325664a4a3b7c7223eefc492a97ca4fdf94d46884621e5a8fae5a04b2b9d29060600160405180910390a2505b919050565b8060005b81811015610aa557610a94848483818110610a8857634e487b7160e01b600052603260045260246000fd5b90506020020135610815565b50610a9e81611cc3565b9050610a5d565b50505050565b6000546001600160a01b03163314610ade5760405162461bcd60e51b8152600401610ad590611b45565b60405180910390fd5b60078190556040518181527fde89cb17ac7f58f94792b3e91e086ed85403819c24ceea882491f960ccb1a2789060200160405180910390a150565b6000546001600160a01b03163314610b435760405162461bcd60e51b8152600401610ad590611b45565b610b4d60006115d2565b565b60038181548110610b5f57600080fd5b6000918252602090912001546001600160a01b0316905081565b6000546001600160a01b03163314610ba35760405162461bcd60e51b8152600401610ad590611b45565b8260028581548110610bc557634e487b7160e01b600052603260045260246000fd5b906000526020600020906003020160020154600654610be49190611c80565b610bee9190611bea565b6006819055508260028581548110610c1657634e487b7160e01b600052603260045260246000fd5b9060005260206000209060030201600201819055508015610c82578160048581548110610c5357634e487b7160e01b600052603260045260246000fd5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b80610cc25760048481548110610ca857634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316610cc4565b815b6001600160a01b0316847f95895a6ab1df54420d241b55243258a33e61b2194db66c1179ec521aae8e18658584604051610d0a9291909182521515602082015260400190565b60405180910390a350505050565b6000610d2384610815565b60008581526005602090815260408083206001600160a01b0387168452909152812080549293509185918391610d5a908490611bea565b9091555050815164e8d4a5100090610d729086611c22565b610d7c9190611c02565b816001016000828254610d8f9190611ba9565b92505081905550600060048681548110610db957634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031690508015610e3f5781546040516344af0fa760e01b81526001600160a01b038316916344af0fa791610e0c918a918991829160009190600401611b7a565b600060405180830381600087803b158015610e2657600080fd5b505af1158015610e3a573d6000803e3d6000fd5b505050505b610e8333308760038a81548110610e6657634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316929190611622565b836001600160a01b031686336001600160a01b03167f02d7e648dd130fc184d383e55bb126ac4c9c60e8f94bf05acdf557ba2d540b478860405161051e91815260200190565b60008060028481548110610eed57634e487b7160e01b600052603260045260246000fd5b60009182526020808320604080516060810182526003948502909201805483526001810154838501526002015482820152888552600583528085206001600160a01b03891686529092529083208151835492955090939092909188908110610f6557634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015610fb157600080fd5b505afa158015610fc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe991906119f8565b9050836020015142118015610ffd57508015155b1561106d5760008460200151426110149190611c80565b9050600060065486604001516007548461102e9190611c22565b6110389190611c22565b6110429190611c02565b90508261105464e8d4a5100083611c22565b61105e9190611c02565b6110689085611bea565b935050505b6001830154835464e8d4a5100090611086908590611c22565b6110909190611c02565b61109a9190611c41565b979650505050505050565b6000546001600160a01b031633146110cf5760405162461bcd60e51b8152600401610ad590611b45565b6110d88261165a565b82600660008282546110ea9190611bea565b909155505060038054600181810183557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b90910180546001600160a01b038087166001600160a01b03199283168117909355600480548086019091557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01805491871691909216811790915560408051606081018252600080825242602083019081529282018a8152600280548089018255925291519087027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace81019190915591517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf830155517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad0909101559254909161122391611c80565b6040518681527f81ee0f8c5c46e2cb41984886f77a84181724abb86c32a5f6de539b07509d45e59060200160405180910390a4505050565b60048181548110610b5f57600080fd5b600061127684610815565b6000858152600560209081526040808320338452909152812082518154939450909264e8d4a51000916112a891611c22565b6112b29190611c02565b905060008260010154826112c69190611c41565b845190915064e8d4a51000906112dc9088611c22565b6112e69190611c02565b6112f09083611c41565b6001840155825486908490600090611309908490611c80565b9091555050801561132b5760015461132b906001600160a01b0316868361156f565b60006004888154811061134e57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316905080156113d35783546040516344af0fa760e01b81526001600160a01b038316916344af0fa7916113a0918c9133918c91899190600401611b7a565b600060405180830381600087803b1580156113ba57600080fd5b505af11580156113ce573d6000803e3d6000fd5b505050505b6113f9868860038b815481106104bc57634e487b7160e01b600052603260045260246000fd5b856001600160a01b031688336001600160a01b03167f8166bf25f8a2b7ed3c85049207da4358d16edbed977d23fa2ee6f0dde3ec21328a60405161143f91815260200190565b60405180910390a4604051828152889033907f71bab65ced2e5750775a0613be067df48ef06cf92a496ebf7663ae06609249549060200160405180910390a35050505050505050565b6000546001600160a01b031633146114b25760405162461bcd60e51b8152600401610ad590611b45565b6001600160a01b0381166115175760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ad5565b611520816115d2565b50565b60025460005b8181101561156a5760008181526005602090815260408083203384529091529020541561155a5761155a8184610561565b61156381611cc3565b9050611529565b505050565b6040516001600160a01b03831660248201526044810182905261156a90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526116fc565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b0380851660248301528316604482015260648101829052610aa59085906323b872dd60e01b9060840161159b565b60025460005b8181101561156a57826001600160a01b03166003828154811061169357634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031614156116ec5760405162461bcd60e51b81526020600482015260136024820152726164643a206578697374696e6720706f6f6c3f60681b6044820152606401610ad5565b6116f581611cc3565b9050611660565b6000611751826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166117ce9092919063ffffffff16565b80519091501561156a578080602001905181019061176f91906119c4565b61156a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610ad5565b60606117dd84846000856117e7565b90505b9392505050565b6060824710156118485760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610ad5565b843b6118965760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ad5565b600080866001600160a01b031685876040516118b29190611af6565b60006040518083038185875af1925050503d80600081146118ef576040519150601f19603f3d011682016040523d82523d6000602084013e6118f4565b606091505b509150915061109a8282866060831561190e5750816117e0565b82511561191e5782518084602001fd5b8160405162461bcd60e51b8152600401610ad59190611b12565b600060208284031215611949578081fd5b81356117e081611cf4565b60008060208385031215611966578081fd5b823567ffffffffffffffff8082111561197d578283fd5b818501915085601f830112611990578283fd5b81358181111561199e578384fd5b8660208260051b85010111156119b2578384fd5b60209290920196919550909350505050565b6000602082840312156119d5578081fd5b81516117e081611d09565b6000602082840312156119f1578081fd5b5035919050565b600060208284031215611a09578081fd5b5051919050565b60008060408385031215611a22578182fd5b823591506020830135611a3481611cf4565b809150509250929050565b600080600060608486031215611a53578081fd5b833592506020840135611a6581611cf4565b91506040840135611a7581611cf4565b809150509250925092565b600080600060608486031215611a94578283fd5b83359250602084013591506040840135611a7581611cf4565b60008060008060808587031215611ac2578081fd5b84359350602085013592506040850135611adb81611cf4565b91506060850135611aeb81611d09565b939692955090935050565b60008251611b08818460208701611c97565b9190910192915050565b6020815260008251806020840152611b31816040850160208701611c97565b601f01601f19169190910160400192915050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b9485526001600160a01b0393841660208601529190921660408401526060830191909152608082015260a00190565b600080821280156001600160ff1b0384900385131615611bcb57611bcb611cde565b600160ff1b8390038412811615611be457611be4611cde565b50500190565b60008219821115611bfd57611bfd611cde565b500190565b600082611c1d57634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615611c3c57611c3c611cde565b500290565b60008083128015600160ff1b850184121615611c5f57611c5f611cde565b6001600160ff1b0384018313811615611c7a57611c7a611cde565b50500390565b600082821015611c9257611c92611cde565b500390565b60005b83811015611cb2578181015183820152602001611c9a565b83811115610aa55750506000910152565b6000600019821415611cd757611cd7611cde565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461152057600080fd5b801515811461152057600080fdfea2646970667358221220935d5b74a860337ab2a72faac19e67bc5c75538cb605769496847b16cdfe9ddf64736f6c634300080400330000000000000000000000003516a7588c2e6ffa66c9507ef51853eb85d76e5b
Deployed Bytecode
0x608060405234801561001057600080fd5b506004361061014d5760003560e01c806378ed5d1f116100c357806398969e821161007c57806398969e8214610303578063ab7de09814610316578063c346253d14610329578063d1abb9071461033c578063f2fde38b1461034f578063fbe6cf6a1461036257600080fd5b806378ed5d1f1461026957806388bba42f1461027c5780638da5cb5b1461028f5780638dbdbe6d146102a05780638f10369a146102b357806393f1a40b146102bc57600080fd5b8063228cb73311610115578063228cb733146101c85780632f940c70146101f357806351eb05a61461020657806357a5b58c1461023b57806366da58151461024e578063715018a61461026157600080fd5b8063081e3eda146101525780630ad58d2f146101695780631526fe271461017e57806317caf6f1146101ac57806318fccc76146101b5575b600080fd5b6002545b6040519081526020015b60405180910390f35b61017c610177366004611a80565b610375565b005b61019161018c3660046119e0565b61052e565b60408051938452602084019290925290820152606001610160565b61015660065481565b61017c6101c3366004611a10565b610561565b6001546101db906001600160a01b031681565b6040516001600160a01b039091168152602001610160565b61017c610201366004611a10565b6106ca565b6102196102143660046119e0565b610815565b6040805182518152602080840151908201529181015190820152606001610160565b61017c610249366004611954565b610a59565b61017c61025c3660046119e0565b610aab565b61017c610b19565b6101db6102773660046119e0565b610b4f565b61017c61028a366004611aad565b610b79565b6000546001600160a01b03166101db565b61017c6102ae366004611a80565b610d18565b61015660075481565b6102ee6102ca366004611a10565b60056020908152600092835260408084209091529082529020805460019091015482565b60408051928352602083019190915201610160565b610156610311366004611a10565b610ec9565b61017c610324366004611a3f565b6110a5565b6101db6103373660046119e0565b61125b565b61017c61034a366004611a80565b61126b565b61017c61035d366004611938565b611488565b61017c610370366004611938565b611523565b600061038084610815565b6000858152600560209081526040808320338452909152902081519192509064e8d4a51000906103b09086611c22565b6103ba9190611c02565b8160010160008282546103cd9190611c41565b90915550508054849082906000906103e6908490611c80565b9250508190555060006004868154811061041057634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316905080156104965781546040516344af0fa760e01b81526001600160a01b038316916344af0fa791610463918a9133918a9160009190600401611b7a565b600060405180830381600087803b15801561047d57600080fd5b505af1158015610491573d6000803e3d6000fd5b505050505b6104d88486600389815481106104bc57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316919061156f565b836001600160a01b031686336001600160a01b03167f8166bf25f8a2b7ed3c85049207da4358d16edbed977d23fa2ee6f0dde3ec21328860405161051e91815260200190565b60405180910390a4505050505050565b6002818154811061053e57600080fd5b600091825260209091206003909102018054600182015460029092015490925083565b600061056c83610815565b6000848152600560209081526040808320338452909152812082518154939450909264e8d4a510009161059e91611c22565b6105a89190611c02565b905060008260010154826105bc9190611c41565b60018401839055905080156105e2576001546105e2906001600160a01b0316868361156f565b60006004878154811061060557634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b03169050801561068a5783546040516344af0fa760e01b81526001600160a01b038316916344af0fa791610657918b9133918c91899190600401611b7a565b600060405180830381600087803b15801561067157600080fd5b505af1158015610685573d6000803e3d6000fd5b505050505b604051828152879033907f71bab65ced2e5750775a0613be067df48ef06cf92a496ebf7663ae06609249549060200160405180910390a350505050505050565b6000828152600560209081526040808320338452909152812080548282556001820183905560048054929391928690811061071557634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b03169050801561079a576040516344af0fa760e01b81526001600160a01b038216906344af0fa790610767908890339089906000908190600401611b7a565b600060405180830381600087803b15801561078157600080fd5b505af1158015610795573d6000803e3d6000fd5b505050505b6107c08483600388815481106104bc57634e487b7160e01b600052603260045260246000fd5b836001600160a01b031685336001600160a01b03167f2cac5e20e1541d836381527a43f651851e302817b71dc8e810284e69210c1c6b8560405161080691815260200190565b60405180910390a45050505050565b61083960405180606001604052806000815260200160008152602001600081525090565b6002828154811061085a57634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051606081018252600390930290910180548352600181015493830184905260020154908201529150421115610a54576000600383815481106108ba57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b15801561090657600080fd5b505afa15801561091a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061093e91906119f8565b905080156109b75760008260200151426109589190611c80565b905060006006548460400151600754846109729190611c22565b61097c9190611c22565b6109869190611c02565b90508261099864e8d4a5100083611c22565b6109a29190611c02565b845185906109b1908390611bea565b90525050505b42602083015260028054839190859081106109e257634e487b7160e01b600052603260045260246000fd5b600091825260209182902083516003929092020190815582820151600182015560409283015160029091015583810151845183519182529181018490529182015283907fcb7325664a4a3b7c7223eefc492a97ca4fdf94d46884621e5a8fae5a04b2b9d29060600160405180910390a2505b919050565b8060005b81811015610aa557610a94848483818110610a8857634e487b7160e01b600052603260045260246000fd5b90506020020135610815565b50610a9e81611cc3565b9050610a5d565b50505050565b6000546001600160a01b03163314610ade5760405162461bcd60e51b8152600401610ad590611b45565b60405180910390fd5b60078190556040518181527fde89cb17ac7f58f94792b3e91e086ed85403819c24ceea882491f960ccb1a2789060200160405180910390a150565b6000546001600160a01b03163314610b435760405162461bcd60e51b8152600401610ad590611b45565b610b4d60006115d2565b565b60038181548110610b5f57600080fd5b6000918252602090912001546001600160a01b0316905081565b6000546001600160a01b03163314610ba35760405162461bcd60e51b8152600401610ad590611b45565b8260028581548110610bc557634e487b7160e01b600052603260045260246000fd5b906000526020600020906003020160020154600654610be49190611c80565b610bee9190611bea565b6006819055508260028581548110610c1657634e487b7160e01b600052603260045260246000fd5b9060005260206000209060030201600201819055508015610c82578160048581548110610c5357634e487b7160e01b600052603260045260246000fd5b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505b80610cc25760048481548110610ca857634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316610cc4565b815b6001600160a01b0316847f95895a6ab1df54420d241b55243258a33e61b2194db66c1179ec521aae8e18658584604051610d0a9291909182521515602082015260400190565b60405180910390a350505050565b6000610d2384610815565b60008581526005602090815260408083206001600160a01b0387168452909152812080549293509185918391610d5a908490611bea565b9091555050815164e8d4a5100090610d729086611c22565b610d7c9190611c02565b816001016000828254610d8f9190611ba9565b92505081905550600060048681548110610db957634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031690508015610e3f5781546040516344af0fa760e01b81526001600160a01b038316916344af0fa791610e0c918a918991829160009190600401611b7a565b600060405180830381600087803b158015610e2657600080fd5b505af1158015610e3a573d6000803e3d6000fd5b505050505b610e8333308760038a81548110610e6657634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316929190611622565b836001600160a01b031686336001600160a01b03167f02d7e648dd130fc184d383e55bb126ac4c9c60e8f94bf05acdf557ba2d540b478860405161051e91815260200190565b60008060028481548110610eed57634e487b7160e01b600052603260045260246000fd5b60009182526020808320604080516060810182526003948502909201805483526001810154838501526002015482820152888552600583528085206001600160a01b03891686529092529083208151835492955090939092909188908110610f6557634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546040516370a0823160e01b81523060048201526001600160a01b03909116906370a082319060240160206040518083038186803b158015610fb157600080fd5b505afa158015610fc5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610fe991906119f8565b9050836020015142118015610ffd57508015155b1561106d5760008460200151426110149190611c80565b9050600060065486604001516007548461102e9190611c22565b6110389190611c22565b6110429190611c02565b90508261105464e8d4a5100083611c22565b61105e9190611c02565b6110689085611bea565b935050505b6001830154835464e8d4a5100090611086908590611c22565b6110909190611c02565b61109a9190611c41565b979650505050505050565b6000546001600160a01b031633146110cf5760405162461bcd60e51b8152600401610ad590611b45565b6110d88261165a565b82600660008282546110ea9190611bea565b909155505060038054600181810183557fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b90910180546001600160a01b038087166001600160a01b03199283168117909355600480548086019091557f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b01805491871691909216811790915560408051606081018252600080825242602083019081529282018a8152600280548089018255925291519087027f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace81019190915591517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acf830155517f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ad0909101559254909161122391611c80565b6040518681527f81ee0f8c5c46e2cb41984886f77a84181724abb86c32a5f6de539b07509d45e59060200160405180910390a4505050565b60048181548110610b5f57600080fd5b600061127684610815565b6000858152600560209081526040808320338452909152812082518154939450909264e8d4a51000916112a891611c22565b6112b29190611c02565b905060008260010154826112c69190611c41565b845190915064e8d4a51000906112dc9088611c22565b6112e69190611c02565b6112f09083611c41565b6001840155825486908490600090611309908490611c80565b9091555050801561132b5760015461132b906001600160a01b0316868361156f565b60006004888154811061134e57634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b0316905080156113d35783546040516344af0fa760e01b81526001600160a01b038316916344af0fa7916113a0918c9133918c91899190600401611b7a565b600060405180830381600087803b1580156113ba57600080fd5b505af11580156113ce573d6000803e3d6000fd5b505050505b6113f9868860038b815481106104bc57634e487b7160e01b600052603260045260246000fd5b856001600160a01b031688336001600160a01b03167f8166bf25f8a2b7ed3c85049207da4358d16edbed977d23fa2ee6f0dde3ec21328a60405161143f91815260200190565b60405180910390a4604051828152889033907f71bab65ced2e5750775a0613be067df48ef06cf92a496ebf7663ae06609249549060200160405180910390a35050505050505050565b6000546001600160a01b031633146114b25760405162461bcd60e51b8152600401610ad590611b45565b6001600160a01b0381166115175760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608401610ad5565b611520816115d2565b50565b60025460005b8181101561156a5760008181526005602090815260408083203384529091529020541561155a5761155a8184610561565b61156381611cc3565b9050611529565b505050565b6040516001600160a01b03831660248201526044810182905261156a90849063a9059cbb60e01b906064015b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b0319909316929092179091526116fc565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6040516001600160a01b0380851660248301528316604482015260648101829052610aa59085906323b872dd60e01b9060840161159b565b60025460005b8181101561156a57826001600160a01b03166003828154811061169357634e487b7160e01b600052603260045260246000fd5b6000918252602090912001546001600160a01b031614156116ec5760405162461bcd60e51b81526020600482015260136024820152726164643a206578697374696e6720706f6f6c3f60681b6044820152606401610ad5565b6116f581611cc3565b9050611660565b6000611751826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166117ce9092919063ffffffff16565b80519091501561156a578080602001905181019061176f91906119c4565b61156a5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401610ad5565b60606117dd84846000856117e7565b90505b9392505050565b6060824710156118485760405162461bcd60e51b815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f6044820152651c8818d85b1b60d21b6064820152608401610ad5565b843b6118965760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610ad5565b600080866001600160a01b031685876040516118b29190611af6565b60006040518083038185875af1925050503d80600081146118ef576040519150601f19603f3d011682016040523d82523d6000602084013e6118f4565b606091505b509150915061109a8282866060831561190e5750816117e0565b82511561191e5782518084602001fd5b8160405162461bcd60e51b8152600401610ad59190611b12565b600060208284031215611949578081fd5b81356117e081611cf4565b60008060208385031215611966578081fd5b823567ffffffffffffffff8082111561197d578283fd5b818501915085601f830112611990578283fd5b81358181111561199e578384fd5b8660208260051b85010111156119b2578384fd5b60209290920196919550909350505050565b6000602082840312156119d5578081fd5b81516117e081611d09565b6000602082840312156119f1578081fd5b5035919050565b600060208284031215611a09578081fd5b5051919050565b60008060408385031215611a22578182fd5b823591506020830135611a3481611cf4565b809150509250929050565b600080600060608486031215611a53578081fd5b833592506020840135611a6581611cf4565b91506040840135611a7581611cf4565b809150509250925092565b600080600060608486031215611a94578283fd5b83359250602084013591506040840135611a7581611cf4565b60008060008060808587031215611ac2578081fd5b84359350602085013592506040850135611adb81611cf4565b91506060850135611aeb81611d09565b939692955090935050565b60008251611b08818460208701611c97565b9190910192915050565b6020815260008251806020840152611b31816040850160208701611c97565b601f01601f19169190910160400192915050565b6020808252818101527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604082015260600190565b9485526001600160a01b0393841660208601529190921660408401526060830191909152608082015260a00190565b600080821280156001600160ff1b0384900385131615611bcb57611bcb611cde565b600160ff1b8390038412811615611be457611be4611cde565b50500190565b60008219821115611bfd57611bfd611cde565b500190565b600082611c1d57634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615611c3c57611c3c611cde565b500290565b60008083128015600160ff1b850184121615611c5f57611c5f611cde565b6001600160ff1b0384018313811615611c7a57611c7a611cde565b50500390565b600082821015611c9257611c92611cde565b500390565b60005b83811015611cb2578181015183820152602001611c9a565b83811115610aa55750506000910152565b6000600019821415611cd757611cd7611cde565b5060010190565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461152057600080fd5b801515811461152057600080fdfea2646970667358221220935d5b74a860337ab2a72faac19e67bc5c75538cb605769496847b16cdfe9ddf64736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000003516a7588c2e6ffa66c9507ef51853eb85d76e5b
-----Decoded View---------------
Arg [0] : _reward (address): 0x3516a7588C2E6FFA66C9507eF51853eb85d76e5B
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000003516a7588c2e6ffa66c9507ef51853eb85d76e5b
Deployed Bytecode Sourcemap
345:11927:13:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1465:100;1542:8;:15;1465:100;;;8170:25:31;;;8158:2;8143:18;1465:100:13;;;;;;;;5002:673;;;;;;:::i;:::-;;:::i;:::-;;704:26;;;;;;:::i;:::-;;:::i;:::-;;;;10518:25:31;;;10574:2;10559:18;;10552:34;;;;10602:18;;;10595:34;10506:2;10491:18;704:26:13;10473:162:31;1150:34:13;;;;;;5848:798;;;;;;:::i;:::-;;:::i;634:20::-;;;;;-1:-1:-1;;;;;634:20:13;;;;;;-1:-1:-1;;;;;3826:32:31;;;3808:51;;3796:2;3781:18;634:20:13;3763:102:31;8168:570:13;;;;;;:::i;:::-;;:::i;2748:740::-;;;;;;:::i;:::-;;:::i;:::-;;;;7873:13:31;;7855:32;;7943:4;7931:17;;;7925:24;7903:20;;;7896:54;7994:17;;;7988:24;7966:20;;;7959:54;7843:2;7828:18;2748:740:13;7810:209:31;3670:193:13;;;;;;:::i;:::-;;:::i;11246:176::-;;;;;;:::i;:::-;;:::i;1605:92:1:-;;;:::i;798:23:13:-;;;;;;:::i;:::-;;:::i;10595:463::-;;;;;;:::i;:::-;;:::i;973:85:1:-;1019:7;1045:6;-1:-1:-1;;;;;1045:6:1;973:85;;4108:682:13;;;;;;:::i;:::-;;:::i;1193:30::-;;;;;;985:64;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10237:25:31;;;10293:2;10278:18;;10271:34;;;;10210:18;985:64:13;10192:119:31;1788:776:13;;;;;;:::i;:::-;;:::i;9720:480::-;;;;;;:::i;:::-;;:::i;891:27::-;;;;;;:::i;:::-;;:::i;6922:1061::-;;;;;;:::i;:::-;;:::i;1846:189:1:-;;;;;;:::i;:::-;;:::i;8746:271:13:-;;;;;;:::i;:::-;;:::i;5002:673::-;5113:20;5136:15;5147:3;5136:10;:15::i;:::-;5162:21;5186:13;;;:8;:13;;;;;;;;5200:10;5186:25;;;;;;;5280:22;;5113:38;;-1:-1:-1;5186:25:13;1278:4;;5271:31;;:6;:31;:::i;:::-;5270:56;;;;:::i;:::-;5244:4;:15;;;:83;;;;;;;:::i;:::-;;;;-1:-1:-1;;5338:21:13;;5353:6;;5338:4;;:11;;:21;;5353:6;;5338:21;:::i;:::-;;;;;;;;5397:19;5419:8;5428:3;5419:13;;;;;;-1:-1:-1;;;5419:13:13;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;5419:13:13;;-1:-1:-1;5447:32:13;;5443:120;;5539:11;;5496:55;;-1:-1:-1;;;5496:55:13;;-1:-1:-1;;;;;5496:18:13;;;;;:55;;5515:3;;5520:10;;5532:2;;5536:1;;5539:11;5496:55;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5443:120;5575:37;5601:2;5605:6;5575:7;5583:3;5575:12;;;;;;-1:-1:-1;;;5575:12:13;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;5575:12:13;;:37;:25;:37::i;:::-;5664:2;-1:-1:-1;;;;;5630:37:13;5651:3;5639:10;-1:-1:-1;;;;;5630:37:13;;5656:6;5630:37;;;;8170:25:31;;8158:2;8143:18;;8125:76;5630:37:13;;;;;;;;5002:673;;;;;;:::o;704:26::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;704:26:13;:::o;5848:798::-;5908:20;5931:15;5942:3;5931:10;:15::i;:::-;5957:21;5981:13;;;:8;:13;;;;;;;;5995:10;5981:25;;;;;;;6066:22;;6052:11;;5908:38;;-1:-1:-1;5981:25:13;;1278:4;;6052:36;;;:::i;:::-;6051:61;;;;:::i;:::-;6017:96;;6124:22;6177:4;:15;;;6157:17;:35;;;;:::i;:::-;6226:15;;;:35;;;6124:69;-1:-1:-1;6303:19:13;;6299:91;;6339:6;;:39;;-1:-1:-1;;;;;6339:6:13;6359:2;6363:14;6339:19;:39::i;:::-;6402:19;6424:8;6433:3;6424:13;;;;;;-1:-1:-1;;;6424:13:13;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;6424:13:13;;-1:-1:-1;6452:32:13;;6448:133;;6557:11;;6501:68;;-1:-1:-1;;;6501:68:13;;-1:-1:-1;;;;;6501:18:13;;;;;:68;;6520:3;;6525:10;;6537:2;;6541:14;;6557:11;6501:68;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6448:133;6598:40;;8170:25:31;;;6618:3:13;;6606:10;;6598:40;;8158:2:31;8143:18;6598:40:13;;;;;;;5848:798;;;;;;;:::o;8168:570::-;8238:21;8262:13;;;:8;:13;;;;;;;;8276:10;8262:25;;;;;;;8315:11;;8337:15;;;-1:-1:-1;8363:15:13;;:19;;;8417:8;:13;;8262:25;;8315:11;;8271:3;;8417:13;;;;-1:-1:-1;;;8417:13:13;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;8417:13:13;;-1:-1:-1;8445:32:13;;8441:110;;8494:45;;-1:-1:-1;;;8494:45:13;;-1:-1:-1;;;;;8494:18:13;;;;;:45;;8513:3;;8518:10;;8530:2;;8534:1;;;;8494:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8441:110;8631:37;8657:2;8661:6;8631:7;8639:3;8631:12;;;;;;-1:-1:-1;;;8631:12:13;;;;;;;;:37;8727:2;-1:-1:-1;;;;;8684:46:13;8714:3;8702:10;-1:-1:-1;;;;;8684:46:13;;8719:6;8684:46;;;;8170:25:31;;8158:2;8143:18;;8125:76;8684:46:13;;;;;;;;8168:570;;;;;:::o;2748:740::-;2797:20;-1:-1:-1;;;;;;;;;;;;;;;;;;;;;;;;2797:20:13;2837:8;2846:3;2837:13;;;;;;-1:-1:-1;;;2837:13:13;;;;;;;;;;;;;;;;;;2830:20;;;;;;;;2837:13;;;;;;;2830:20;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2865:15:13;:37;2861:620;;;2919:16;2938:7;2946:3;2938:12;;;;;;-1:-1:-1;;;2938:12:13;;;;;;;;;;;;;;;;;;;:37;;-1:-1:-1;;;2938:37:13;;2969:4;2938:37;;;3808:51:31;-1:-1:-1;;;;;2938:12:13;;;;:22;;3781:18:31;;2938:37:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2919:56;-1:-1:-1;2994:12:13;;2990:300;;3027:12;3060:4;:19;;;3042:15;:37;;;;:::i;:::-;3027:52;;3098:20;3166:15;;3147:4;:15;;;3129;;3122:4;:22;;;;:::i;:::-;:40;;;;:::i;:::-;3121:60;;;;:::i;:::-;3098:83;-1:-1:-1;3266:8:13;3227:35;1278:4;3098:83;3227:35;:::i;:::-;3226:48;;;;:::i;:::-;3200:74;;:4;;:74;;;;;:::i;:::-;;;-1:-1:-1;;;2990:300:13;3326:15;3304:19;;;:37;3356:8;:13;;3304:4;;3356:8;3365:3;;3356:13;;;;-1:-1:-1;;;3356:13:13;;;;;;;;;;;;;;;;;;:20;;:13;;;;;;:20;;;;;;;;;;;;;;;;;;;;;3415:19;;;;3446:22;;3396:73;;10518:25:31;;;10559:18;;;10552:34;;;10602:18;;;10595:34;3410:3:13;;3396:73;;10506:2:31;10491:18;3396:73:13;;;;;;;2861:620;;2748:740;;;:::o;3670:193::-;3754:4;3740:11;3776:80;3800:3;3796:1;:7;3776:80;;;3825:19;3836:4;;3841:1;3836:7;;;;;-1:-1:-1;;;3836:7:13;;;;;;;;;;;;;;;3825:10;:19::i;:::-;-1:-1:-1;3805:3:13;;;:::i;:::-;;;3776:80;;;;3670:193;;;:::o;11246:176::-;1019:7:1;1045:6;-1:-1:-1;;;;;1045:6:1;666:10:11;1185:23:1;1177:68;;;;-1:-1:-1;;;1177:68:1;;;;;;;:::i;:::-;;;;;;;;;11328:15:13::1;:34:::0;;;11378:36:::1;::::0;8170:25:31;;;11378:36:13::1;::::0;8158:2:31;8143:18;11378:36:13::1;;;;;;;11246:176:::0;:::o;1605:92:1:-;1019:7;1045:6;-1:-1:-1;;;;;1045:6:1;666:10:11;1185:23:1;1177:68;;;;-1:-1:-1;;;1177:68:1;;;;;;;:::i;:::-;1669:21:::1;1687:1;1669:9;:21::i;:::-;1605:92::o:0;798:23:13:-;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;798:23:13;;-1:-1:-1;798:23:13;:::o;10595:463::-;1019:7:1;1045:6;-1:-1:-1;;;;;1045:6:1;666:10:11;1185:23:1;1177:68;;;;-1:-1:-1;;;1177:68:1;;;;;;;:::i;:::-;10815:11:13::1;10787:8;10796:4;10787:14;;;;;;-1:-1:-1::0;;;10787:14:13::1;;;;;;;;;;;;;;;;;;;:25;;;10769:15;;:43;;;;:::i;:::-;:57;;;;:::i;:::-;10751:15;:75;;;;10865:11;10837:8;10846:4;10837:14;;;;;;-1:-1:-1::0;;;10837:14:13::1;;;;;;;;;;;;;;;;;;;:25;;:39;;;;10891:9;10887:68;;;10934:9;10917:8;10926:4;10917:14;;;;;;-1:-1:-1::0;;;10917:14:13::1;;;;;;;;;;;;;;;;;:26;;;;;-1:-1:-1::0;;;;;10917:26:13::1;;;;;-1:-1:-1::0;;;;;10917:26:13::1;;;;;;10887:68;11000:9;:38;;11024:8;11033:4;11024:14;;;;;;-1:-1:-1::0;;;11024:14:13::1;;;;;;;;;;::::0;;;::::1;::::0;;;::::1;::::0;-1:-1:-1;;;;;11024:14:13::1;11000:38;;;11012:9;11000:38;-1:-1:-1::0;;;;;10970:80:13::1;10981:4;10970:80;10987:11;11040:9;10970:80;;;;;;9970:25:31::0;;;10038:14;10031:22;10026:2;10011:18;;10004:50;9958:2;9943:18;;9925:135;10970:80:13::1;;;;;;;;10595:463:::0;;;;:::o;4108:682::-;4218:20;4241:15;4252:3;4241:10;:15::i;:::-;4267:21;4291:13;;;:8;:13;;;;;;;;-1:-1:-1;;;;;4291:17:13;;;;;;;;;4341:21;;4218:38;;-1:-1:-1;4291:17:13;4356:6;;4291:17;;4341:21;;4356:6;;4341:21;:::i;:::-;;;;-1:-1:-1;;4409:22:13;;1278:4;;4400:31;;:6;:31;:::i;:::-;4399:56;;;;:::i;:::-;4373:4;:15;;;:83;;;;;;;:::i;:::-;;;;;;;;4494:19;4516:8;4525:3;4516:13;;;;;;-1:-1:-1;;;4516:13:13;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4516:13:13;;-1:-1:-1;4544:32:13;;4540:112;;4628:11;;4593:47;;-1:-1:-1;;;4593:47:13;;-1:-1:-1;;;;;4593:18:13;;;;;:47;;4612:3;;4617:2;;;;4625:1;;4628:11;4593:47;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4540:112;4664:64;4694:10;4714:4;4721:6;4664:7;4672:3;4664:12;;;;;;-1:-1:-1;;;4664:12:13;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;4664:12:13;;:64;;:29;:64::i;:::-;4779:2;-1:-1:-1;;;;;4746:36:13;4766:3;4754:10;-1:-1:-1;;;;;4746:36:13;;4771:6;4746:36;;;;8170:25:31;;8158:2;8143:18;;8125:76;1788:776:13;1863:15;1891:20;1914:8;1923:4;1914:14;;;;;;-1:-1:-1;;;1914:14:13;;;;;;;;;;;;;;;;;1891:37;;;;;;;;1914:14;;;;;;;1891:37;;;;;;;;;;;;;;;;;;;1963:14;;;:8;:14;;;;;-1:-1:-1;;;;;1963:21:13;;;;;;;;;;2023:22;;2075:13;;1891:37;;-1:-1:-1;1963:21:13;;2023:22;;1914:14;;1972:4;;2075:13;;;;-1:-1:-1;;;2075:13:13;;;;;;;;;;;;;;;;;;;:38;;-1:-1:-1;;;2075:38:13;;2107:4;2075:38;;;3808:51:31;-1:-1:-1;;;;;2075:13:13;;;;:23;;3781:18:31;;2075:38:13;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;2056:57;;2146:4;:19;;;2128:15;:37;:54;;;;-1:-1:-1;2169:13:13;;;2128:54;2124:321;;;2199:12;2232:4;:19;;;2214:15;:37;;;;:::i;:::-;2199:52;;2266:20;2334:15;;2315:4;:15;;;2297;;2290:4;:22;;;;:::i;:::-;:40;;;;:::i;:::-;2289:60;;;;:::i;:::-;2266:83;-1:-1:-1;2425:8:13;2386:35;1278:4;2266:83;2386:35;:::i;:::-;2385:48;;;;:::i;:::-;2364:69;;;;:::i;:::-;;;2124:321;;;2540:15;;;;2481:11;;1278:4;;2481:31;;2495:17;;2481:31;:::i;:::-;2480:56;;;;:::i;:::-;2473:82;;;;:::i;:::-;2455:101;1788:776;-1:-1:-1;;;;;;;1788:776:13:o;9720:480::-;1019:7:1;1045:6;-1:-1:-1;;;;;1045:6:1;666:10:11;1185:23:1;1177:68;;;;-1:-1:-1;;;1177:68:1;;;;;;;:::i;:::-;9853:28:13::1;9872:8;9853:18;:28::i;:::-;9913:10;9894:15;;:29;;;;;;;:::i;:::-;::::0;;;-1:-1:-1;;9934:7:13::1;:22:::0;;::::1;::::0;;::::1;::::0;;;;;::::1;::::0;;-1:-1:-1;;;;;9934:22:13;;::::1;-1:-1:-1::0;;;;;;9934:22:13;;::::1;::::0;::::1;::::0;;;9967:8:::1;:24:::0;;;;::::1;::::0;;;;::::1;::::0;;;;::::1;::::0;;;::::1;::::0;::::1;::::0;;;10018:89:::1;::::0;;::::1;::::0;::::1;::::0;;-1:-1:-1;10018:89:13;;;10068:15:::1;9934:22;10018:89:::0;::::1;::::0;;;;;;;;;10004:8:::1;:104:::0;;;;::::1;::::0;;;;;;;;::::1;::::0;;::::1;::::0;;;;;;;;;;;;;;;;10140:14;;9934:22;;10140:18:::1;::::0;::::1;:::i;:::-;10124:68;::::0;8170:25:31;;;10124:68:13::1;::::0;8158:2:31;8143:18;10124:68:13::1;;;;;;;9720:480:::0;;;:::o;891:27::-;;;;;;;;;;;;6922:1061;7043:20;7066:15;7077:3;7066:10;:15::i;:::-;7092:21;7116:13;;;:8;:13;;;;;;;;7130:10;7116:25;;;;;;;7201:22;;7187:11;;7043:38;;-1:-1:-1;7116:25:13;;1278:4;;7187:36;;;:::i;:::-;7186:61;;;;:::i;:::-;7152:96;;7259:22;7312:4;:15;;;7292:17;:35;;;;:::i;:::-;7416:22;;7259:69;;-1:-1:-1;1278:4:13;;7407:31;;:6;:31;:::i;:::-;7406:56;;;;:::i;:::-;7379:84;;:17;:84;:::i;:::-;7361:15;;;:102;7474:21;;7489:6;;7361:4;;7474:11;;:21;;7489:6;;7474:21;:::i;:::-;;;;-1:-1:-1;;7537:19:13;;7533:91;;7573:6;;:39;;-1:-1:-1;;;;;7573:6:13;7593:2;7597:14;7573:19;:39::i;:::-;7636:19;7658:8;7667:3;7658:13;;;;;;-1:-1:-1;;;7658:13:13;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;7658:13:13;;-1:-1:-1;7686:32:13;;7682:133;;7791:11;;7735:68;;-1:-1:-1;;;7735:68:13;;-1:-1:-1;;;;;7735:18:13;;;;;:68;;7754:3;;7759:10;;7771:2;;7775:14;;7791:11;7735:68;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;7682:133;7827:37;7853:2;7857:6;7827:7;7835:3;7827:12;;;;;;-1:-1:-1;;;7827:12:13;;;;;;;;:37;7916:2;-1:-1:-1;;;;;7882:37:13;7903:3;7891:10;-1:-1:-1;;;;;7882:37:13;;7908:6;7882:37;;;;8170:25:31;;8158:2;8143:18;;8125:76;7882:37:13;;;;;;;;7935:40;;8170:25:31;;;7955:3:13;;7943:10;;7935:40;;8158:2:31;8143:18;7935:40:13;;;;;;;6922:1061;;;;;;;;:::o;1846:189:1:-;1019:7;1045:6;-1:-1:-1;;;;;1045:6:1;666:10:11;1185:23:1;1177:68;;;;-1:-1:-1;;;1177:68:1;;;;;;;:::i;:::-;-1:-1:-1;;;;;1934:22:1;::::1;1926:73;;;::::0;-1:-1:-1;;;1926:73:1;;5567:2:31;1926:73:1::1;::::0;::::1;5549:21:31::0;5606:2;5586:18;;;5579:30;5645:34;5625:18;;;5618:62;-1:-1:-1;;;5696:18:31;;;5689:36;5742:19;;1926:73:1::1;5539:228:31::0;1926:73:1::1;2009:19;2019:8;2009:9;:19::i;:::-;1846:189:::0;:::o;8746:271:13:-;8822:8;:15;8805:14;8848:162;8876:6;8870:3;:12;8848:162;;;8945:1;8910:13;;;:8;:13;;;;;;;;8924:10;8910:25;;;;;;;:32;:36;8906:93;;8967:16;8975:3;8980:2;8967:7;:16::i;:::-;8884:5;;;:::i;:::-;;;8848:162;;;;8746:271;;:::o;634:205:9:-;773:58;;-1:-1:-1;;;;;4442:32:31;;773:58:9;;;4424:51:31;4491:18;;;4484:34;;;746:86:9;;766:5;;-1:-1:-1;;;796:23:9;4397:18:31;;773:58:9;;;;-1:-1:-1;;773:58:9;;;;;;;;;;;;;;-1:-1:-1;;;;;773:58:9;-1:-1:-1;;;;;;773:58:9;;;;;;;;;;746:19;:86::i;2041:169:1:-;2096:16;2115:6;;-1:-1:-1;;;;;2131:17:1;;;-1:-1:-1;;;;;;2131:17:1;;;;;;2163:40;;2115:6;;;;;;;2163:40;;2096:16;2163:40;2041:169;;:::o;845:241:9:-;1010:68;;-1:-1:-1;;;;;4128:15:31;;;1010:68:9;;;4110:34:31;4180:15;;4160:18;;;4153:43;4212:18;;;4205:34;;;983:96:9;;1003:5;;-1:-1:-1;;;1033:27:9;4045:18:31;;1010:68:9;4027:218:31;9079:246:13;9166:8;:15;9149:14;9192:126;9220:6;9214:3;:12;9192:126;;;9274:8;-1:-1:-1;;;;;9258:24:13;:7;9266:3;9258:12;;;;;;-1:-1:-1;;;9258:12:13;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;9258:12:13;:24;;9250:56;;;;-1:-1:-1;;;9250:56:13;;6381:2:31;9250:56:13;;;6363:21:31;6420:2;6400:18;;;6393:30;-1:-1:-1;;;6439:18:31;;;6432:49;6498:18;;9250:56:13;6353:169:31;9250:56:13;9228:5;;;:::i;:::-;;;9192:126;;3140:706:9;3559:23;3585:69;3613:4;3585:69;;;;;;;;;;;;;;;;;3593:5;-1:-1:-1;;;;;3585:27:9;;;:69;;;;;:::i;:::-;3668:17;;3559:95;;-1:-1:-1;3668:21:9;3664:176;;3763:10;3752:30;;;;;;;;;;;;:::i;:::-;3744:85;;;;-1:-1:-1;;;3744:85:9;;7448:2:31;3744:85:9;;;7430:21:31;7487:2;7467:18;;;7460:30;7526:34;7506:18;;;7499:62;-1:-1:-1;;;7577:18:31;;;7570:40;7627:19;;3744:85:9;7420:232:31;3461:223:10;3594:12;3625:52;3647:6;3655:4;3661:1;3664:12;3625:21;:52::i;:::-;3618:59;;3461:223;;;;;;:::o;4548:499::-;4713:12;4770:5;4745:21;:30;;4737:81;;;;-1:-1:-1;;;4737:81:10;;5974:2:31;4737:81:10;;;5956:21:31;6013:2;5993:18;;;5986:30;6052:34;6032:18;;;6025:62;-1:-1:-1;;;6103:18:31;;;6096:36;6149:19;;4737:81:10;5946:228:31;4737:81:10;1034:20;;4828:60;;;;-1:-1:-1;;;4828:60:10;;7090:2:31;4828:60:10;;;7072:21:31;7129:2;7109:18;;;7102:30;7168:31;7148:18;;;7141:59;7217:18;;4828:60:10;7062:179:31;4828:60:10;4900:12;4914:23;4941:6;-1:-1:-1;;;;;4941:11:10;4960:5;4967:4;4941:31;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4899:73;;;;4989:51;5006:7;5015:10;5027:12;7307;7335:7;7331:516;;;-1:-1:-1;7365:10:10;7358:17;;7331:516;7476:17;;:21;7472:365;;7670:10;7664:17;7730:15;7717:10;7713:2;7709:19;7702:44;7619:145;7809:12;7802:20;;-1:-1:-1;;;7802:20:10;;;;;;;;:::i;14:257:31:-;73:6;126:2;114:9;105:7;101:23;97:32;94:2;;;147:6;139;132:22;94:2;191:9;178:23;210:31;235:5;210:31;:::i;276:665::-;362:6;370;423:2;411:9;402:7;398:23;394:32;391:2;;;444:6;436;429:22;391:2;489:9;476:23;518:18;559:2;551:6;548:14;545:2;;;580:6;572;565:22;545:2;623:6;612:9;608:22;598:32;;668:7;661:4;657:2;653:13;649:27;639:2;;695:6;687;680:22;639:2;740;727:16;766:2;758:6;755:14;752:2;;;787:6;779;772:22;752:2;845:7;840:2;830:6;827:1;823:14;819:2;815:23;811:32;808:45;805:2;;;871:6;863;856:22;805:2;907;899:11;;;;;929:6;;-1:-1:-1;381:560:31;;-1:-1:-1;;;;381:560:31:o;946:255::-;1013:6;1066:2;1054:9;1045:7;1041:23;1037:32;1034:2;;;1087:6;1079;1072:22;1034:2;1124:9;1118:16;1143:28;1165:5;1143:28;:::i;1206:190::-;1265:6;1318:2;1306:9;1297:7;1293:23;1289:32;1286:2;;;1339:6;1331;1324:22;1286:2;-1:-1:-1;1367:23:31;;1276:120;-1:-1:-1;1276:120:31:o;1401:194::-;1471:6;1524:2;1512:9;1503:7;1499:23;1495:32;1492:2;;;1545:6;1537;1530:22;1492:2;-1:-1:-1;1573:16:31;;1482:113;-1:-1:-1;1482:113:31:o;1600:325::-;1668:6;1676;1729:2;1717:9;1708:7;1704:23;1700:32;1697:2;;;1750:6;1742;1735:22;1697:2;1791:9;1778:23;1768:33;;1851:2;1840:9;1836:18;1823:32;1864:31;1889:5;1864:31;:::i;:::-;1914:5;1904:15;;;1687:238;;;;;:::o;1930:498::-;2039:6;2047;2055;2108:2;2096:9;2087:7;2083:23;2079:32;2076:2;;;2129:6;2121;2114:22;2076:2;2170:9;2157:23;2147:33;;2230:2;2219:9;2215:18;2202:32;2243:31;2268:5;2243:31;:::i;:::-;2293:5;-1:-1:-1;2350:2:31;2335:18;;2322:32;2363:33;2322:32;2363:33;:::i;:::-;2415:7;2405:17;;;2066:362;;;;;:::o;2433:393::-;2510:6;2518;2526;2579:2;2567:9;2558:7;2554:23;2550:32;2547:2;;;2600:6;2592;2585:22;2547:2;2641:9;2628:23;2618:33;;2698:2;2687:9;2683:18;2670:32;2660:42;;2752:2;2741:9;2737:18;2724:32;2765:31;2790:5;2765:31;:::i;2831:547::-;2932:6;2940;2948;2956;3009:3;2997:9;2988:7;2984:23;2980:33;2977:2;;;3031:6;3023;3016:22;2977:2;3072:9;3059:23;3049:33;;3129:2;3118:9;3114:18;3101:32;3091:42;;3183:2;3172:9;3168:18;3155:32;3196:31;3221:5;3196:31;:::i;:::-;3246:5;-1:-1:-1;3303:2:31;3288:18;;3275:32;3316:30;3275:32;3316:30;:::i;:::-;2967:411;;;;-1:-1:-1;2967:411:31;;-1:-1:-1;;2967:411:31:o;3383:274::-;3512:3;3550:6;3544:13;3566:53;3612:6;3607:3;3600:4;3592:6;3588:17;3566:53;:::i;:::-;3635:16;;;;;3520:137;-1:-1:-1;;3520:137:31:o;4977:383::-;5126:2;5115:9;5108:21;5089:4;5158:6;5152:13;5201:6;5196:2;5185:9;5181:18;5174:34;5217:66;5276:6;5271:2;5260:9;5256:18;5251:2;5243:6;5239:15;5217:66;:::i;:::-;5344:2;5323:15;-1:-1:-1;;5319:29:31;5304:45;;;;5351:2;5300:54;;5098:262;-1:-1:-1;;5098:262:31:o;6527:356::-;6729:2;6711:21;;;6748:18;;;6741:30;6807:34;6802:2;6787:18;;6780:62;6874:2;6859:18;;6701:182::o;8206:535::-;8481:25;;;-1:-1:-1;;;;;8580:15:31;;;8575:2;8560:18;;8553:43;8632:15;;;;8627:2;8612:18;;8605:43;8679:2;8664:18;;8657:34;;;;8722:3;8707:19;;8700:35;8468:3;8453:19;;8435:306::o;10640:267::-;10679:3;10707:11;;;10734:10;;-1:-1:-1;;;;;10753:27:31;;;10746:35;;10730:52;10727:2;;;10785:18;;:::i;:::-;-1:-1:-1;;;10832:19:31;;;10825:27;;10817:36;;10814:2;;;10856:18;;:::i;:::-;-1:-1:-1;;10892:9:31;;10687:220::o;10912:128::-;10952:3;10983:1;10979:6;10976:1;10973:13;10970:2;;;10989:18;;:::i;:::-;-1:-1:-1;11025:9:31;;10960:80::o;11045:217::-;11085:1;11111;11101:2;;-1:-1:-1;;;11136:31:31;;11190:4;11187:1;11180:15;11218:4;11143:1;11208:15;11101:2;-1:-1:-1;11247:9:31;;11091:171::o;11267:168::-;11307:7;11373:1;11369;11365:6;11361:14;11358:1;11355:21;11350:1;11343:9;11336:17;11332:45;11329:2;;;11380:18;;:::i;:::-;-1:-1:-1;11420:9:31;;11319:116::o;11440:270::-;11479:4;11508:12;;;11536:10;;-1:-1:-1;;;11555:19:31;;11548:27;;11532:44;11529:2;;;11579:18;;:::i;:::-;-1:-1:-1;;;;;11626:27:31;;11619:35;;11611:44;;11608:2;;;11658:18;;:::i;:::-;-1:-1:-1;;11695:9:31;;11488:222::o;11715:125::-;11755:4;11783:1;11780;11777:8;11774:2;;;11788:18;;:::i;:::-;-1:-1:-1;11825:9:31;;11764:76::o;11845:258::-;11917:1;11927:113;11941:6;11938:1;11935:13;11927:113;;;12017:11;;;12011:18;11998:11;;;11991:39;11963:2;11956:10;11927:113;;;12058:6;12055:1;12052:13;12049:2;;;-1:-1:-1;;12093:1:31;12075:16;;12068:27;11898:205::o;12108:135::-;12147:3;-1:-1:-1;;12168:17:31;;12165:2;;;12188:18;;:::i;:::-;-1:-1:-1;12235:1:31;12224:13;;12155:88::o;12248:127::-;12309:10;12304:3;12300:20;12297:1;12290:31;12340:4;12337:1;12330:15;12364:4;12361:1;12354:15;12380:131;-1:-1:-1;;;;;12455:31:31;;12445:42;;12435:2;;12501:1;12498;12491:12;12516:118;12602:5;12595:13;12588:21;12581:5;12578:32;12568:2;;12624:1;12621;12614:12
Swarm Source
ipfs://935d5b74a860337ab2a72faac19e67bc5c75538cb605769496847b16cdfe9ddf
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in MOVR
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.