Latest 25 from a total of 20,244 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw | 282747472 | 419 days ago | IN | 0 ETH | 0.00000171 | ||||
| Withdraw | 279257977 | 429 days ago | IN | 0 ETH | 0.0000083 | ||||
| Set Global UP Ls | 257688209 | 492 days ago | IN | 0 ETH | 0.00000182 | ||||
| Set Global UP Ls | 257673920 | 492 days ago | IN | 0 ETH | 0.0000022 | ||||
| Set Global UP Ls | 257659614 | 492 days ago | IN | 0 ETH | 0.00000229 | ||||
| Set Global UP Ls | 257645278 | 492 days ago | IN | 0 ETH | 0.00000197 | ||||
| Set Global UP Ls | 257630911 | 492 days ago | IN | 0 ETH | 0.00000253 | ||||
| Set Global UP Ls | 257616584 | 492 days ago | IN | 0 ETH | 0.00000387 | ||||
| Set Global UP Ls | 257602265 | 492 days ago | IN | 0 ETH | 0.00000403 | ||||
| Set Global UP Ls | 257587942 | 492 days ago | IN | 0 ETH | 0.00000435 | ||||
| Set Global UP Ls | 257573622 | 492 days ago | IN | 0 ETH | 0.00000441 | ||||
| Set Global UP Ls | 257559281 | 492 days ago | IN | 0 ETH | 0.00000335 | ||||
| Set Global UP Ls | 257544915 | 492 days ago | IN | 0 ETH | 0.00000178 | ||||
| Set Global UP Ls | 257530539 | 492 days ago | IN | 0 ETH | 0.000002 | ||||
| Set Global UP Ls | 257516183 | 492 days ago | IN | 0 ETH | 0.00000184 | ||||
| Set Global UP Ls | 257501822 | 492 days ago | IN | 0 ETH | 0.00000173 | ||||
| Set Global UP Ls | 257487438 | 492 days ago | IN | 0 ETH | 0.00000193 | ||||
| Set Global UP Ls | 257473064 | 492 days ago | IN | 0 ETH | 0.0000037 | ||||
| Set Global UP Ls | 257458703 | 492 days ago | IN | 0 ETH | 0.0000014 | ||||
| Set Global UP Ls | 257444348 | 493 days ago | IN | 0 ETH | 0.00000117 | ||||
| Set Global UP Ls | 257429973 | 493 days ago | IN | 0 ETH | 0.00000131 | ||||
| Set Global UP Ls | 257415616 | 493 days ago | IN | 0 ETH | 0.0000016 | ||||
| Set Global UP Ls | 257401285 | 493 days ago | IN | 0 ETH | 0.00000164 | ||||
| Set Global UP Ls | 257386984 | 493 days ago | IN | 0 ETH | 0.00000149 | ||||
| Set Global UP Ls | 257372623 | 493 days ago | IN | 0 ETH | 0.00000174 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 252426936 | 507 days ago | 0.001 ETH | ||||
| 194429706 | 676 days ago | 1 ETH | ||||
| 194429134 | 676 days ago | 1 ETH | ||||
| 194429019 | 676 days ago | 1 ETH | ||||
| 194428753 | 676 days ago | 1 ETH | ||||
| 194428706 | 676 days ago | 1 ETH | ||||
| 194428645 | 676 days ago | 1 ETH | ||||
| 194428564 | 676 days ago | 1 ETH | ||||
| 194428510 | 676 days ago | 1 ETH | ||||
| 194428464 | 676 days ago | 1 ETH | ||||
| 194428400 | 676 days ago | 1 ETH | ||||
| 194428351 | 676 days ago | 1 ETH | ||||
| 194428283 | 676 days ago | 1 ETH | ||||
| 194428233 | 676 days ago | 1 ETH | ||||
| 194428105 | 676 days ago | 1 ETH | ||||
| 194343169 | 676 days ago | 16.5 ETH | ||||
| 192763202 | 681 days ago | 0.1 ETH | ||||
| 192414447 | 682 days ago | 0.1 ETH | ||||
| 190807510 | 687 days ago | 11 ETH | ||||
| 190736266 | 687 days ago | 11 ETH | ||||
| 190493919 | 688 days ago | 9.5 ETH | ||||
| 190380241 | 688 days ago | 7.51 ETH | ||||
| 183042489 | 710 days ago | 0.1 ETH | ||||
| 181687745 | 714 days ago | 22.35 ETH | ||||
| 181367809 | 715 days ago | 21.27 ETH |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Pool
Compiler Version
v0.8.17+commit.8df45f5f
Optimization Enabled:
Yes with 100 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;
import '../stores/AssetStore.sol';
import '../stores/DataStore.sol';
import '../stores/FundStore.sol';
import '../stores/PoolStore.sol';
import '../utils/Roles.sol';
/**
* @title Pool
* @notice Users can deposit supported assets to back trader profits and receive
* a share of trader losses. Each asset pool is siloed, e.g. the ETH
* pool is independent from the USDC pool.
*/
contract Pool is Roles {
// Constants
uint256 public constant UNIT = 10 ** 18;
uint256 public constant BPS_DIVIDER = 10000;
// Events
event PoolDeposit(
address indexed user,
address indexed asset,
uint256 amount,
uint256 feeAmount,
uint256 clpAmount,
uint256 poolBalance
);
event PoolWithdrawal(
address indexed user,
address indexed asset,
uint256 amount,
uint256 feeAmount,
uint256 clpAmount,
uint256 poolBalance
);
event PoolPayIn(
address indexed user,
address indexed asset,
string market,
uint256 amount,
uint256 bufferToPoolAmount,
uint256 poolBalance,
uint256 bufferBalance
);
event PoolPayOut(
address indexed user,
address indexed asset,
string market,
uint256 amount,
uint256 poolBalance,
uint256 bufferBalance
);
// Contracts
DataStore public DS;
AssetStore public assetStore;
FundStore public fundStore;
PoolStore public poolStore;
// Ephemeral storage
mapping(address => bool) private whitelistedKeepers;
mapping(address => int256) private globalUPLs; // asset => upl
/// @dev Initializes DataStore address
constructor(RoleStore rs, DataStore ds) Roles(rs) {
DS = ds;
}
/// @notice Initializes protocol contracts
/// @dev Only callable by governance
function link() external onlyGov {
assetStore = AssetStore(DS.getAddress('AssetStore'));
fundStore = FundStore(payable(DS.getAddress('FundStore')));
poolStore = PoolStore(DS.getAddress('PoolStore'));
}
// -- Ephemeral storage -- //
/// @notice Whitelisted keeper that can update global UPL
/// @param keeper Keeper address
function setWhitelistedKeeper(address keeper, bool isActive) external onlyGov {
whitelistedKeepers[keeper] = isActive;
}
/// @notice Set global UPL, called by whitelisted keeper
/// @param assets Asset addresses
/// @param upls Corresponding total unrealized profit / loss
function setGlobalUPLs(address[] calldata assets, int256[] calldata upls) external {
require(whitelistedKeepers[msg.sender], "!unauthorized");
for (uint256 i = 0; i < assets.length; i++) {
globalUPLs[assets[i]] = upls[i];
}
}
/// @notice Returns total unrealized p/l for `asset`
function getGlobalUPL(address asset) external view returns (int256) {
return globalUPLs[asset];
}
/// @notice Returns pool deposit tax for `asset` and amount in bps
function getDepositTaxBps(address asset, uint256 amount) public view returns (uint256) {
uint256 taxBps;
uint256 balance = poolStore.getBalance(asset);
uint256 bufferBalance = poolStore.getBufferBalance(asset);
if (globalUPLs[asset] - int256(bufferBalance) < 0) {
taxBps = uint256(int256(BPS_DIVIDER) * (int256(bufferBalance) - globalUPLs[asset]) / (int256(balance) + int256(amount)));
}
return taxBps;
}
/// @notice Returns pool withdrawal tax for `asset` and amount in bps
function getWithdrawalTaxBps(address asset, uint256 amount) public view returns (uint256) {
uint256 taxBps;
uint256 balance = poolStore.getBalance(asset);
if (amount >= balance) return BPS_DIVIDER;
uint256 bufferBalance = poolStore.getBufferBalance(asset);
if (globalUPLs[asset] - int256(bufferBalance) > 0) {
taxBps = uint256(int256(BPS_DIVIDER) * (globalUPLs[asset] - int256(bufferBalance)) / (int256(balance) - int256(amount)));
}
return taxBps;
}
// -- //
/// @notice Credit trader loss to buffer and pay pool from buffer amount based on time and payout rate
/// @param user User which incurred trading loss
/// @param asset Asset address, e.g. address(0) for ETH
/// @param market Market, e.g. "ETH-USD"
/// @param amount Amount of trader loss
function creditTraderLoss(address user, address asset, string memory market, uint256 amount) external onlyContract {
// credit trader loss to buffer
poolStore.incrementBufferBalance(asset, amount);
// local variables
uint256 lastPaid = poolStore.getLastPaid(asset);
uint256 _now = block.timestamp;
uint256 amountToSendPool;
if (lastPaid == 0) {
// during the very first execution, set lastPaid and return
poolStore.setLastPaid(asset, _now);
} else {
// get buffer balance and buffer payout period to calculate amountToSendPool
uint256 bufferBalance = poolStore.getBufferBalance(asset);
uint256 bufferPayoutPeriod = poolStore.bufferPayoutPeriod();
// Stream buffer balance progressively into the pool
amountToSendPool = (bufferBalance * (block.timestamp - lastPaid)) / bufferPayoutPeriod;
if (amountToSendPool > bufferBalance) amountToSendPool = bufferBalance;
// update storage
poolStore.incrementBalance(asset, amountToSendPool);
poolStore.decrementBufferBalance(asset, amountToSendPool);
poolStore.setLastPaid(asset, _now);
}
// emit event
emit PoolPayIn(
user,
asset,
market,
amount,
amountToSendPool,
poolStore.getBalance(asset),
poolStore.getBufferBalance(asset)
);
}
/// @notice Pay out trader profit, from buffer first then pool if buffer is depleted
/// @param user Address to send funds to
/// @param asset Asset address, e.g. address(0) for ETH
/// @param market Market, e.g. "ETH-USD"
/// @param amount Amount of trader profit
function debitTraderProfit(
address user,
address asset,
string calldata market,
uint256 amount
) external onlyContract {
// return if profit = 0
if (amount == 0) return;
uint256 bufferBalance = poolStore.getBufferBalance(asset);
// decrement buffer balance first
poolStore.decrementBufferBalance(asset, amount);
// if amount is greater than available in the buffer, pay remaining from the pool
if (amount > bufferBalance) {
uint256 diffToPayFromPool = amount - bufferBalance;
uint256 poolBalance = poolStore.getBalance(asset);
require(diffToPayFromPool < poolBalance, '!pool-balance');
poolStore.decrementBalance(asset, diffToPayFromPool);
}
// transfer profit out
fundStore.transferOut(asset, user, amount);
// emit event
emit PoolPayOut(user, asset, market, amount, poolStore.getBalance(asset), poolStore.getBufferBalance(asset));
}
/// @notice Deposit 'amount' of 'asset' into the pool
/// @param asset Asset address, e.g. address(0) for ETH
/// @param amount Amount to be deposited
function deposit(address asset, uint256 amount) public payable {
require(amount > 0, '!amount');
require(assetStore.isSupported(asset), '!asset');
uint256 balance = poolStore.getBalance(asset);
address user = msg.sender;
// if asset is ETH (address(0)), set amount to msg.value
if (asset == address(0)) {
amount = msg.value;
fundStore.transferIn{value: amount}(asset, user, amount);
} else {
fundStore.transferIn(asset, user, amount);
}
// deposit tax
uint256 taxBps = getDepositTaxBps(asset, amount);
require(taxBps < BPS_DIVIDER, "!tax");
uint256 tax = (amount * taxBps) / BPS_DIVIDER;
uint256 amountMinusTax = amount - tax;
// pool share is equal to pool balance of user divided by the total balance
uint256 clpSupply = poolStore.getClpSupply(asset);
uint256 clpAmount = balance == 0 || clpSupply == 0 ? amountMinusTax : (amountMinusTax * clpSupply) / balance;
// increment balances
poolStore.incrementUserClpBalance(asset, user, clpAmount);
poolStore.incrementBalance(asset, amount);
// emit event
emit PoolDeposit(user, asset, amount, tax, clpAmount, poolStore.getBalance(asset));
}
/// @notice Withdraw 'amount' of 'asset'
/// @param asset Asset address, e.g. address(0) for ETH
/// @param amount Amount to be withdrawn
function withdraw(address asset, uint256 amount) public {
require(amount > BPS_DIVIDER, '!amount');
require(assetStore.isSupported(asset), '!asset');
address user = msg.sender;
// check pool balance and clp supply
uint256 balance = poolStore.getBalance(asset);
uint256 clpSupply = poolStore.getClpSupply(asset);
require(balance > 0 && clpSupply > 0, '!empty');
// check user balance
uint256 userBalance = poolStore.getUserBalance(asset, user);
if (amount > userBalance) amount = userBalance;
// withdrawal tax
uint256 taxBps = getWithdrawalTaxBps(asset, amount);
require(taxBps < BPS_DIVIDER, "!tax");
uint256 tax = (amount * taxBps) / BPS_DIVIDER;
uint256 amountMinusTax = amount - tax;
// // flat pool withdrawal fee (should generally be = 0)
// uint256 feeAmount = (amountMinusTax * poolStore.getWithdrawalFee(asset)) / BPS_DIVIDER;
// uint256 amountMinusFee = amountMinusTax - feeAmount;
// CLP amount
uint256 clpAmount = (amount * clpSupply) / balance;
// decrement balances
poolStore.decrementUserClpBalance(asset, user, clpAmount);
poolStore.decrementBalance(asset, amountMinusTax);
// transfer funds out
fundStore.transferOut(asset, user, amountMinusTax);
// emit event
emit PoolWithdrawal(user, asset, amount, tax, clpAmount, poolStore.getBalance(asset));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (security/ReentrancyGuard.sol)
pragma solidity ^0.8.0;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant _NOT_ENTERED = 1;
uint256 private constant _ENTERED = 2;
uint256 private _status;
constructor() {
_status = _NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
// 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
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)
pragma solidity ^0.8.0;
import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";
/**
* @title SafeERC20
* @dev Wrappers around ERC20 operations that throw on failure (when the token
* contract returns false). Tokens that return no value (and instead revert or
* throw on failure) are also supported, non-reverting calls are assumed to be
* successful.
* To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
* which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
*/
library SafeERC20 {
using Address for address;
function safeTransfer(
IERC20 token,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
}
function safeTransferFrom(
IERC20 token,
address from,
address to,
uint256 value
) internal {
_callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
}
/**
* @dev Deprecated. This function has issues similar to the ones found in
* {IERC20-approve}, and its usage is discouraged.
*
* Whenever possible, use {safeIncreaseAllowance} and
* {safeDecreaseAllowance} instead.
*/
function safeApprove(
IERC20 token,
address spender,
uint256 value
) internal {
// safeApprove should only be called when setting an initial allowance,
// or when resetting it to zero. To increase and decrease it, use
// 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
require(
(value == 0) || (token.allowance(address(this), spender) == 0),
"SafeERC20: approve from non-zero to non-zero allowance"
);
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
}
function safeIncreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
uint256 newAllowance = token.allowance(address(this), spender) + value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
function safeDecreaseAllowance(
IERC20 token,
address spender,
uint256 value
) internal {
unchecked {
uint256 oldAllowance = token.allowance(address(this), spender);
require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
uint256 newAllowance = oldAllowance - value;
_callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
}
}
function safePermit(
IERC20Permit token,
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) internal {
uint256 nonceBefore = token.nonces(owner);
token.permit(owner, spender, value, deadline, v, r, s);
uint256 nonceAfter = token.nonces(owner);
require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
}
/**
* @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
* on the return value: the return value is optional (but if data is returned, it must not be false).
* @param token The token targeted by the call.
* @param data The call data (encoded using abi.encode or one of its variants).
*/
function _callOptionalReturn(IERC20 token, bytes memory data) private {
// We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
// we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
// the target address contains contract code and also asserts for success in the low-level call.
bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
if (returndata.length > 0) {
// Return data is optional
require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return 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
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/structs/EnumerableSet.sol)
pragma solidity ^0.8.0;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position of the value in the `values` array, plus 1 because index 0
// means a value is not in the set.
mapping(bytes32 => uint256) _indexes;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._indexes[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We read and store the value's index to prevent multiple reads from the same storage slot
uint256 valueIndex = set._indexes[value];
if (valueIndex != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 toDeleteIndex = valueIndex - 1;
uint256 lastIndex = set._values.length - 1;
if (lastIndex != toDeleteIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the last value to the index where the value to delete is
set._values[toDeleteIndex] = lastValue;
// Update the index for the moved value
set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the index for the deleted slot
delete set._indexes[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._indexes[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
return _values(set._inner);
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;
import '../utils/Roles.sol';
/// @title AssetStore
/// @notice Persistent storage of supported assets
contract AssetStore is Roles {
// Asset info struct
struct Asset {
uint256 minSize;
address chainlinkFeed;
}
// Asset list
address[] public assetList;
mapping(address => Asset) private assets;
constructor(RoleStore rs) Roles(rs) {}
/// @notice Set or update an asset
/// @dev Only callable by governance
/// @param asset Asset address, e.g. address(0) for ETH
/// @param assetInfo Struct containing minSize and chainlinkFeed
function set(address asset, Asset memory assetInfo) external onlyGov {
assets[asset] = assetInfo;
for (uint256 i = 0; i < assetList.length; i++) {
if (assetList[i] == asset) return;
}
assetList.push(asset);
}
/// @notice Returns asset struct of `asset`
/// @param asset Asset address, e.g. address(0) for ETH
function get(address asset) external view returns (Asset memory) {
return assets[asset];
}
/// @notice Get a list of all supported assets
function getAssetList() external view returns (address[] memory) {
return assetList;
}
/// @notice Get number of supported assets
function getAssetCount() external view returns (uint256) {
return assetList.length;
}
/// @notice Returns asset address at `index`
/// @param index index of asset
function getAssetByIndex(uint256 index) external view returns (address) {
return assetList[index];
}
/// @notice Returns true if `asset` is supported
/// @param asset Asset address, e.g. address(0) for ETH
function isSupported(address asset) external view returns (bool) {
return assets[asset].minSize > 0;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;
import '../utils/Governable.sol';
/// @title DataStore
/// @notice General purpose storage contract
/// @dev Access is restricted to governance
contract DataStore is Governable {
// Key-value stores
mapping(bytes32 => uint256) public uintValues;
mapping(bytes32 => int256) public intValues;
mapping(bytes32 => address) public addressValues;
mapping(bytes32 => bytes32) public dataValues;
mapping(bytes32 => bool) public boolValues;
mapping(bytes32 => string) public stringValues;
constructor() Governable() {}
/// @param key The key for the record
/// @param value value to store
/// @param overwrite Overwrites existing value if set to true
function setUint(string calldata key, uint256 value, bool overwrite) external onlyGov returns (bool) {
bytes32 hash = getHash(key);
if (overwrite || uintValues[hash] == 0) {
uintValues[hash] = value;
return true;
}
return false;
}
/// @param key The key for the record
function getUint(string calldata key) external view returns (uint256) {
return uintValues[getHash(key)];
}
/// @param key The key for the record
/// @param value value to store
/// @param overwrite Overwrites existing value if set to true
function setInt(string calldata key, int256 value, bool overwrite) external onlyGov returns (bool) {
bytes32 hash = getHash(key);
if (overwrite || intValues[hash] == 0) {
intValues[hash] = value;
return true;
}
return false;
}
/// @param key The key for the record
function getInt(string calldata key) external view returns (int256) {
return intValues[getHash(key)];
}
/// @param key The key for the record
/// @param value address to store
/// @param overwrite Overwrites existing value if set to true
function setAddress(string calldata key, address value, bool overwrite) external onlyGov returns (bool) {
bytes32 hash = getHash(key);
if (overwrite || addressValues[hash] == address(0)) {
addressValues[hash] = value;
return true;
}
return false;
}
/// @param key The key for the record
function getAddress(string calldata key) external view returns (address) {
return addressValues[getHash(key)];
}
/// @param key The key for the record
/// @param value byte value to store
function setData(string calldata key, bytes32 value) external onlyGov returns (bool) {
dataValues[getHash(key)] = value;
return true;
}
/// @param key The key for the record
function getData(string calldata key) external view returns (bytes32) {
return dataValues[getHash(key)];
}
/// @param key The key for the record
/// @param value value to store (true / false)
function setBool(string calldata key, bool value) external onlyGov returns (bool) {
boolValues[getHash(key)] = value;
return true;
}
/// @param key The key for the record
function getBool(string calldata key) external view returns (bool) {
return boolValues[getHash(key)];
}
/// @param key The key for the record
/// @param value string to store
function setString(string calldata key, string calldata value) external onlyGov returns (bool) {
stringValues[getHash(key)] = value;
return true;
}
/// @param key The key for the record
function getString(string calldata key) external view returns (string memory) {
return stringValues[getHash(key)];
}
/// @param key string to hash
function getHash(string memory key) public pure returns (bytes32) {
return keccak256(abi.encodePacked(key));
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;
import '@openzeppelin/contracts/security/ReentrancyGuard.sol';
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '../utils/Roles.sol';
/// @title FundStore
/// @notice Storage of protocol funds
contract FundStore is Roles, ReentrancyGuard {
// Libraries
using SafeERC20 for IERC20;
using Address for address payable;
constructor(RoleStore rs) Roles(rs) {}
/// @notice Transfers `amount` of `asset` in
/// @dev Only callable by other protocol contracts
/// @param asset Asset address, e.g. address(0) for ETH
/// @param from Address where asset is transferred from
function transferIn(address asset, address from, uint256 amount) external payable onlyContract {
if (amount == 0 || asset == address(0)) return;
IERC20(asset).safeTransferFrom(from, address(this), amount);
}
/// @notice Transfers `amount` of `asset` out
/// @dev Only callable by other protocol contracts
/// @param asset Asset address, e.g. address(0) for ETH
/// @param to Address where asset is transferred to
function transferOut(address asset, address to, uint256 amount) external nonReentrant onlyContract {
if (amount == 0 || to == address(0)) return;
if (asset == address(0)) {
payable(to).sendValue(amount);
} else {
IERC20(asset).safeTransfer(to, amount);
}
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;
import '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
import '../utils/Roles.sol';
/// @title PoolStore
/// @notice Persistent storage for Pool.sol
contract PoolStore is Roles {
// Libraries
using SafeERC20 for IERC20;
// Constants
uint256 public constant BPS_DIVIDER = 10000;
uint256 public constant MAX_POOL_WITHDRAWAL_FEE = 500; // in bps = 5%
// State variables
uint256 public feeShare = 500;
uint256 public bufferPayoutPeriod = 7 days;
mapping(address => uint256) private clpSupply; // asset => clp supply
mapping(address => uint256) private balances; // asset => balance
mapping(address => mapping(address => uint256)) private userClpBalances; // asset => account => clp amount
mapping(address => uint256) private bufferBalances; // asset => balance
mapping(address => uint256) private lastPaid; // asset => timestamp
mapping(address => uint256) private withdrawalFees; // asset => bps
constructor(RoleStore rs) Roles(rs) {}
/// @notice Set pool fee
/// @dev Only callable by governance
/// @param bps fee share in bps
function setFeeShare(uint256 bps) external onlyGov {
require(bps < BPS_DIVIDER, '!bps');
feeShare = bps;
}
/// @notice Set buffer payout period
/// @dev Only callable by governance
/// @param period Buffer payout period in seconds, default is 7 days (604800 seconds)
function setBufferPayoutPeriod(uint256 period) external onlyGov {
require(period > 0, '!period');
bufferPayoutPeriod = period;
}
/// @notice Set pool withdrawal fee
/// @dev Only callable by governance
/// @param asset Pool asset, e.g. address(0) for ETH
/// @param bps Withdrawal fee in bps
function setWithdrawalFee(address asset, uint256 bps) external onlyGov {
require(bps <= MAX_POOL_WITHDRAWAL_FEE, '!pool-withdrawal-fee');
withdrawalFees[asset] = bps;
}
/// @notice Increments pool balance
/// @dev Only callable by other protocol contracts
function incrementBalance(address asset, uint256 amount) external onlyContract {
balances[asset] += amount;
}
/// @notice Decrements pool balance
/// @dev Only callable by other protocol contracts
function decrementBalance(address asset, uint256 amount) external onlyContract {
balances[asset] = balances[asset] <= amount ? 0 : balances[asset] - amount;
}
/// @notice Increments buffer balance
/// @dev Only callable by other protocol contracts
function incrementBufferBalance(address asset, uint256 amount) external onlyContract {
bufferBalances[asset] += amount;
}
/// @notice Decrements buffer balance
/// @dev Only callable by other protocol contracts
function decrementBufferBalance(address asset, uint256 amount) external onlyContract {
bufferBalances[asset] = bufferBalances[asset] <= amount ? 0 : bufferBalances[asset] - amount;
}
/// @notice Updates `lastPaid`
/// @dev Only callable by other protocol contracts
function setLastPaid(address asset, uint256 timestamp) external onlyContract {
lastPaid[asset] = timestamp;
}
/// @notice Increments `clpSupply` and `userClpBalances`
/// @dev Only callable by other protocol contracts
function incrementUserClpBalance(address asset, address user, uint256 amount) external onlyContract {
clpSupply[asset] += amount;
unchecked {
// Overflow not possible: balance + amount is at most clpSupply + amount, which is checked above.
userClpBalances[asset][user] += amount;
}
}
/// @notice Decrements `clpSupply` and `userClpBalances`
/// @dev Only callable by other protocol contracts
function decrementUserClpBalance(address asset, address user, uint256 amount) external onlyContract {
clpSupply[asset] = clpSupply[asset] <= amount ? 0 : clpSupply[asset] - amount;
userClpBalances[asset][user] = userClpBalances[asset][user] <= amount
? 0
: userClpBalances[asset][user] - amount;
}
/// @notice Returns withdrawal fee of `asset` from pool
function getWithdrawalFee(address asset) external view returns (uint256) {
return withdrawalFees[asset];
}
/// @notice Returns the sum of buffer and pool balance of `asset`
function getAvailable(address asset) external view returns (uint256) {
return balances[asset] + bufferBalances[asset];
}
/// @notice Returns amount of `asset` in pool
function getBalance(address asset) external view returns (uint256) {
return balances[asset];
}
/// @notice Returns amount of `asset` in buffer
function getBufferBalance(address asset) external view returns (uint256) {
return bufferBalances[asset];
}
/// @notice Returns pool balances of `_assets`
function getBalances(address[] calldata _assets) external view returns (uint256[] memory) {
uint256 length = _assets.length;
uint256[] memory _balances = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
_balances[i] = balances[_assets[i]];
}
return _balances;
}
/// @notice Returns buffer balances of `_assets`
function getBufferBalances(address[] calldata _assets) external view returns (uint256[] memory) {
uint256 length = _assets.length;
uint256[] memory _balances = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
_balances[i] = bufferBalances[_assets[i]];
}
return _balances;
}
/// @notice Returns last time pool was paid
function getLastPaid(address asset) external view returns (uint256) {
return lastPaid[asset];
}
/// @notice Returns `_assets` balance of `account`
function getUserBalances(address[] calldata _assets, address account) external view returns (uint256[] memory) {
uint256 length = _assets.length;
uint256[] memory _balances = new uint256[](length);
for (uint256 i = 0; i < length; i++) {
_balances[i] = getUserBalance(_assets[i], account);
}
return _balances;
}
/// @notice Returns `asset` balance of `account`
function getUserBalance(address asset, address account) public view returns (uint256) {
if (clpSupply[asset] == 0) return 0;
return (userClpBalances[asset][account] * balances[asset]) / clpSupply[asset];
}
/// @notice Returns total amount of CLP for `asset`
function getClpSupply(address asset) public view returns (uint256) {
return clpSupply[asset];
}
/// @notice Returns amount of CLP of `account` for `asset`
function getUserClpBalance(address asset, address account) public view returns (uint256) {
return userClpBalances[asset][account];
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;
import '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
import '../utils/Governable.sol';
/**
* @title RoleStore
* @notice Role-based access control mechanism. Governance can grant and
* revoke roles dynamically via {grantRole} and {revokeRole}
*/
contract RoleStore is Governable {
// Libraries
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.Bytes32Set;
// Set of roles
EnumerableSet.Bytes32Set internal roles;
// Role -> address
mapping(bytes32 => EnumerableSet.AddressSet) internal roleMembers;
constructor() Governable() {}
/// @notice Grants `role` to `account`
/// @dev Only callable by governance
function grantRole(address account, bytes32 role) external onlyGov {
// add role if not already present
if (!roles.contains(role)) roles.add(role);
require(roleMembers[role].add(account));
}
/// @notice Revokes `role` from `account`
/// @dev Only callable by governance
function revokeRole(address account, bytes32 role) external onlyGov {
require(roleMembers[role].remove(account));
// Remove role if it has no longer any members
if (roleMembers[role].length() == 0) {
roles.remove(role);
}
}
/// @notice Returns `true` if `account` has been granted `role`
function hasRole(address account, bytes32 role) external view returns (bool) {
return roleMembers[role].contains(account);
}
/// @notice Returns number of roles
function getRoleCount() external view returns (uint256) {
return roles.length();
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;
/// @title Governable
/// @notice Basic access control mechanism, gov has access to certain functions
contract Governable {
address public gov;
event SetGov(address prevGov, address nextGov);
/// @dev Initializes the contract setting the deployer address as governance
constructor() {
_setGov(msg.sender);
}
/// @dev Reverts if called by any account other than gov
modifier onlyGov() {
require(msg.sender == gov, '!gov');
_;
}
/// @notice Sets a new governance address
/// @dev Only callable by governance
function setGov(address _gov) external onlyGov {
_setGov(_gov);
}
/// @notice Sets a new governance address
/// @dev Internal function without access restriction
function _setGov(address _gov) internal {
address prevGov = gov;
gov = _gov;
emit SetGov(prevGov, _gov);
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.17;
import './Governable.sol';
import '../stores/RoleStore.sol';
/// @title Roles
/// @notice Role-based access control mechanism via onlyContract modifier
contract Roles is Governable {
bytes32 public constant CONTRACT = keccak256('CONTRACT');
RoleStore public roleStore;
/// @dev Initializes roleStore address
constructor(RoleStore rs) Governable() {
roleStore = rs;
}
/// @dev Reverts if caller address has not the contract role
modifier onlyContract() {
require(roleStore.hasRole(msg.sender, CONTRACT), '!contract-role');
_;
}
}{
"viaIR": true,
"optimizer": {
"enabled": true,
"runs": 100
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"contract RoleStore","name":"rs","type":"address"},{"internalType":"contract DataStore","name":"ds","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"clpAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"poolBalance","type":"uint256"}],"name":"PoolDeposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"string","name":"market","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bufferToPoolAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"poolBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bufferBalance","type":"uint256"}],"name":"PoolPayIn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"string","name":"market","type":"string"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"poolBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bufferBalance","type":"uint256"}],"name":"PoolPayOut","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"asset","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"clpAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"poolBalance","type":"uint256"}],"name":"PoolWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"prevGov","type":"address"},{"indexed":false,"internalType":"address","name":"nextGov","type":"address"}],"name":"SetGov","type":"event"},{"inputs":[],"name":"BPS_DIVIDER","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"CONTRACT","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DS","outputs":[{"internalType":"contract DataStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"UNIT","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"assetStore","outputs":[{"internalType":"contract AssetStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"string","name":"market","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"creditTraderLoss","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"address","name":"asset","type":"address"},{"internalType":"string","name":"market","type":"string"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"debitTraderProfit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"fundStore","outputs":[{"internalType":"contract FundStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getDepositTaxBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"}],"name":"getGlobalUPL","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"getWithdrawalTaxBps","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gov","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"link","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"poolStore","outputs":[{"internalType":"contract PoolStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"roleStore","outputs":[{"internalType":"contract RoleStore","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"assets","type":"address[]"},{"internalType":"int256[]","name":"upls","type":"int256[]"}],"name":"setGlobalUPLs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_gov","type":"address"}],"name":"setGov","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"keeper","type":"address"},{"internalType":"bool","name":"isActive","type":"bool"}],"name":"setWhitelistedKeeper","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"asset","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6080346100c757601f61203638819003918201601f19168301916001600160401b038311848410176100cc5780849260409485528339810103126100c75780516001600160a01b038082169290918390036100c75760200151918183168093036100c7577f53351836099c03ffc3b1727d8abd4b0222afa87d4ed76ae3102d51369ef7f785604060005460018060a01b0319943386831617600055825191168152336020820152a18160015416176001556002541617600255604051611f5390816100e38239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b600090813560e01c908163077d17f8146115515750806312d43a511461152a5780631c4695f41461139f57806325e9768f146113665780634242bac01461133d57806347e7ef2414610f625780634a4a7b0414610f395780634d2ccfd814610e5a578063597a0e3614610e315780635b2f4a1a14610d2c57806360465d1114610d035780637c4283bc14610ce65780638d86a79d14610c895780638e373abf14610c6157806394851ca314610c315780639d8e217714610c0e578063b931db6d14610637578063cfad57a2146105b2578063f3fef3a3146101285763fc833ac6146100fd57600080fd5b346101255780600319360112610125576020604051600080516020611efe8339815191528152f35b80fd5b503461012557604036600319011261012557610142611576565b6024908135612710610155818311611e60565b60018060a01b039283600354169460405192634f129c5360e01b84528386841697886004830152818460209788935afa80156105a75761019c918a9161057a575b50611e96565b8560055416926040519663f8b2cb4f60e01b918289528960048a015286898681895afa98891561056f578b99610540575b5060405163ee39b63760e01b8152600481018b905293878587818a5afa948515610535578c95610506575b50891515806104fd575b156104d057604051636805d6ad60e01b81526001600160a01b03831660048201523360248201528c92919089816044818c5afa9081156104c5578491610494575b50808b1161048a575b50899a61028a61028361028f9361027b61026a8f9e9f9d9e88611866565b610275838210611ecb565b8d611a29565b04809b611a1c565b978d611a29565b611a3c565b97803b1561044f57604051630963ccad60e11b815290839082908183816102bb8f338a60048501611a46565b03925af190811561046b578391610476575b50508260055416803b1561044f57826040518092631c83b8df60e21b82528183816102fc8c8960048401611a01565b03925af190811561046b578391610453575b5050826004541694853b1561044f576103429583928360405180998195829463078d3b7960e01b8452339060048501611a46565b03925af1938415610442578894610425575b505060055416926040518094819382528a60048301525afa93841561041a5787946103c3575b5050604080519485526020850191909152830152606082015233907fae04f501857d63b8ca31ec171decfe6513ab9113a08210fc4acc3403190e0df99080608081015b0390a380f35b90809450813d8311610413575b6103da81836115fd565b8101031261040e576103bd7fae04f501857d63b8ca31ec171decfe6513ab9113a08210fc4acc3403190e0df993519361037a565b600080fd5b503d6103d0565b6040513d89823e3d90fd5b610431919294506115d3565b61043e5785918938610354565b8880fd5b50604051903d90823e3d90fd5b8280fd5b61045c906115d3565b61046757813861030e565b5080fd5b6040513d85823e3d90fd5b61047f906115d3565b6104675781386102cd565b995061028361024c565b8094508a8092503d83116104be575b6104ad81836115fd565b8101031261040e578c925138610243565b503d6104a3565b6040513d86823e3d90fd5b60405162461bcd60e51b8152600481018990526006818801526521656d70747960d01b6044820152606490fd5b50841515610202565b9094508781813d831161052e575b61051e81836115fd565b8101031261040e575193386101f8565b503d610514565b6040513d8e823e3d90fd5b9098508681813d8311610568575b61055881836115fd565b8101031261040e575197386101cd565b503d61054e565b6040513d8d823e3d90fd5b61059a9150863d88116105a0575b61059281836115fd565b8101906119ac565b38610196565b503d610588565b6040513d8b823e3d90fd5b5034610125576020366003190112610125577f53351836099c03ffc3b1727d8abd4b0222afa87d4ed76ae3102d51369ef7f7856105ed611576565b82546001600160a01b03808216919061060733841461161f565b83166001600160a01b031991909116178455604080516001600160a01b039283168152919092166020820152a180f35b503461012557608036600319011261012557610651611576565b9061065a61158c565b916044359267ffffffffffffffff8085116109855736602386011215610985578460040135908111610bfa576040519461069e601f8301601f1916602001876115fd565b818652366024838301011161099457818592602460209301838901378601015260015460405163ac4ab3fb60e01b8152336004820152600080516020611efe833981519152602482015290602090829060449082906001600160a01b03165afa9081156104c55790610717918591610bdb575b506119c4565b6005546001600160a01b0316803b156109855783604051809263de900ab960e01b825281838161074d6064358960048401611a01565b03925af180156104c557908491610bc7575b5050600554604051631d683d8f60e11b81526001600160a01b0383811660048301529091169190602081602481865afa908115610989578591610b95575b508492816109985750506005546001600160a01b0316803b156109945784604051809263473cc2af60e01b82528183816107db428960048401611a01565b03925af1801561098957908591610971575b50505b60055460405163f8b2cb4f60e01b81526001600160a01b03838116600483015290929116602083602481845afa92831561093157869361093c575b50604051634021fe0f60e01b81526001600160a01b038316600482015290602090829060249082905afa9081156109315786916108ff575b506040519260a084528751948560a0860152875b8681106108e957509260c09285949285938a868a7fa23af116f782ad07f8010bd150b57bb7084c718271e5aa4bdab61a8be2986b059a010152606435602086015260408501526060840152608083015260018060a01b03169560018060a01b031694601f80199101168101030190a380f35b80602080928c01015160c0828901015201610877565b90506020813d602011610929575b8161091a602093836115fd565b8101031261040e575138610863565b3d915061090d565b6040513d88823e3d90fd5b9092506020813d602011610969575b81610958602093836115fd565b8101031261040e575191602061082b565b3d915061094b565b61097a906115d3565b6109855783386107ed565b8380fd5b6040513d87823e3d90fd5b8480fd5b604051634021fe0f60e01b81526001600160a01b0384166004820152935090602084602481855afa938415610931578694610b61575b506040516359bca66760e01b815290602082600481865afa91821561041a578792610b2b575b509061028a610a06610a0c9342611a1c565b86611a29565b92808411610b23575b50803b1561099457846040518092631c25e23360e11b8252818381610a3e898960048401611a01565b03925af1801561098957908591610b0f575b50506005546001600160a01b0316803b1561099457846040518092637a8b01ef60e11b8252818381610a86898960048401611a01565b03925af1801561098957908591610afb575b50506005546001600160a01b0316803b156109945784604051809263473cc2af60e01b8252818381610ace428960048401611a01565b03925af1801561098957908591610ae7575b50506107f0565b610af0906115d3565b610985578338610ae0565b610b04906115d3565b610985578338610a98565b610b18906115d3565b610985578338610a50565b925038610a15565b91506020823d602011610b59575b81610b46602093836115fd565b8101031261040e5790519061028a6109f4565b3d9150610b39565b9093506020813d602011610b8d575b81610b7d602093836115fd565b8101031261040e575192386109ce565b3d9150610b70565b90506020813d602011610bbf575b81610bb0602093836115fd565b8101031261040e57513861079d565b3d9150610ba3565b610bd0906115d3565b61044f57823861075f565b610bf4915060203d6020116105a05761059281836115fd565b38610711565b634e487b7160e01b84526041600452602484fd5b50346101255780600319360112610125576020604051670de0b6b3a76400008152f35b5034610125576040366003190112610125576020610c59610c50611576565b60243590611866565b604051908152f35b5034610125576040366003190112610125576020610c59610c80611576565b60243590611708565b503461012557604036600319011261012557610ca3611576565b6024359081151580920361044f5782546001600160a01b039190610cca908316331461161f565b1682526006602052604082209060ff8019835416911617905580f35b503461012557806003193601126101255760206040516127108152f35b50346101255780600319360112610125576005546040516001600160a01b039091168152602090f35b50346101255760403660031901126101255767ffffffffffffffff60043581811161044f57610d5f9036906004016115a2565b90602492833590811161099457610d7a9036906004016115a2565b90923386526020916006835260ff60408820541615610dfd57865b828110610da0578780f35b610dab818388611670565b35610db7828588611670565b356001600160a01b03811690819003610df95789526007855260408920556000198114610de657600101610d95565b634e487b7160e01b885260116004528688fd5b8980fd5b60405162461bcd60e51b815260048101849052600d818801526c085d5b985d5d1a1bdc9a5e9959609a1b6044820152606490fd5b50346101255780600319360112610125576003546040516001600160a01b039091168152602090f35b503461012557608036600319011261012557610e74611576565b610e7c61158c565b906044359067ffffffffffffffff9081831161099457366023840112156109945782600401359182116109945736602483850101116109945760015460405163ac4ab3fb60e01b8152336004820152600080516020611efe83398151915260248201529490602090869060449082906001600160a01b03165afa94851561093157610f1e95610f11918891610f2157506119c4565b6024606435940191611a68565b80f35b610bf4915060203d81116105a05761059281836115fd565b50346101255780600319360112610125576001546040516001600160a01b039091168152602090f35b50604036600319011261012557610f77611576565b60243590610f86821515611e60565b600354604051634f129c5360e01b81526001600160a01b03838116600483018190529460209390929084908290602490829086165afa801561041a57610fd29188916113265750611e96565b806005541660405192848460248163f8b2cb4f60e01b958682528b60048301525afa93841561131b5788946112ec575b508661129557503494878360045416803b156104675781604051809263e4652f4960e01b8252818b8161103a82338b60048501611a46565b03925af1801561122a57611281575b50505b6110568682611708565b61106e61271091611068838210611ecb565b88611a29565b04928861107b8589611a1c565b82600554169660405163ee39b63760e01b81528b600482015289816024818c5afa9081156104c5578491611250575b5081158015611248575b15611235575050955b803b1561046757816040518092637ecad97360e11b82528183816110e68d338c60048501611a46565b03925af1801561122a57611216575b508160055416803b15610467578882916111269583604051809881958294631c25e23360e11b845260048401611a01565b03925af19283156104425787936111f9575b5050600554169160246040518094819382528a60048301525afa93841561041a5787946111a7575b5050604080519485526020850191909152830152606082015233907fe86ca4e4cf6c4f168e7f6b59c7eeccff1c602e4a3a8e157200ac7ea3fb33792a9080608081016103bd565b90809450813d83116111f2575b6111be81836115fd565b8101031261040e576103bd7fe86ca4e4cf6c4f168e7f6b59c7eeccff1c602e4a3a8e157200ac7ea3fb33792a935193611160565b503d6111b4565b611205919293506115d3565b6112125784908838611138565b8780fd5b61121f906115d3565b61043e5788386110f5565b6040513d84823e3d90fd5b61028a9061124293611a29565b956110bd565b5080156110b4565b8094508a8092503d831161127a575b61126981836115fd565b8101031261040e578b9251386110aa565b503d61125f565b61128a906115d3565b611212578738611049565b948260045416803b1561043e5788604051809263e4652f4960e01b82528183816112c48d338a60048501611a46565b03925af180156105a7576112d9575b5061104c565b6112e5909891986115d3565b96386112d3565b9093508481813d8311611314575b61130481836115fd565b8101031261121257519238611002565b503d6112fa565b6040513d8a823e3d90fd5b61059a9150853d87116105a05761059281836115fd565b50346101255780600319360112610125576002546040516001600160a01b039091168152602090f35b5034610125576020366003190112610125576020906040906001600160a01b0361138e611576565b168152600783522054604051908152f35b503461012557806003193601126101255780546001600160a01b03906113c8908216331461161f565b60025460405163bf40fac160e01b808252602060048301819052600a602484015269417373657453746f726560b01b60448401529193928316908285606481855afa94851561093157869561150b575b508360018060a01b0319951685600354161760035560405190808252836004830152600960248301526846756e6453746f726560b81b60448301528382606481865afa91821561041a578492869189916114ee575b501686600454161760045560646040518094819382528460048301526009602483015268506f6f6c53746f726560b81b60448301525afa9182156109895785926114c1575b50501690600554161760055580f35b6114e09250803d106114e7575b6114d881836115fd565b810190611651565b38806114b2565b503d6114ce565b6115059150843d86116114e7576114d881836115fd565b3861146d565b611523919550833d85116114e7576114d881836115fd565b9338611418565b5034610125578060031936011261012557546040516001600160a01b039091168152602090f35b9050346104675781600319360112610467576004546001600160a01b03168152602090f35b600435906001600160a01b038216820361040e57565b602435906001600160a01b038216820361040e57565b9181601f8401121561040e5782359167ffffffffffffffff831161040e576020808501948460051b01011161040e57565b67ffffffffffffffff81116115e757604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff8211176115e757604052565b1561162657565b606460405162461bcd60e51b815260206004820152600460248201526310b3b7bb60e11b6044820152fd5b9081602091031261040e57516001600160a01b038116810361040e5790565b91908110156116805760051b0190565b634e487b7160e01b600052603260045260246000fd5b818103929160001380158285131691841216176116af57565b634e487b7160e01b600052601160045260246000fd5b9061271091808302928305036116af57565b81156116f257600160ff1b81146000198314166116af570590565b634e487b7160e01b600052601260045260246000fd5b6005546040805163f8b2cb4f60e01b81526001600160a01b03938416600482018190526000969594909316929091906020908184602481885afa93841561182d578894611837575b508160249495845195868092634021fe0f60e01b82528560048301525afa93841561182d5788946117fe575b5080885260078252876117928585832054611696565b126117a0575b505050505050565b8752600790528520546117bc916117b79190611696565b6116c5565b908483820193841291129080158216911516176117ea576117de9293506116d7565b90388080808080611798565b634e487b7160e01b84526011600452602484fd5b9093508181813d8311611826575b61181681836115fd565b810103126112125751923861177c565b503d61180c565b83513d8a823e3d90fd5b93508184813d831161185f575b61184e81836115fd565b810103126112125792519281611750565b503d611844565b60009160018060a01b0380600554169060409081519463f8b2cb4f60e01b8652168060048601526020908186602481875afa95861561196657879661197d575b50858510156119705781602494845195868092634021fe0f60e01b82528560048301525afa938415611966578794611933575b5080875260078252866118ef8585832054611696565b136118fe575b50505050505090565b9261191c928760076117b79461192298976119289b52522054611696565b92611696565b906116d7565b3880808080806118f5565b9093508181813d831161195f575b61194b81836115fd565b8101031261195b575192386118d9565b8680fd5b503d611941565b83513d89823e3d90fd5b5050505050505061271090565b9095508181813d83116119a5575b61199581836115fd565b8101031261195b575194386118a6565b503d61198b565b9081602091031261040e5751801515810361040e5790565b156119cb57565b60405162461bcd60e51b815260206004820152600e60248201526d21636f6e74726163742d726f6c6560901b6044820152606490fd5b6001600160a01b039091168152602081019190915260400190565b919082039182116116af57565b818102929181159184041417156116af57565b81156116f2570490565b6001600160a01b03918216815291166020820152604081019190915260600190565b94939092916000958215611e575760018060a01b039081600554166040908151634021fe0f60e01b808252858a16996004928b848201528d6020958683602481845afa928315611e4d578293611e1e575b50803b1561046757611ae282918d8a51948580948193637a8b01ef60e11b83528a8d8401611a01565b03925af18015611e1257611df5575b5090818e96959493928b11611cd7575b5087835416803b1561195b578a87918983611b31958a519687958694859363078d3b7960e01b85528c8501611a46565b03925af18015611ccd57908691611cb9575b50508660055416845163f8b2cb4f60e01b81528c848201528481602481855afa968715611cae57908d9796959493929196611c76575b508392916024918651988994859384528301525afa938415611c6c579b899a9b9c819a999a95611c06575b509882917f3092724f7adc895c13332959eb9d68277692c0f667f5c166c06996dfd6f21e2d9a60a0999897969594519a8b9960808b528160808c01528b8b0137888d018a015287015285015260608401521694601f01601f19168101030190a3565b82809a50819998979650919493923d8311611c65575b611c2681836115fd565b8101031261040e577f3092724f7adc895c13332959eb9d68277692c0f667f5c166c06996dfd6f21e2d988a9860a0985195969798509192939099611ba4565b503d611c1c565b82513d8e823e3d90fd5b96509450908286813d8111611ca7575b611c9081836115fd565b8101031261040e5794518b95909490919083611b79565b503d611c86565b8651903d90823e3d90fd5b611cc2906115d3565b610994578438611b43565b85513d88823e3d90fd5b611ce7919293949596508a611a1c565b8d8860055416908d88519063f8b2cb4f60e01b8252878201528781602481865afa918215611dea5791611dbd575b50821015611d8a5790818f9796959493923b15611212578651631c83b8df60e21b81529188918391829084908290611d5090898c8401611a01565b03925af18015611d8057908791611d68575b50611b01565b611d71906115d3565b611d7c578538611d62565b8580fd5b86513d89823e3d90fd5b865162461bcd60e51b8152808601879052600d60248201526c21706f6f6c2d62616c616e636560981b6044820152606490fd5b90508681813d8311611de3575b611dd481836115fd565b8101031261040e575138611d15565b503d611dca565b8951903d90823e3d90fd5b611e06909e9196959493929e6115d3565b9c909192939438611af1565b8f8851903d90823e3d90fd5b9092508681813d8311611e46575b611e3681836115fd565b8101031261046757519138611ab9565b503d611e2c565b88513d84823e3d90fd5b50505050509050565b15611e6757565b60405162461bcd60e51b815260206004820152600760248201526608585b5bdd5b9d60ca1b6044820152606490fd5b15611e9d57565b60405162461bcd60e51b815260206004820152600660248201526508585cdcd95d60d21b6044820152606490fd5b15611ed257565b606460405162461bcd60e51b8152602060048201526004602482015263042e8c2f60e31b6044820152fdfea66b7a3e6b19d24ccb6f717fc232a1bb0278a7f83f8e2211835fc4ed0fe69f19a26469706673582212203b0f7b57ab25cb52ff5516ecd2369456922922dfda1686ca9055cd11b3647bd264736f6c63430008110033000000000000000000000000e5da4704a582fe799dcd1dff31dc2ed2e0bdc961000000000000000000000000a64694e51b22a081ea1e4051ef4ea1b715b47026
Deployed Bytecode
0x608080604052600436101561001357600080fd5b600090813560e01c908163077d17f8146115515750806312d43a511461152a5780631c4695f41461139f57806325e9768f146113665780634242bac01461133d57806347e7ef2414610f625780634a4a7b0414610f395780634d2ccfd814610e5a578063597a0e3614610e315780635b2f4a1a14610d2c57806360465d1114610d035780637c4283bc14610ce65780638d86a79d14610c895780638e373abf14610c6157806394851ca314610c315780639d8e217714610c0e578063b931db6d14610637578063cfad57a2146105b2578063f3fef3a3146101285763fc833ac6146100fd57600080fd5b346101255780600319360112610125576020604051600080516020611efe8339815191528152f35b80fd5b503461012557604036600319011261012557610142611576565b6024908135612710610155818311611e60565b60018060a01b039283600354169460405192634f129c5360e01b84528386841697886004830152818460209788935afa80156105a75761019c918a9161057a575b50611e96565b8560055416926040519663f8b2cb4f60e01b918289528960048a015286898681895afa98891561056f578b99610540575b5060405163ee39b63760e01b8152600481018b905293878587818a5afa948515610535578c95610506575b50891515806104fd575b156104d057604051636805d6ad60e01b81526001600160a01b03831660048201523360248201528c92919089816044818c5afa9081156104c5578491610494575b50808b1161048a575b50899a61028a61028361028f9361027b61026a8f9e9f9d9e88611866565b610275838210611ecb565b8d611a29565b04809b611a1c565b978d611a29565b611a3c565b97803b1561044f57604051630963ccad60e11b815290839082908183816102bb8f338a60048501611a46565b03925af190811561046b578391610476575b50508260055416803b1561044f57826040518092631c83b8df60e21b82528183816102fc8c8960048401611a01565b03925af190811561046b578391610453575b5050826004541694853b1561044f576103429583928360405180998195829463078d3b7960e01b8452339060048501611a46565b03925af1938415610442578894610425575b505060055416926040518094819382528a60048301525afa93841561041a5787946103c3575b5050604080519485526020850191909152830152606082015233907fae04f501857d63b8ca31ec171decfe6513ab9113a08210fc4acc3403190e0df99080608081015b0390a380f35b90809450813d8311610413575b6103da81836115fd565b8101031261040e576103bd7fae04f501857d63b8ca31ec171decfe6513ab9113a08210fc4acc3403190e0df993519361037a565b600080fd5b503d6103d0565b6040513d89823e3d90fd5b610431919294506115d3565b61043e5785918938610354565b8880fd5b50604051903d90823e3d90fd5b8280fd5b61045c906115d3565b61046757813861030e565b5080fd5b6040513d85823e3d90fd5b61047f906115d3565b6104675781386102cd565b995061028361024c565b8094508a8092503d83116104be575b6104ad81836115fd565b8101031261040e578c925138610243565b503d6104a3565b6040513d86823e3d90fd5b60405162461bcd60e51b8152600481018990526006818801526521656d70747960d01b6044820152606490fd5b50841515610202565b9094508781813d831161052e575b61051e81836115fd565b8101031261040e575193386101f8565b503d610514565b6040513d8e823e3d90fd5b9098508681813d8311610568575b61055881836115fd565b8101031261040e575197386101cd565b503d61054e565b6040513d8d823e3d90fd5b61059a9150863d88116105a0575b61059281836115fd565b8101906119ac565b38610196565b503d610588565b6040513d8b823e3d90fd5b5034610125576020366003190112610125577f53351836099c03ffc3b1727d8abd4b0222afa87d4ed76ae3102d51369ef7f7856105ed611576565b82546001600160a01b03808216919061060733841461161f565b83166001600160a01b031991909116178455604080516001600160a01b039283168152919092166020820152a180f35b503461012557608036600319011261012557610651611576565b9061065a61158c565b916044359267ffffffffffffffff8085116109855736602386011215610985578460040135908111610bfa576040519461069e601f8301601f1916602001876115fd565b818652366024838301011161099457818592602460209301838901378601015260015460405163ac4ab3fb60e01b8152336004820152600080516020611efe833981519152602482015290602090829060449082906001600160a01b03165afa9081156104c55790610717918591610bdb575b506119c4565b6005546001600160a01b0316803b156109855783604051809263de900ab960e01b825281838161074d6064358960048401611a01565b03925af180156104c557908491610bc7575b5050600554604051631d683d8f60e11b81526001600160a01b0383811660048301529091169190602081602481865afa908115610989578591610b95575b508492816109985750506005546001600160a01b0316803b156109945784604051809263473cc2af60e01b82528183816107db428960048401611a01565b03925af1801561098957908591610971575b50505b60055460405163f8b2cb4f60e01b81526001600160a01b03838116600483015290929116602083602481845afa92831561093157869361093c575b50604051634021fe0f60e01b81526001600160a01b038316600482015290602090829060249082905afa9081156109315786916108ff575b506040519260a084528751948560a0860152875b8681106108e957509260c09285949285938a868a7fa23af116f782ad07f8010bd150b57bb7084c718271e5aa4bdab61a8be2986b059a010152606435602086015260408501526060840152608083015260018060a01b03169560018060a01b031694601f80199101168101030190a380f35b80602080928c01015160c0828901015201610877565b90506020813d602011610929575b8161091a602093836115fd565b8101031261040e575138610863565b3d915061090d565b6040513d88823e3d90fd5b9092506020813d602011610969575b81610958602093836115fd565b8101031261040e575191602061082b565b3d915061094b565b61097a906115d3565b6109855783386107ed565b8380fd5b6040513d87823e3d90fd5b8480fd5b604051634021fe0f60e01b81526001600160a01b0384166004820152935090602084602481855afa938415610931578694610b61575b506040516359bca66760e01b815290602082600481865afa91821561041a578792610b2b575b509061028a610a06610a0c9342611a1c565b86611a29565b92808411610b23575b50803b1561099457846040518092631c25e23360e11b8252818381610a3e898960048401611a01565b03925af1801561098957908591610b0f575b50506005546001600160a01b0316803b1561099457846040518092637a8b01ef60e11b8252818381610a86898960048401611a01565b03925af1801561098957908591610afb575b50506005546001600160a01b0316803b156109945784604051809263473cc2af60e01b8252818381610ace428960048401611a01565b03925af1801561098957908591610ae7575b50506107f0565b610af0906115d3565b610985578338610ae0565b610b04906115d3565b610985578338610a98565b610b18906115d3565b610985578338610a50565b925038610a15565b91506020823d602011610b59575b81610b46602093836115fd565b8101031261040e5790519061028a6109f4565b3d9150610b39565b9093506020813d602011610b8d575b81610b7d602093836115fd565b8101031261040e575192386109ce565b3d9150610b70565b90506020813d602011610bbf575b81610bb0602093836115fd565b8101031261040e57513861079d565b3d9150610ba3565b610bd0906115d3565b61044f57823861075f565b610bf4915060203d6020116105a05761059281836115fd565b38610711565b634e487b7160e01b84526041600452602484fd5b50346101255780600319360112610125576020604051670de0b6b3a76400008152f35b5034610125576040366003190112610125576020610c59610c50611576565b60243590611866565b604051908152f35b5034610125576040366003190112610125576020610c59610c80611576565b60243590611708565b503461012557604036600319011261012557610ca3611576565b6024359081151580920361044f5782546001600160a01b039190610cca908316331461161f565b1682526006602052604082209060ff8019835416911617905580f35b503461012557806003193601126101255760206040516127108152f35b50346101255780600319360112610125576005546040516001600160a01b039091168152602090f35b50346101255760403660031901126101255767ffffffffffffffff60043581811161044f57610d5f9036906004016115a2565b90602492833590811161099457610d7a9036906004016115a2565b90923386526020916006835260ff60408820541615610dfd57865b828110610da0578780f35b610dab818388611670565b35610db7828588611670565b356001600160a01b03811690819003610df95789526007855260408920556000198114610de657600101610d95565b634e487b7160e01b885260116004528688fd5b8980fd5b60405162461bcd60e51b815260048101849052600d818801526c085d5b985d5d1a1bdc9a5e9959609a1b6044820152606490fd5b50346101255780600319360112610125576003546040516001600160a01b039091168152602090f35b503461012557608036600319011261012557610e74611576565b610e7c61158c565b906044359067ffffffffffffffff9081831161099457366023840112156109945782600401359182116109945736602483850101116109945760015460405163ac4ab3fb60e01b8152336004820152600080516020611efe83398151915260248201529490602090869060449082906001600160a01b03165afa94851561093157610f1e95610f11918891610f2157506119c4565b6024606435940191611a68565b80f35b610bf4915060203d81116105a05761059281836115fd565b50346101255780600319360112610125576001546040516001600160a01b039091168152602090f35b50604036600319011261012557610f77611576565b60243590610f86821515611e60565b600354604051634f129c5360e01b81526001600160a01b03838116600483018190529460209390929084908290602490829086165afa801561041a57610fd29188916113265750611e96565b806005541660405192848460248163f8b2cb4f60e01b958682528b60048301525afa93841561131b5788946112ec575b508661129557503494878360045416803b156104675781604051809263e4652f4960e01b8252818b8161103a82338b60048501611a46565b03925af1801561122a57611281575b50505b6110568682611708565b61106e61271091611068838210611ecb565b88611a29565b04928861107b8589611a1c565b82600554169660405163ee39b63760e01b81528b600482015289816024818c5afa9081156104c5578491611250575b5081158015611248575b15611235575050955b803b1561046757816040518092637ecad97360e11b82528183816110e68d338c60048501611a46565b03925af1801561122a57611216575b508160055416803b15610467578882916111269583604051809881958294631c25e23360e11b845260048401611a01565b03925af19283156104425787936111f9575b5050600554169160246040518094819382528a60048301525afa93841561041a5787946111a7575b5050604080519485526020850191909152830152606082015233907fe86ca4e4cf6c4f168e7f6b59c7eeccff1c602e4a3a8e157200ac7ea3fb33792a9080608081016103bd565b90809450813d83116111f2575b6111be81836115fd565b8101031261040e576103bd7fe86ca4e4cf6c4f168e7f6b59c7eeccff1c602e4a3a8e157200ac7ea3fb33792a935193611160565b503d6111b4565b611205919293506115d3565b6112125784908838611138565b8780fd5b61121f906115d3565b61043e5788386110f5565b6040513d84823e3d90fd5b61028a9061124293611a29565b956110bd565b5080156110b4565b8094508a8092503d831161127a575b61126981836115fd565b8101031261040e578b9251386110aa565b503d61125f565b61128a906115d3565b611212578738611049565b948260045416803b1561043e5788604051809263e4652f4960e01b82528183816112c48d338a60048501611a46565b03925af180156105a7576112d9575b5061104c565b6112e5909891986115d3565b96386112d3565b9093508481813d8311611314575b61130481836115fd565b8101031261121257519238611002565b503d6112fa565b6040513d8a823e3d90fd5b61059a9150853d87116105a05761059281836115fd565b50346101255780600319360112610125576002546040516001600160a01b039091168152602090f35b5034610125576020366003190112610125576020906040906001600160a01b0361138e611576565b168152600783522054604051908152f35b503461012557806003193601126101255780546001600160a01b03906113c8908216331461161f565b60025460405163bf40fac160e01b808252602060048301819052600a602484015269417373657453746f726560b01b60448401529193928316908285606481855afa94851561093157869561150b575b508360018060a01b0319951685600354161760035560405190808252836004830152600960248301526846756e6453746f726560b81b60448301528382606481865afa91821561041a578492869189916114ee575b501686600454161760045560646040518094819382528460048301526009602483015268506f6f6c53746f726560b81b60448301525afa9182156109895785926114c1575b50501690600554161760055580f35b6114e09250803d106114e7575b6114d881836115fd565b810190611651565b38806114b2565b503d6114ce565b6115059150843d86116114e7576114d881836115fd565b3861146d565b611523919550833d85116114e7576114d881836115fd565b9338611418565b5034610125578060031936011261012557546040516001600160a01b039091168152602090f35b9050346104675781600319360112610467576004546001600160a01b03168152602090f35b600435906001600160a01b038216820361040e57565b602435906001600160a01b038216820361040e57565b9181601f8401121561040e5782359167ffffffffffffffff831161040e576020808501948460051b01011161040e57565b67ffffffffffffffff81116115e757604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff8211176115e757604052565b1561162657565b606460405162461bcd60e51b815260206004820152600460248201526310b3b7bb60e11b6044820152fd5b9081602091031261040e57516001600160a01b038116810361040e5790565b91908110156116805760051b0190565b634e487b7160e01b600052603260045260246000fd5b818103929160001380158285131691841216176116af57565b634e487b7160e01b600052601160045260246000fd5b9061271091808302928305036116af57565b81156116f257600160ff1b81146000198314166116af570590565b634e487b7160e01b600052601260045260246000fd5b6005546040805163f8b2cb4f60e01b81526001600160a01b03938416600482018190526000969594909316929091906020908184602481885afa93841561182d578894611837575b508160249495845195868092634021fe0f60e01b82528560048301525afa93841561182d5788946117fe575b5080885260078252876117928585832054611696565b126117a0575b505050505050565b8752600790528520546117bc916117b79190611696565b6116c5565b908483820193841291129080158216911516176117ea576117de9293506116d7565b90388080808080611798565b634e487b7160e01b84526011600452602484fd5b9093508181813d8311611826575b61181681836115fd565b810103126112125751923861177c565b503d61180c565b83513d8a823e3d90fd5b93508184813d831161185f575b61184e81836115fd565b810103126112125792519281611750565b503d611844565b60009160018060a01b0380600554169060409081519463f8b2cb4f60e01b8652168060048601526020908186602481875afa95861561196657879661197d575b50858510156119705781602494845195868092634021fe0f60e01b82528560048301525afa938415611966578794611933575b5080875260078252866118ef8585832054611696565b136118fe575b50505050505090565b9261191c928760076117b79461192298976119289b52522054611696565b92611696565b906116d7565b3880808080806118f5565b9093508181813d831161195f575b61194b81836115fd565b8101031261195b575192386118d9565b8680fd5b503d611941565b83513d89823e3d90fd5b5050505050505061271090565b9095508181813d83116119a5575b61199581836115fd565b8101031261195b575194386118a6565b503d61198b565b9081602091031261040e5751801515810361040e5790565b156119cb57565b60405162461bcd60e51b815260206004820152600e60248201526d21636f6e74726163742d726f6c6560901b6044820152606490fd5b6001600160a01b039091168152602081019190915260400190565b919082039182116116af57565b818102929181159184041417156116af57565b81156116f2570490565b6001600160a01b03918216815291166020820152604081019190915260600190565b94939092916000958215611e575760018060a01b039081600554166040908151634021fe0f60e01b808252858a16996004928b848201528d6020958683602481845afa928315611e4d578293611e1e575b50803b1561046757611ae282918d8a51948580948193637a8b01ef60e11b83528a8d8401611a01565b03925af18015611e1257611df5575b5090818e96959493928b11611cd7575b5087835416803b1561195b578a87918983611b31958a519687958694859363078d3b7960e01b85528c8501611a46565b03925af18015611ccd57908691611cb9575b50508660055416845163f8b2cb4f60e01b81528c848201528481602481855afa968715611cae57908d9796959493929196611c76575b508392916024918651988994859384528301525afa938415611c6c579b899a9b9c819a999a95611c06575b509882917f3092724f7adc895c13332959eb9d68277692c0f667f5c166c06996dfd6f21e2d9a60a0999897969594519a8b9960808b528160808c01528b8b0137888d018a015287015285015260608401521694601f01601f19168101030190a3565b82809a50819998979650919493923d8311611c65575b611c2681836115fd565b8101031261040e577f3092724f7adc895c13332959eb9d68277692c0f667f5c166c06996dfd6f21e2d988a9860a0985195969798509192939099611ba4565b503d611c1c565b82513d8e823e3d90fd5b96509450908286813d8111611ca7575b611c9081836115fd565b8101031261040e5794518b95909490919083611b79565b503d611c86565b8651903d90823e3d90fd5b611cc2906115d3565b610994578438611b43565b85513d88823e3d90fd5b611ce7919293949596508a611a1c565b8d8860055416908d88519063f8b2cb4f60e01b8252878201528781602481865afa918215611dea5791611dbd575b50821015611d8a5790818f9796959493923b15611212578651631c83b8df60e21b81529188918391829084908290611d5090898c8401611a01565b03925af18015611d8057908791611d68575b50611b01565b611d71906115d3565b611d7c578538611d62565b8580fd5b86513d89823e3d90fd5b865162461bcd60e51b8152808601879052600d60248201526c21706f6f6c2d62616c616e636560981b6044820152606490fd5b90508681813d8311611de3575b611dd481836115fd565b8101031261040e575138611d15565b503d611dca565b8951903d90823e3d90fd5b611e06909e9196959493929e6115d3565b9c909192939438611af1565b8f8851903d90823e3d90fd5b9092508681813d8311611e46575b611e3681836115fd565b8101031261046757519138611ab9565b503d611e2c565b88513d84823e3d90fd5b50505050509050565b15611e6757565b60405162461bcd60e51b815260206004820152600760248201526608585b5bdd5b9d60ca1b6044820152606490fd5b15611e9d57565b60405162461bcd60e51b815260206004820152600660248201526508585cdcd95d60d21b6044820152606490fd5b15611ed257565b606460405162461bcd60e51b8152602060048201526004602482015263042e8c2f60e31b6044820152fdfea66b7a3e6b19d24ccb6f717fc232a1bb0278a7f83f8e2211835fc4ed0fe69f19a26469706673582212203b0f7b57ab25cb52ff5516ecd2369456922922dfda1686ca9055cd11b3647bd264736f6c63430008110033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000e5da4704a582fe799dcd1dff31dc2ed2e0bdc961000000000000000000000000a64694e51b22a081ea1e4051ef4ea1b715b47026
-----Decoded View---------------
Arg [0] : rs (address): 0xe5DA4704a582Fe799dcd1dFF31dc2eD2e0BdC961
Arg [1] : ds (address): 0xa64694E51B22A081EA1e4051EF4EA1b715b47026
-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 000000000000000000000000e5da4704a582fe799dcd1dff31dc2ed2e0bdc961
Arg [1] : 000000000000000000000000a64694e51b22a081ea1e4051ef4ea1b715b47026
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.