Overview
ETH Balance
ETH Value
$0.00Latest 25 from a total of 1,280 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Withdraw | 81327672 | 943 days ago | IN | 0 ETH | 0.00005021 | ||||
| Deposit | 74924260 | 962 days ago | IN | 0 ETH | 0.00006544 | ||||
| Deposit | 74900299 | 962 days ago | IN | 0 ETH | 0.00005263 | ||||
| Withdraw | 74875498 | 962 days ago | IN | 0 ETH | 0.00005347 | ||||
| Withdraw | 74874903 | 962 days ago | IN | 0 ETH | 0.00005111 | ||||
| Withdraw | 74874748 | 962 days ago | IN | 0 ETH | 0.00005111 | ||||
| Deposit | 74864399 | 962 days ago | IN | 0 ETH | 0.00005768 | ||||
| Deposit | 74857768 | 962 days ago | IN | 0 ETH | 0.00009031 | ||||
| Withdraw | 74837979 | 962 days ago | IN | 0 ETH | 0.00004979 | ||||
| Withdraw | 74832247 | 962 days ago | IN | 0 ETH | 0.00005358 | ||||
| Withdraw | 74832199 | 962 days ago | IN | 0 ETH | 0.00004951 | ||||
| Withdraw | 74798259 | 962 days ago | IN | 0 ETH | 0.00006597 | ||||
| Withdraw | 74791663 | 962 days ago | IN | 0 ETH | 0.00004781 | ||||
| Withdraw | 74791552 | 962 days ago | IN | 0 ETH | 0.00004374 | ||||
| Deposit | 74773614 | 962 days ago | IN | 0.3 ETH | 0.00005677 | ||||
| Deposit | 74773120 | 962 days ago | IN | 0 ETH | 0.00005629 | ||||
| Deposit | 74771013 | 962 days ago | IN | 0 ETH | 0.00005959 | ||||
| Withdraw | 74763175 | 962 days ago | IN | 0 ETH | 0.00005828 | ||||
| Deposit | 74753023 | 962 days ago | IN | 0 ETH | 0.00004888 | ||||
| Withdraw | 74751803 | 962 days ago | IN | 0 ETH | 0.00004711 | ||||
| Withdraw | 74751644 | 962 days ago | IN | 0 ETH | 0.00004711 | ||||
| Withdraw | 74746732 | 962 days ago | IN | 0 ETH | 0.00004771 | ||||
| Deposit | 74741355 | 962 days ago | IN | 0 ETH | 0.00004624 | ||||
| Deposit | 74726088 | 962 days ago | IN | 5 ETH | 0.000056 | ||||
| Deposit | 74719585 | 962 days ago | IN | 0 ETH | 0.00005634 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 74773614 | 962 days ago | 0.3 ETH | ||||
| 74726088 | 962 days ago | 5 ETH | ||||
| 74688712 | 962 days ago | 3 ETH | ||||
| 74687699 | 962 days ago | 1.014 ETH | ||||
| 74631417 | 962 days ago | 0.75 ETH | ||||
| 74572687 | 963 days ago | 31.5 ETH | ||||
| 74566717 | 963 days ago | 0.458 ETH | ||||
| 74566668 | 963 days ago | 5 ETH | ||||
| 74565328 | 963 days ago | 0.4 ETH | ||||
| 74563366 | 963 days ago | 12.3 ETH | ||||
| 74518511 | 963 days ago | 0.7 ETH | ||||
| 74481287 | 963 days ago | 20 ETH | ||||
| 74476181 | 963 days ago | 0.5 ETH | ||||
| 74471958 | 963 days ago | 14.4 ETH | ||||
| 74425619 | 963 days ago | 1.3 ETH | ||||
| 74366528 | 963 days ago | 0.1 ETH | ||||
| 74196221 | 964 days ago | 0.07 ETH | ||||
| 74084269 | 964 days ago | 0.012 ETH | ||||
| 73956499 | 964 days ago | 0.3 ETH | ||||
| 73896133 | 965 days ago | 0.2 ETH | ||||
| 73839645 | 965 days ago | 0.5 ETH | ||||
| 73676832 | 965 days ago | 0.555 ETH | ||||
| 73587927 | 965 days ago | 19.43 ETH | ||||
| 73550637 | 966 days ago | 0.995 ETH | ||||
| 73507487 | 966 days ago | 30 ETH |
Cross-Chain Transactions
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 BPS_DIVIDER = 10000;
// Events
event PoolDeposit(
address indexed user,
address indexed asset,
uint256 amount,
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;
/// @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'));
}
/// @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);
}
// 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 ? amount : (amount * clpSupply) / balance;
// increment balances
poolStore.incrementUserClpBalance(asset, user, clpAmount);
poolStore.incrementBalance(asset, amount);
// emit event
emit PoolDeposit(user, asset, amount, 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;
// calculate pool withdrawal fee
uint256 feeAmount = (amount * poolStore.getWithdrawalFee(asset)) / BPS_DIVIDER;
uint256 amountMinusFee = amount - feeAmount;
// CLP amount
uint256 clpAmount = (amount * clpSupply) / balance;
// decrement balances
poolStore.decrementUserClpBalance(asset, user, clpAmount);
poolStore.decrementBalance(asset, amountMinusFee);
// transfer funds out
fundStore.transferOut(asset, user, amountMinusFee);
// emit event
emit PoolWithdrawal(user, asset, amount, feeAmount, clpAmount, poolStore.getBalance(asset));
}
}// 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 '@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 '../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/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 './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');
_;
}
}// 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 '@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: 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: 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 (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.6.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
* https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
*
* Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
* presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
* need to send a transaction, and thus is not required to hold Ether at all.
*/
interface IERC20Permit {
/**
* @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
* given ``owner``'s signed approval.
*
* IMPORTANT: The same issues {IERC20-approve} has related to transaction
* ordering also apply here.
*
* Emits an {Approval} event.
*
* Requirements:
*
* - `spender` cannot be the zero address.
* - `deadline` must be a timestamp in the future.
* - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
* over the EIP712-formatted function arguments.
* - the signature must use ``owner``'s current nonce (see {nonces}).
*
* For more information on the signature format, see the
* https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
* section].
*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
/**
* @dev Returns the current nonce for `owner`. This value must be
* included whenever a signature is generated for {permit}.
*
* Every successful call to {permit} increases ``owner``'s nonce by one. This
* prevents a signature from being used multiple times.
*/
function nonces(address owner) external view returns (uint256);
/**
* @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
*/
// solhint-disable-next-line func-name-mixedcase
function DOMAIN_SEPARATOR() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.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);
}
}
}
}{
"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":"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":"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":[],"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":"_gov","type":"address"}],"name":"setGov","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
6080346100c757601f611a6c38819003918201601f19168301916001600160401b038311848410176100cc5780849260409485528339810103126100c75780516001600160a01b038082169290918390036100c75760200151918183168093036100c7577f53351836099c03ffc3b1727d8abd4b0222afa87d4ed76ae3102d51369ef7f785604060005460018060a01b0319943386831617600055825191168152336020820152a1816001541617600155600254161760025560405161198990816100e38239f35b600080fd5b634e487b7160e01b600052604160045260246000fdfe608080604052600436101561001357600080fd5b600090813560e01c908163077d17f8146112fa5750806312d43a51146112d35780631c4695f4146111485780634242bac01461111f57806347e7ef2414610d915780634a4a7b0414610d685780634d2ccfd814610c89578063597a0e3614610c6057806360465d1114610c375780637c4283bc14610c1a578063b931db6d1461065d578063cfad57a2146105d8578063f3fef3a3146100e65763fc833ac6146100bb57600080fd5b346100e357806003193601126100e35760206040516000805160206119348339815191528152f35b80fd5b50346100e35760403660031901126100e35761010061131f565b602435906127106101128184116118c8565b600354604051634f129c5360e01b81526001600160a01b038481166004830152909160209183916024918391165afa80156105cd5761015891869161059e575b506118fe565b60055460405163f8b2cb4f60e01b81526001600160a01b0384811660048301529092911690602083602481855afa92831561040c57869361056a575b5060405163ee39b63760e01b81526001600160a01b0385166004820152602081602481865afa90811561055f57879161052d575b5083151580610524575b156104f657604051636805d6ad60e01b81526001600160a01b0386166004820152336024820152879290602081604481885afa9081156104ae5784916104c1575b508088116104b9575b506040516302b916f760e51b81526001600160a01b0387166004820152602081602481885afa9081156104ae578491610475575b509061025f61027a928961147b565b049461027561026e878a611458565b938961147b565b61148e565b92803b1561043a57604051630963ccad60e11b815290839082908183816102a68a338e600485016114ae565b03925af1908115610456578391610461575b50506005546001600160a01b0316803b1561043a57826040518092631c83b8df60e21b82528183816102ee888d6004840161143d565b03925af190811561045657839161043e575b50506004546001600160a01b0316803b1561043a5760405163078d3b7960e01b8152918391839182908490829061033c90338d600485016114ae565b03925af1801561042f57610417575b505060055460405163f8b2cb4f60e01b81526001600160a01b03858116600483015290939160209185916024918391165afa92831561040c5786936103d3575b5060405194855260208501526040840152606083015260018060a01b0316907fae04f501857d63b8ca31ec171decfe6513ab9113a08210fc4acc3403190e0df960803392a380f35b9092506020813d602011610404575b816103ef60209383611375565b810103126103ff5751913861038b565b600080fd5b3d91506103e2565b6040513d88823e3d90fd5b6104209061134b565b61042b57843861034b565b8480fd5b6040513d84823e3d90fd5b8280fd5b6104479061134b565b610452578138610300565b5080fd5b6040513d85823e3d90fd5b61046a9061134b565b6104525781386102b8565b919350506020813d6020116104a6575b8161049260209383611375565b810103126103ff575187929061025f610250565b3d9150610485565b6040513d86823e3d90fd5b96503861021c565b9350506020833d6020116104ee575b816104dd60209383611375565b810103126103ff5787925138610213565b3d91506104d0565b60405162461bcd60e51b815260206004820152600660248201526521656d70747960d01b6044820152606490fd5b508015156101d2565b90506020813d602011610557575b8161054860209383611375565b810103126103ff5751386101c8565b3d915061053b565b6040513d89823e3d90fd5b9092506020813d602011610596575b8161058660209383611375565b810103126103ff57519138610194565b3d9150610579565b6105c0915060203d6020116105c6575b6105b88183611375565b8101906113e8565b38610152565b503d6105ae565b6040513d87823e3d90fd5b50346100e35760203660031901126100e3577f53351836099c03ffc3b1727d8abd4b0222afa87d4ed76ae3102d51369ef7f78561061361131f565b82546001600160a01b03808216919061062d338414611397565b83166001600160a01b031991909116178455604080516001600160a01b039283168152919092166020820152a180f35b50346100e35760803660031901126100e35761067761131f565b90610680611335565b916044359267ffffffffffffffff8085116109a057366023860112156109a0578460040135908111610c0657604051946106c4601f8301601f191660200187611375565b818652366024838301011161042b57818592602460209301838901378601015260015460405163ac4ab3fb60e01b8152336004820152600080516020611934833981519152602482015290602090829060449082906001600160a01b03165afa9081156104ae579061073d918591610be7575b50611400565b6005546001600160a01b0316803b156109a05783604051809263de900ab960e01b8252818381610773606435896004840161143d565b03925af180156104ae57908491610bd3575b5050600554604051631d683d8f60e11b81526001600160a01b0383811660048301529091169190602081602481865afa9081156105cd578591610ba1575b508492816109a45750506005546001600160a01b0316803b1561042b5784604051809263473cc2af60e01b825281838161080142896004840161143d565b03925af180156105cd5790859161098c575b50505b60055460405163f8b2cb4f60e01b81526001600160a01b03838116600483015290929116602083602481845afa92831561040c578693610957575b50604051634021fe0f60e01b81526001600160a01b038316600482015290602090829060249082905afa90811561040c578691610925575b506040519260a084528751948560a0860152875b86811061090f57509260c09285949285938a868a7fa23af116f782ad07f8010bd150b57bb7084c718271e5aa4bdab61a8be2986b059a010152606435602086015260408501526060840152608083015260018060a01b03169560018060a01b031694601f80199101168101030190a380f35b80602080928c01015160c082890101520161089d565b90506020813d60201161094f575b8161094060209383611375565b810103126103ff575138610889565b3d9150610933565b9092506020813d602011610984575b8161097360209383611375565b810103126103ff5751916020610851565b3d9150610966565b6109959061134b565b6109a0578338610813565b8380fd5b604051634021fe0f60e01b81526001600160a01b0384166004820152935090602084602481855afa93841561040c578694610b6d575b506040516359bca66760e01b815290602082600481865afa91821561055f578792610b37575b5090610275610a12610a189342611458565b8661147b565b92808411610b2f575b50803b1561042b57846040518092631c25e23360e11b8252818381610a4a89896004840161143d565b03925af180156105cd57908591610b1b575b50506005546001600160a01b0316803b1561042b57846040518092637a8b01ef60e11b8252818381610a9289896004840161143d565b03925af180156105cd57908591610b07575b50506005546001600160a01b0316803b1561042b5784604051809263473cc2af60e01b8252818381610ada42896004840161143d565b03925af180156105cd57908591610af3575b5050610816565b610afc9061134b565b6109a0578338610aec565b610b109061134b565b6109a0578338610aa4565b610b249061134b565b6109a0578338610a5c565b925038610a21565b91506020823d602011610b65575b81610b5260209383611375565b810103126103ff57905190610275610a00565b3d9150610b45565b9093506020813d602011610b99575b81610b8960209383611375565b810103126103ff575192386109da565b3d9150610b7c565b90506020813d602011610bcb575b81610bbc60209383611375565b810103126103ff5751386107c3565b3d9150610baf565b610bdc9061134b565b61043a578238610785565b610c00915060203d6020116105c6576105b88183611375565b38610737565b634e487b7160e01b84526041600452602484fd5b50346100e357806003193601126100e35760206040516127108152f35b50346100e357806003193601126100e3576005546040516001600160a01b039091168152602090f35b50346100e357806003193601126100e3576003546040516001600160a01b039091168152602090f35b50346100e35760803660031901126100e357610ca361131f565b610cab611335565b906044359067ffffffffffffffff9081831161042b573660238401121561042b57826004013591821161042b57366024838501011161042b5760015460405163ac4ab3fb60e01b815233600482015260008051602061193483398151915260248201529490602090869060449082906001600160a01b03165afa94851561040c57610d4d95610d40918891610d505750611400565b60246064359401916114d0565b80f35b610c00915060203d81116105c6576105b88183611375565b50346100e357806003193601126100e3576001546040516001600160a01b039091168152602090f35b5060403660031901126100e357610da661131f565b60243590610db58215156118c8565b60018060a01b0390816003541692604051634f129c5360e01b8152808484169586600483015281602460209485935afa801561055f57610dfb91889161110857506118fe565b83600554169260405192828460248163f8b2cb4f60e01b988982528b60048301525afa9384156110fd5788946110ce575b508661106857503494878160045416803b156104525781604051809263e4652f4960e01b8252818b81610e6482338c600485016114ae565b03925af1801561042f57611054575b50505b878160055416946040519063ee39b63760e01b825289600483015285826024818a5afa918215610456578392611022575b508015801561101a575b1561100757505086945b803b1561045257816040518092637ecad97360e11b8252818381610ee48c338c600485016114ae565b03925af1801561042f57610fef575b508160055416803b1561045257878291610f249583604051809881958294631c25e23360e11b84526004840161143d565b03925af1928315610fe2578493610fc5575b5050600554169360246040518096819382528960048301525afa92831561040c578693610f96575b5060405193845283015260408201527f476bb75dda88c17897f99c2de3be0f64f242ac9b025839a6f3759b9fe9751b9660603392a380f35b9080935081813d8311610fbe575b610fae8183611375565b810103126103ff57519138610f5e565b503d610fa4565b610fd19192935061134b565b610fde5781908738610f36565b8680fd5b50604051903d90823e3d90fd5b610ff89061134b565b611003578738610ef3565b8780fd5b610275611014928a61147b565b94610ebb565b508115610eb1565b925090508482813d811161104d575b61103b8183611375565b810103126103ff578991519038610ea7565b503d611031565b61105d9061134b565b611003578738610e73565b948060045416803b156110ca5788604051809263e4652f4960e01b82528183816110978d338b600485016114ae565b03925af180156110bf576110ac575b50610e76565b6110b89098919861134b565b96386110a6565b6040513d8b823e3d90fd5b8880fd5b9093508281813d83116110f6575b6110e68183611375565b8101031261100357519238610e2c565b503d6110dc565b6040513d8a823e3d90fd5b6105c09150833d85116105c6576105b88183611375565b50346100e357806003193601126100e3576002546040516001600160a01b039091168152602090f35b50346100e357806003193601126100e35780546001600160a01b03906111719082163314611397565b60025460405163bf40fac160e01b808252602060048301819052600a602484015269417373657453746f726560b01b60448401529193928316908285606481855afa94851561040c5786956112b4575b508360018060a01b0319951685600354161760035560405190808252836004830152600960248301526846756e6453746f726560b81b60448301528382606481865afa91821561055f57849286918991611297575b501686600454161760045560646040518094819382528460048301526009602483015268506f6f6c53746f726560b81b60448301525afa9182156105cd57859261126a575b50501690600554161760055580f35b6112899250803d10611290575b6112818183611375565b8101906113c9565b388061125b565b503d611277565b6112ae9150843d8611611290576112818183611375565b38611216565b6112cc919550833d8511611290576112818183611375565b93386111c1565b50346100e357806003193601126100e357546040516001600160a01b039091168152602090f35b9050346104525781600319360112610452576004546001600160a01b03168152602090f35b600435906001600160a01b03821682036103ff57565b602435906001600160a01b03821682036103ff57565b67ffffffffffffffff811161135f57604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff82111761135f57604052565b1561139e57565b606460405162461bcd60e51b815260206004820152600460248201526310b3b7bb60e11b6044820152fd5b908160209103126103ff57516001600160a01b03811681036103ff5790565b908160209103126103ff575180151581036103ff5790565b1561140757565b60405162461bcd60e51b815260206004820152600e60248201526d21636f6e74726163742d726f6c6560901b6044820152606490fd5b6001600160a01b039091168152602081019190915260400190565b9190820391821161146557565b634e487b7160e01b600052601160045260246000fd5b8181029291811591840414171561146557565b8115611498570490565b634e487b7160e01b600052601260045260246000fd5b6001600160a01b03918216815291166020820152604081019190915260600190565b949390929160009582156118bf5760018060a01b039081600554166040908151634021fe0f60e01b808252858a16996004928b848201528d6020958683602481845afa9283156118b5578293611886575b50803b156104525761154a82918d8a51948580948193637a8b01ef60e11b83528a8d840161143d565b03925af1801561187a5761185d575b5090818e96959493928b1161173f575b5087835416803b15610fde578a87918983611599958a519687958694859363078d3b7960e01b85528c85016114ae565b03925af1801561173557908691611721575b50508660055416845163f8b2cb4f60e01b81528c848201528481602481855afa96871561171657908d97969594939291966116de575b508392916024918651988994859384528301525afa9384156116d4579b899a9b9c819a999a9561166e575b509882917f3092724f7adc895c13332959eb9d68277692c0f667f5c166c06996dfd6f21e2d9a60a0999897969594519a8b9960808b528160808c01528b8b0137888d018a015287015285015260608401521694601f01601f19168101030190a3565b82809a50819998979650919493923d83116116cd575b61168e8183611375565b810103126103ff577f3092724f7adc895c13332959eb9d68277692c0f667f5c166c06996dfd6f21e2d988a9860a098519596979850919293909961160c565b503d611684565b82513d8e823e3d90fd5b96509450908286813d811161170f575b6116f88183611375565b810103126103ff5794518b959094909190836115e1565b503d6116ee565b8651903d90823e3d90fd5b61172a9061134b565b61042b5784386115ab565b85513d88823e3d90fd5b61174f919293949596508a611458565b8d8860055416908d88519063f8b2cb4f60e01b8252878201528781602481865afa9182156118525791611825575b508210156117f25790818f9796959493923b15611003578651631c83b8df60e21b815291889183918290849082906117b890898c840161143d565b03925af180156117e8579087916117d0575b50611569565b6117d99061134b565b6117e45785386117ca565b8580fd5b86513d89823e3d90fd5b865162461bcd60e51b8152808601879052600d60248201526c21706f6f6c2d62616c616e636560981b6044820152606490fd5b90508681813d831161184b575b61183c8183611375565b810103126103ff57513861177d565b503d611832565b8951903d90823e3d90fd5b61186e909e9196959493929e61134b565b9c909192939438611559565b8f8851903d90823e3d90fd5b9092508681813d83116118ae575b61189e8183611375565b8101031261045257519138611521565b503d611894565b88513d84823e3d90fd5b50505050509050565b156118cf57565b60405162461bcd60e51b815260206004820152600760248201526608585b5bdd5b9d60ca1b6044820152606490fd5b1561190557565b60405162461bcd60e51b815260206004820152600660248201526508585cdcd95d60d21b6044820152606490fdfea66b7a3e6b19d24ccb6f717fc232a1bb0278a7f83f8e2211835fc4ed0fe69f19a264697066735822122014ba47cb85200fa58e8e87c368ef3da313cf73554d91ed51421254971365703d64736f6c63430008110033000000000000000000000000e5da4704a582fe799dcd1dff31dc2ed2e0bdc961000000000000000000000000a64694e51b22a081ea1e4051ef4ea1b715b47026
Deployed Bytecode
0x608080604052600436101561001357600080fd5b600090813560e01c908163077d17f8146112fa5750806312d43a51146112d35780631c4695f4146111485780634242bac01461111f57806347e7ef2414610d915780634a4a7b0414610d685780634d2ccfd814610c89578063597a0e3614610c6057806360465d1114610c375780637c4283bc14610c1a578063b931db6d1461065d578063cfad57a2146105d8578063f3fef3a3146100e65763fc833ac6146100bb57600080fd5b346100e357806003193601126100e35760206040516000805160206119348339815191528152f35b80fd5b50346100e35760403660031901126100e35761010061131f565b602435906127106101128184116118c8565b600354604051634f129c5360e01b81526001600160a01b038481166004830152909160209183916024918391165afa80156105cd5761015891869161059e575b506118fe565b60055460405163f8b2cb4f60e01b81526001600160a01b0384811660048301529092911690602083602481855afa92831561040c57869361056a575b5060405163ee39b63760e01b81526001600160a01b0385166004820152602081602481865afa90811561055f57879161052d575b5083151580610524575b156104f657604051636805d6ad60e01b81526001600160a01b0386166004820152336024820152879290602081604481885afa9081156104ae5784916104c1575b508088116104b9575b506040516302b916f760e51b81526001600160a01b0387166004820152602081602481885afa9081156104ae578491610475575b509061025f61027a928961147b565b049461027561026e878a611458565b938961147b565b61148e565b92803b1561043a57604051630963ccad60e11b815290839082908183816102a68a338e600485016114ae565b03925af1908115610456578391610461575b50506005546001600160a01b0316803b1561043a57826040518092631c83b8df60e21b82528183816102ee888d6004840161143d565b03925af190811561045657839161043e575b50506004546001600160a01b0316803b1561043a5760405163078d3b7960e01b8152918391839182908490829061033c90338d600485016114ae565b03925af1801561042f57610417575b505060055460405163f8b2cb4f60e01b81526001600160a01b03858116600483015290939160209185916024918391165afa92831561040c5786936103d3575b5060405194855260208501526040840152606083015260018060a01b0316907fae04f501857d63b8ca31ec171decfe6513ab9113a08210fc4acc3403190e0df960803392a380f35b9092506020813d602011610404575b816103ef60209383611375565b810103126103ff5751913861038b565b600080fd5b3d91506103e2565b6040513d88823e3d90fd5b6104209061134b565b61042b57843861034b565b8480fd5b6040513d84823e3d90fd5b8280fd5b6104479061134b565b610452578138610300565b5080fd5b6040513d85823e3d90fd5b61046a9061134b565b6104525781386102b8565b919350506020813d6020116104a6575b8161049260209383611375565b810103126103ff575187929061025f610250565b3d9150610485565b6040513d86823e3d90fd5b96503861021c565b9350506020833d6020116104ee575b816104dd60209383611375565b810103126103ff5787925138610213565b3d91506104d0565b60405162461bcd60e51b815260206004820152600660248201526521656d70747960d01b6044820152606490fd5b508015156101d2565b90506020813d602011610557575b8161054860209383611375565b810103126103ff5751386101c8565b3d915061053b565b6040513d89823e3d90fd5b9092506020813d602011610596575b8161058660209383611375565b810103126103ff57519138610194565b3d9150610579565b6105c0915060203d6020116105c6575b6105b88183611375565b8101906113e8565b38610152565b503d6105ae565b6040513d87823e3d90fd5b50346100e35760203660031901126100e3577f53351836099c03ffc3b1727d8abd4b0222afa87d4ed76ae3102d51369ef7f78561061361131f565b82546001600160a01b03808216919061062d338414611397565b83166001600160a01b031991909116178455604080516001600160a01b039283168152919092166020820152a180f35b50346100e35760803660031901126100e35761067761131f565b90610680611335565b916044359267ffffffffffffffff8085116109a057366023860112156109a0578460040135908111610c0657604051946106c4601f8301601f191660200187611375565b818652366024838301011161042b57818592602460209301838901378601015260015460405163ac4ab3fb60e01b8152336004820152600080516020611934833981519152602482015290602090829060449082906001600160a01b03165afa9081156104ae579061073d918591610be7575b50611400565b6005546001600160a01b0316803b156109a05783604051809263de900ab960e01b8252818381610773606435896004840161143d565b03925af180156104ae57908491610bd3575b5050600554604051631d683d8f60e11b81526001600160a01b0383811660048301529091169190602081602481865afa9081156105cd578591610ba1575b508492816109a45750506005546001600160a01b0316803b1561042b5784604051809263473cc2af60e01b825281838161080142896004840161143d565b03925af180156105cd5790859161098c575b50505b60055460405163f8b2cb4f60e01b81526001600160a01b03838116600483015290929116602083602481845afa92831561040c578693610957575b50604051634021fe0f60e01b81526001600160a01b038316600482015290602090829060249082905afa90811561040c578691610925575b506040519260a084528751948560a0860152875b86811061090f57509260c09285949285938a868a7fa23af116f782ad07f8010bd150b57bb7084c718271e5aa4bdab61a8be2986b059a010152606435602086015260408501526060840152608083015260018060a01b03169560018060a01b031694601f80199101168101030190a380f35b80602080928c01015160c082890101520161089d565b90506020813d60201161094f575b8161094060209383611375565b810103126103ff575138610889565b3d9150610933565b9092506020813d602011610984575b8161097360209383611375565b810103126103ff5751916020610851565b3d9150610966565b6109959061134b565b6109a0578338610813565b8380fd5b604051634021fe0f60e01b81526001600160a01b0384166004820152935090602084602481855afa93841561040c578694610b6d575b506040516359bca66760e01b815290602082600481865afa91821561055f578792610b37575b5090610275610a12610a189342611458565b8661147b565b92808411610b2f575b50803b1561042b57846040518092631c25e23360e11b8252818381610a4a89896004840161143d565b03925af180156105cd57908591610b1b575b50506005546001600160a01b0316803b1561042b57846040518092637a8b01ef60e11b8252818381610a9289896004840161143d565b03925af180156105cd57908591610b07575b50506005546001600160a01b0316803b1561042b5784604051809263473cc2af60e01b8252818381610ada42896004840161143d565b03925af180156105cd57908591610af3575b5050610816565b610afc9061134b565b6109a0578338610aec565b610b109061134b565b6109a0578338610aa4565b610b249061134b565b6109a0578338610a5c565b925038610a21565b91506020823d602011610b65575b81610b5260209383611375565b810103126103ff57905190610275610a00565b3d9150610b45565b9093506020813d602011610b99575b81610b8960209383611375565b810103126103ff575192386109da565b3d9150610b7c565b90506020813d602011610bcb575b81610bbc60209383611375565b810103126103ff5751386107c3565b3d9150610baf565b610bdc9061134b565b61043a578238610785565b610c00915060203d6020116105c6576105b88183611375565b38610737565b634e487b7160e01b84526041600452602484fd5b50346100e357806003193601126100e35760206040516127108152f35b50346100e357806003193601126100e3576005546040516001600160a01b039091168152602090f35b50346100e357806003193601126100e3576003546040516001600160a01b039091168152602090f35b50346100e35760803660031901126100e357610ca361131f565b610cab611335565b906044359067ffffffffffffffff9081831161042b573660238401121561042b57826004013591821161042b57366024838501011161042b5760015460405163ac4ab3fb60e01b815233600482015260008051602061193483398151915260248201529490602090869060449082906001600160a01b03165afa94851561040c57610d4d95610d40918891610d505750611400565b60246064359401916114d0565b80f35b610c00915060203d81116105c6576105b88183611375565b50346100e357806003193601126100e3576001546040516001600160a01b039091168152602090f35b5060403660031901126100e357610da661131f565b60243590610db58215156118c8565b60018060a01b0390816003541692604051634f129c5360e01b8152808484169586600483015281602460209485935afa801561055f57610dfb91889161110857506118fe565b83600554169260405192828460248163f8b2cb4f60e01b988982528b60048301525afa9384156110fd5788946110ce575b508661106857503494878160045416803b156104525781604051809263e4652f4960e01b8252818b81610e6482338c600485016114ae565b03925af1801561042f57611054575b50505b878160055416946040519063ee39b63760e01b825289600483015285826024818a5afa918215610456578392611022575b508015801561101a575b1561100757505086945b803b1561045257816040518092637ecad97360e11b8252818381610ee48c338c600485016114ae565b03925af1801561042f57610fef575b508160055416803b1561045257878291610f249583604051809881958294631c25e23360e11b84526004840161143d565b03925af1928315610fe2578493610fc5575b5050600554169360246040518096819382528960048301525afa92831561040c578693610f96575b5060405193845283015260408201527f476bb75dda88c17897f99c2de3be0f64f242ac9b025839a6f3759b9fe9751b9660603392a380f35b9080935081813d8311610fbe575b610fae8183611375565b810103126103ff57519138610f5e565b503d610fa4565b610fd19192935061134b565b610fde5781908738610f36565b8680fd5b50604051903d90823e3d90fd5b610ff89061134b565b611003578738610ef3565b8780fd5b610275611014928a61147b565b94610ebb565b508115610eb1565b925090508482813d811161104d575b61103b8183611375565b810103126103ff578991519038610ea7565b503d611031565b61105d9061134b565b611003578738610e73565b948060045416803b156110ca5788604051809263e4652f4960e01b82528183816110978d338b600485016114ae565b03925af180156110bf576110ac575b50610e76565b6110b89098919861134b565b96386110a6565b6040513d8b823e3d90fd5b8880fd5b9093508281813d83116110f6575b6110e68183611375565b8101031261100357519238610e2c565b503d6110dc565b6040513d8a823e3d90fd5b6105c09150833d85116105c6576105b88183611375565b50346100e357806003193601126100e3576002546040516001600160a01b039091168152602090f35b50346100e357806003193601126100e35780546001600160a01b03906111719082163314611397565b60025460405163bf40fac160e01b808252602060048301819052600a602484015269417373657453746f726560b01b60448401529193928316908285606481855afa94851561040c5786956112b4575b508360018060a01b0319951685600354161760035560405190808252836004830152600960248301526846756e6453746f726560b81b60448301528382606481865afa91821561055f57849286918991611297575b501686600454161760045560646040518094819382528460048301526009602483015268506f6f6c53746f726560b81b60448301525afa9182156105cd57859261126a575b50501690600554161760055580f35b6112899250803d10611290575b6112818183611375565b8101906113c9565b388061125b565b503d611277565b6112ae9150843d8611611290576112818183611375565b38611216565b6112cc919550833d8511611290576112818183611375565b93386111c1565b50346100e357806003193601126100e357546040516001600160a01b039091168152602090f35b9050346104525781600319360112610452576004546001600160a01b03168152602090f35b600435906001600160a01b03821682036103ff57565b602435906001600160a01b03821682036103ff57565b67ffffffffffffffff811161135f57604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff82111761135f57604052565b1561139e57565b606460405162461bcd60e51b815260206004820152600460248201526310b3b7bb60e11b6044820152fd5b908160209103126103ff57516001600160a01b03811681036103ff5790565b908160209103126103ff575180151581036103ff5790565b1561140757565b60405162461bcd60e51b815260206004820152600e60248201526d21636f6e74726163742d726f6c6560901b6044820152606490fd5b6001600160a01b039091168152602081019190915260400190565b9190820391821161146557565b634e487b7160e01b600052601160045260246000fd5b8181029291811591840414171561146557565b8115611498570490565b634e487b7160e01b600052601260045260246000fd5b6001600160a01b03918216815291166020820152604081019190915260600190565b949390929160009582156118bf5760018060a01b039081600554166040908151634021fe0f60e01b808252858a16996004928b848201528d6020958683602481845afa9283156118b5578293611886575b50803b156104525761154a82918d8a51948580948193637a8b01ef60e11b83528a8d840161143d565b03925af1801561187a5761185d575b5090818e96959493928b1161173f575b5087835416803b15610fde578a87918983611599958a519687958694859363078d3b7960e01b85528c85016114ae565b03925af1801561173557908691611721575b50508660055416845163f8b2cb4f60e01b81528c848201528481602481855afa96871561171657908d97969594939291966116de575b508392916024918651988994859384528301525afa9384156116d4579b899a9b9c819a999a9561166e575b509882917f3092724f7adc895c13332959eb9d68277692c0f667f5c166c06996dfd6f21e2d9a60a0999897969594519a8b9960808b528160808c01528b8b0137888d018a015287015285015260608401521694601f01601f19168101030190a3565b82809a50819998979650919493923d83116116cd575b61168e8183611375565b810103126103ff577f3092724f7adc895c13332959eb9d68277692c0f667f5c166c06996dfd6f21e2d988a9860a098519596979850919293909961160c565b503d611684565b82513d8e823e3d90fd5b96509450908286813d811161170f575b6116f88183611375565b810103126103ff5794518b959094909190836115e1565b503d6116ee565b8651903d90823e3d90fd5b61172a9061134b565b61042b5784386115ab565b85513d88823e3d90fd5b61174f919293949596508a611458565b8d8860055416908d88519063f8b2cb4f60e01b8252878201528781602481865afa9182156118525791611825575b508210156117f25790818f9796959493923b15611003578651631c83b8df60e21b815291889183918290849082906117b890898c840161143d565b03925af180156117e8579087916117d0575b50611569565b6117d99061134b565b6117e45785386117ca565b8580fd5b86513d89823e3d90fd5b865162461bcd60e51b8152808601879052600d60248201526c21706f6f6c2d62616c616e636560981b6044820152606490fd5b90508681813d831161184b575b61183c8183611375565b810103126103ff57513861177d565b503d611832565b8951903d90823e3d90fd5b61186e909e9196959493929e61134b565b9c909192939438611559565b8f8851903d90823e3d90fd5b9092508681813d83116118ae575b61189e8183611375565b8101031261045257519138611521565b503d611894565b88513d84823e3d90fd5b50505050509050565b156118cf57565b60405162461bcd60e51b815260206004820152600760248201526608585b5bdd5b9d60ca1b6044820152606490fd5b1561190557565b60405162461bcd60e51b815260206004820152600660248201526508585cdcd95d60d21b6044820152606490fdfea66b7a3e6b19d24ccb6f717fc232a1bb0278a7f83f8e2211835fc4ed0fe69f19a264697066735822122014ba47cb85200fa58e8e87c368ef3da313cf73554d91ed51421254971365703d64736f6c63430008110033
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
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
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.