Latest 25 from a total of 11,860 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Create Split | 42143683 | 26 hrs ago | IN | 0 ETH | 0.00000056 | ||||
| Withdraw | 41905449 | 6 days ago | IN | 0 ETH | 0.00000025 | ||||
| Withdraw | 41826792 | 8 days ago | IN | 0 ETH | 0.00000025 | ||||
| Create Split | 41812057 | 8 days ago | IN | 0 ETH | 0.0000008 | ||||
| Withdraw | 41772150 | 9 days ago | IN | 0 ETH | 0.00000045 | ||||
| Withdraw | 41658729 | 12 days ago | IN | 0 ETH | 0.00000101 | ||||
| Withdraw | 41658726 | 12 days ago | IN | 0 ETH | 0.00000102 | ||||
| Withdraw | 41415907 | 17 days ago | IN | 0 ETH | 0.00000047 | ||||
| Withdraw | 41358506 | 19 days ago | IN | 0 ETH | 0.00000043 | ||||
| Withdraw | 41358051 | 19 days ago | IN | 0 ETH | 0.00000042 | ||||
| Withdraw | 41357742 | 19 days ago | IN | 0 ETH | 0.00000068 | ||||
| Withdraw | 41357641 | 19 days ago | IN | 0 ETH | 0.00000029 | ||||
| Create Split | 40975927 | 28 days ago | IN | 0 ETH | 0.00000066 | ||||
| Distribute ETH | 40959983 | 28 days ago | IN | 0 ETH | 0.00000018 | ||||
| Create Split | 40645803 | 35 days ago | IN | 0 ETH | 0.00000016 | ||||
| Withdraw | 40633213 | 36 days ago | IN | 0 ETH | 0.00000013 | ||||
| Withdraw | 40549245 | 37 days ago | IN | 0 ETH | 0.00000054 | ||||
| Withdraw | 40205864 | 45 days ago | IN | 0 ETH | 0.00000025 | ||||
| Withdraw | 40137177 | 47 days ago | IN | 0 ETH | 0.00000008 | ||||
| Withdraw | 39924124 | 52 days ago | IN | 0 ETH | 0.00000002 | ||||
| Distribute ETH | 39783106 | 55 days ago | IN | 0 ETH | 0.0000001 | ||||
| Withdraw | 39782438 | 55 days ago | IN | 0 ETH | 0.00000007 | ||||
| Withdraw | 39772230 | 55 days ago | IN | 0 ETH | 0.0000002 | ||||
| Withdraw | 39748993 | 56 days ago | IN | 0 ETH | 0.00000006 | ||||
| Distribute ERC20 | 39707365 | 57 days ago | IN | 0 ETH | 0.00000005 |
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 42143683 | 26 hrs ago | Contract Creation | 0 ETH | |||
| 42124177 | 36 hrs ago | Contract Creation | 0 ETH | |||
| 41923562 | 6 days ago | Contract Creation | 0 ETH | |||
| 41905449 | 6 days ago | 0.00071427 ETH | ||||
| 41899760 | 6 days ago | 0.00050767 ETH | ||||
| 41899760 | 6 days ago | 0.0007615 ETH | ||||
| 41899760 | 6 days ago | 0.00126917 ETH | ||||
| 41826792 | 8 days ago | 0.00041624 ETH | ||||
| 41812057 | 8 days ago | Contract Creation | 0 ETH | |||
| 41772150 | 9 days ago | 0.0029715 ETH | ||||
| 41596707 | 13 days ago | 0.00173333 ETH | ||||
| 41596707 | 13 days ago | 0.0052 ETH | ||||
| 41477160 | 16 days ago | Contract Creation | 0 ETH | |||
| 41471435 | 16 days ago | Contract Creation | 0 ETH | |||
| 41415907 | 17 days ago | 0.0000899 ETH | ||||
| 41397103 | 18 days ago | Contract Creation | 0 ETH | |||
| 41397027 | 18 days ago | Contract Creation | 0 ETH | |||
| 41377730 | 18 days ago | 0.00028386 ETH | ||||
| 41377729 | 18 days ago | 0.00028386 ETH | ||||
| 41377729 | 18 days ago | 0.00028386 ETH | ||||
| 41358487 | 19 days ago | 1.1026599 ETH | ||||
| 41358487 | 19 days ago | 2.2053198 ETH | ||||
| 41235121 | 22 days ago | 0.00022249 ETH | ||||
| 41235121 | 22 days ago | 0.00033374 ETH | ||||
| 41235121 | 22 days ago | 0.00055623 ETH |
Cross-Chain Transactions
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
SplitMain
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;
import {ISplitMain} from 'contracts/interfaces/ISplitMain.sol';
import {SplitWallet} from 'contracts/SplitWallet.sol';
import {Clones} from 'contracts/libraries/Clones.sol';
import {ERC20} from '@rari-capital/solmate/src/tokens/ERC20.sol';
import {SafeTransferLib} from '@rari-capital/solmate/src/utils/SafeTransferLib.sol';
/**
█████████
███████████████ █████████
█████████████████ █████████████ ███████
███████████████████ ███████████████ █████████
███████████████████ ███████████████ ███████████
███████████████████ ███████████████ █████████
█████████████████ █████████████ ███████
███████████████ █████████
█████████
███████████
█████████████████ █████████
███████████████████ ███████████████ █████████
█████████████████████ █████████████████ █████████████ ███████
███████████████████████ ███████████████████ ███████████████ █████████
███████████████████████ ███████████████████ ███████████████ ███████████
███████████████████████ ███████████████████ ███████████████ █████████
█████████████████████ █████████████████ █████████████ ███████
███████████████████ █████████████ █████████
█████████████████ █████████
███████████
███████████
███████████████████ ███████████
███████████████████████ ███████████████ █████████
█████████████████████████ ███████████████████ ███████████████ █████████
███████████████████████████ █████████████████████ █████████████████ █████████████ ███████
███████████████████████████ ███████████████████████ ███████████████████ ███████████████ █████████
███████████████████████████ ███████████████████████ ███████████████████ ███████████████ ███████████
███████████████████████████ ███████████████████████ ███████████████████ ███████████████ █████████
███████████████████████████ █████████████████████ █████████████████ █████████████ ███████
█████████████████████████ ███████████████████ █████████████ █████████
█████████████████████ ███████████████ █████████
█████████████████ ███████████
███████████
███████████
█████████████████ █████████
███████████████████ ███████████████ █████████
█████████████████████ █████████████████ █████████████ ███████
███████████████████████ ███████████████████ ███████████████ █████████
███████████████████████ ███████████████████ ███████████████ ███████████
███████████████████████ ███████████████████ ███████████████ █████████
█████████████████████ █████████████████ █████████████ ███████
███████████████████ █████████████ █████████
█████████████████ █████████
███████████
█████████
███████████████ █████████
█████████████████ █████████████ ███████
███████████████████ ███████████████ █████████
███████████████████ ███████████████ ███████████
███████████████████ ███████████████ █████████
█████████████████ █████████████ ███████
███████████████ █████████
█████████
*/
/**
* ERRORS
*/
/// @notice Unauthorized sender `sender`
/// @param sender Transaction sender
error Unauthorized(address sender);
/// @notice Invalid number of accounts `accountsLength`, must have at least 2
/// @param accountsLength Length of accounts array
error InvalidSplit__TooFewAccounts(uint256 accountsLength);
/// @notice Array lengths of accounts & percentAllocations don't match (`accountsLength` != `allocationsLength`)
/// @param accountsLength Length of accounts array
/// @param allocationsLength Length of percentAllocations array
error InvalidSplit__AccountsAndAllocationsMismatch(
uint256 accountsLength,
uint256 allocationsLength
);
/// @notice Invalid percentAllocations sum `allocationsSum` must equal `PERCENTAGE_SCALE`
/// @param allocationsSum Sum of percentAllocations array
error InvalidSplit__InvalidAllocationsSum(uint32 allocationsSum);
/// @notice Invalid accounts ordering at `index`
/// @param index Index of out-of-order account
error InvalidSplit__AccountsOutOfOrder(uint256 index);
/// @notice Invalid percentAllocation of zero at `index`
/// @param index Index of zero percentAllocation
error InvalidSplit__AllocationMustBePositive(uint256 index);
/// @notice Invalid distributorFee `distributorFee` cannot be greater than 10% (1e5)
/// @param distributorFee Invalid distributorFee amount
error InvalidSplit__InvalidDistributorFee(uint32 distributorFee);
/// @notice Invalid hash `hash` from split data (accounts, percentAllocations, distributorFee)
/// @param hash Invalid hash
error InvalidSplit__InvalidHash(bytes32 hash);
/// @notice Invalid new controlling address `newController` for mutable split
/// @param newController Invalid new controller
error InvalidNewController(address newController);
/**
* @title SplitMain
* @author 0xSplits <[email protected]>
* @notice A composable and gas-efficient protocol for deploying splitter contracts.
* @dev Split recipients, ownerships, and keeper fees are stored onchain as calldata & re-passed as args / validated
* via hashing when needed. Each split gets its own address & proxy for maximum composability with other contracts onchain.
* For these proxies, we extended EIP-1167 Minimal Proxy Contract to avoid `DELEGATECALL` inside `receive()` to accept
* hard gas-capped `sends` & `transfers`.
*/
contract SplitMain is ISplitMain {
using SafeTransferLib for address;
using SafeTransferLib for ERC20;
/**
* STRUCTS
*/
/// @notice holds Split metadata
struct Split {
bytes32 hash;
address controller;
address newPotentialController;
}
/**
* STORAGE
*/
/**
* STORAGE - CONSTANTS & IMMUTABLES
*/
/// @notice constant to scale uints into percentages (1e6 == 100%)
uint256 public constant PERCENTAGE_SCALE = 1e6;
/// @notice maximum distributor fee; 1e5 = 10% * PERCENTAGE_SCALE
uint256 internal constant MAX_DISTRIBUTOR_FEE = 1e5;
/// @notice address of wallet implementation for split proxies
address public immutable override walletImplementation;
/**
* STORAGE - VARIABLES - PRIVATE & INTERNAL
*/
/// @notice mapping to account ETH balances
mapping(address => uint256) internal ethBalances;
/// @notice mapping to account ERC20 balances
mapping(ERC20 => mapping(address => uint256)) internal erc20Balances;
/// @notice mapping to Split metadata
mapping(address => Split) internal splits;
/**
* MODIFIERS
*/
/** @notice Reverts if the sender doesn't own the split `split`
* @param split Address to check for control
*/
modifier onlySplitController(address split) {
if (msg.sender != splits[split].controller) revert Unauthorized(msg.sender);
_;
}
/** @notice Reverts if the sender isn't the new potential controller of split `split`
* @param split Address to check for new potential control
*/
modifier onlySplitNewPotentialController(address split) {
if (msg.sender != splits[split].newPotentialController)
revert Unauthorized(msg.sender);
_;
}
/** @notice Reverts if the split with recipients represented by `accounts` and `percentAllocations` is malformed
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
*/
modifier validSplit(
address[] memory accounts,
uint32[] memory percentAllocations,
uint32 distributorFee
) {
if (accounts.length < 2)
revert InvalidSplit__TooFewAccounts(accounts.length);
if (accounts.length != percentAllocations.length)
revert InvalidSplit__AccountsAndAllocationsMismatch(
accounts.length,
percentAllocations.length
);
// _getSum should overflow if any percentAllocation[i] < 0
if (_getSum(percentAllocations) != PERCENTAGE_SCALE)
revert InvalidSplit__InvalidAllocationsSum(_getSum(percentAllocations));
unchecked {
// overflow should be impossible in for-loop index
// cache accounts length to save gas
uint256 loopLength = accounts.length - 1;
for (uint256 i = 0; i < loopLength; ++i) {
// overflow should be impossible in array access math
if (accounts[i] >= accounts[i + 1])
revert InvalidSplit__AccountsOutOfOrder(i);
if (percentAllocations[i] == uint32(0))
revert InvalidSplit__AllocationMustBePositive(i);
}
// overflow should be impossible in array access math with validated equal array lengths
if (percentAllocations[loopLength] == uint32(0))
revert InvalidSplit__AllocationMustBePositive(loopLength);
}
if (distributorFee > MAX_DISTRIBUTOR_FEE)
revert InvalidSplit__InvalidDistributorFee(distributorFee);
_;
}
/** @notice Reverts if `newController` is the zero address
* @param newController Proposed new controlling address
*/
modifier validNewController(address newController) {
if (newController == address(0)) revert InvalidNewController(newController);
_;
}
/**
* CONSTRUCTOR
*/
constructor() {
walletImplementation = address(new SplitWallet());
}
/**
* FUNCTIONS
*/
/**
* FUNCTIONS - PUBLIC & EXTERNAL
*/
/** @notice Receive ETH
* @dev Used by split proxies in `distributeETH` to transfer ETH to `SplitMain`
* Funds sent outside of `distributeETH` will be unrecoverable
*/
receive() external payable {}
/** @notice Creates a new split with recipients `accounts` with ownerships `percentAllocations`, a keeper fee for splitting of `distributorFee` and the controlling address `controller`
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
* @param controller Controlling address (0x0 if immutable)
* @return split Address of newly created split
*/
function createSplit(
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address controller
)
external
override
validSplit(accounts, percentAllocations, distributorFee)
returns (address split)
{
bytes32 splitHash = _hashSplit(
accounts,
percentAllocations,
distributorFee
);
if (controller == address(0)) {
// create immutable split
split = Clones.cloneDeterministic(walletImplementation, splitHash);
} else {
// create mutable split
split = Clones.clone(walletImplementation);
splits[split].controller = controller;
}
// store split's hash in storage for future verification
splits[split].hash = splitHash;
emit CreateSplit(
split,
accounts,
percentAllocations,
distributorFee,
controller
);
}
/** @notice Predicts the address for an immutable split created with recipients `accounts` with ownerships `percentAllocations` and a keeper fee for splitting of `distributorFee`
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
* @return split Predicted address of such an immutable split
*/
function predictImmutableSplitAddress(
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee
)
external
view
override
validSplit(accounts, percentAllocations, distributorFee)
returns (address split)
{
bytes32 splitHash = _hashSplit(
accounts,
percentAllocations,
distributorFee
);
split = Clones.predictDeterministicAddress(walletImplementation, splitHash);
}
/** @notice Updates an existing split with recipients `accounts` with ownerships `percentAllocations` and a keeper fee for splitting of `distributorFee`
* @param split Address of mutable split to update
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
*/
function updateSplit(
address split,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee
)
external
override
onlySplitController(split)
validSplit(accounts, percentAllocations, distributorFee)
{
_updateSplit(split, accounts, percentAllocations, distributorFee);
}
/** @notice Begins transfer of the controlling address of mutable split `split` to `newController`
* @dev Two-step control transfer inspired by [dharma](https://github.com/dharma-eng/dharma-smart-wallet/blob/master/contracts/helpers/TwoStepOwnable.sol)
* @param split Address of mutable split to transfer control for
* @param newController Address to begin transferring control to
*/
function transferControl(address split, address newController)
external
override
onlySplitController(split)
validNewController(newController)
{
splits[split].newPotentialController = newController;
emit InitiateControlTransfer(split, newController);
}
/** @notice Cancels transfer of the controlling address of mutable split `split`
* @param split Address of mutable split to cancel control transfer for
*/
function cancelControlTransfer(address split)
external
override
onlySplitController(split)
{
delete splits[split].newPotentialController;
emit CancelControlTransfer(split);
}
/** @notice Accepts transfer of the controlling address of mutable split `split`
* @param split Address of mutable split to accept control transfer for
*/
function acceptControl(address split)
external
override
onlySplitNewPotentialController(split)
{
delete splits[split].newPotentialController;
emit ControlTransfer(split, splits[split].controller, msg.sender);
splits[split].controller = msg.sender;
}
/** @notice Turns mutable split `split` immutable
* @param split Address of mutable split to turn immutable
*/
function makeSplitImmutable(address split)
external
override
onlySplitController(split)
{
delete splits[split].newPotentialController;
emit ControlTransfer(split, splits[split].controller, address(0));
splits[split].controller = address(0);
}
/** @notice Distributes the ETH balance for split `split`
* @dev `accounts`, `percentAllocations`, and `distributorFee` are verified by hashing
* & comparing to the hash in storage associated with split `split`
* @param split Address of split to distribute balance for
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
* @param distributorAddress Address to pay `distributorFee` to
*/
function distributeETH(
address split,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
) external override validSplit(accounts, percentAllocations, distributorFee) {
// use internal fn instead of modifier to avoid stack depth compiler errors
_validSplitHash(split, accounts, percentAllocations, distributorFee);
_distributeETH(
split,
accounts,
percentAllocations,
distributorFee,
distributorAddress
);
}
/** @notice Updates & distributes the ETH balance for split `split`
* @dev only callable by SplitController
* @param split Address of split to distribute balance for
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
* @param distributorAddress Address to pay `distributorFee` to
*/
function updateAndDistributeETH(
address split,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
)
external
override
onlySplitController(split)
validSplit(accounts, percentAllocations, distributorFee)
{
_updateSplit(split, accounts, percentAllocations, distributorFee);
// know splitHash is valid immediately after updating; only accessible via controller
_distributeETH(
split,
accounts,
percentAllocations,
distributorFee,
distributorAddress
);
}
/** @notice Distributes the ERC20 `token` balance for split `split`
* @dev `accounts`, `percentAllocations`, and `distributorFee` are verified by hashing
* & comparing to the hash in storage associated with split `split`
* @dev pernicious ERC20s may cause overflow in this function inside
* _scaleAmountByPercentage, but results do not affect ETH & other ERC20 balances
* @param split Address of split to distribute balance for
* @param token Address of ERC20 to distribute balance for
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
* @param distributorAddress Address to pay `distributorFee` to
*/
function distributeERC20(
address split,
ERC20 token,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
) external override validSplit(accounts, percentAllocations, distributorFee) {
// use internal fn instead of modifier to avoid stack depth compiler errors
_validSplitHash(split, accounts, percentAllocations, distributorFee);
_distributeERC20(
split,
token,
accounts,
percentAllocations,
distributorFee,
distributorAddress
);
}
/** @notice Updates & distributes the ERC20 `token` balance for split `split`
* @dev only callable by SplitController
* @dev pernicious ERC20s may cause overflow in this function inside
* _scaleAmountByPercentage, but results do not affect ETH & other ERC20 balances
* @param split Address of split to distribute balance for
* @param token Address of ERC20 to distribute balance for
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
* @param distributorAddress Address to pay `distributorFee` to
*/
function updateAndDistributeERC20(
address split,
ERC20 token,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
)
external
override
onlySplitController(split)
validSplit(accounts, percentAllocations, distributorFee)
{
_updateSplit(split, accounts, percentAllocations, distributorFee);
// know splitHash is valid immediately after updating; only accessible via controller
_distributeERC20(
split,
token,
accounts,
percentAllocations,
distributorFee,
distributorAddress
);
}
/** @notice Withdraw ETH &/ ERC20 balances for account `account`
* @param account Address to withdraw on behalf of
* @param withdrawETH Withdraw all ETH if nonzero
* @param tokens Addresses of ERC20s to withdraw
*/
function withdraw(
address account,
uint256 withdrawETH,
ERC20[] calldata tokens
) external override {
uint256[] memory tokenAmounts = new uint256[](tokens.length);
uint256 ethAmount;
if (withdrawETH != 0) {
ethAmount = _withdraw(account);
}
unchecked {
// overflow should be impossible in for-loop index
for (uint256 i = 0; i < tokens.length; ++i) {
// overflow should be impossible in array length math
tokenAmounts[i] = _withdrawERC20(account, tokens[i]);
}
emit Withdrawal(account, ethAmount, tokens, tokenAmounts);
}
}
/**
* FUNCTIONS - VIEWS
*/
/** @notice Returns the current hash of split `split`
* @param split Split to return hash for
* @return Split's hash
*/
function getHash(address split) external view returns (bytes32) {
return splits[split].hash;
}
/** @notice Returns the current controller of split `split`
* @param split Split to return controller for
* @return Split's controller
*/
function getController(address split) external view returns (address) {
return splits[split].controller;
}
/** @notice Returns the current newPotentialController of split `split`
* @param split Split to return newPotentialController for
* @return Split's newPotentialController
*/
function getNewPotentialController(address split)
external
view
returns (address)
{
return splits[split].newPotentialController;
}
/** @notice Returns the current ETH balance of account `account`
* @param account Account to return ETH balance for
* @return Account's balance of ETH
*/
function getETHBalance(address account) external view returns (uint256) {
return
ethBalances[account] + (splits[account].hash != 0 ? account.balance : 0);
}
/** @notice Returns the ERC20 balance of token `token` for account `account`
* @param account Account to return ERC20 `token` balance for
* @param token Token to return balance for
* @return Account's balance of `token`
*/
function getERC20Balance(address account, ERC20 token)
external
view
returns (uint256)
{
return
erc20Balances[token][account] +
(splits[account].hash != 0 ? token.balanceOf(account) : 0);
}
/**
* FUNCTIONS - PRIVATE & INTERNAL
*/
/** @notice Sums array of uint32s
* @param numbers Array of uint32s to sum
* @return sum Sum of `numbers`.
*/
function _getSum(uint32[] memory numbers) internal pure returns (uint32 sum) {
// overflow should be impossible in for-loop index
uint256 numbersLength = numbers.length;
for (uint256 i = 0; i < numbersLength; ) {
sum += numbers[i];
unchecked {
// overflow should be impossible in for-loop index
++i;
}
}
}
/** @notice Hashes a split
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
* @return computedHash Hash of the split.
*/
function _hashSplit(
address[] memory accounts,
uint32[] memory percentAllocations,
uint32 distributorFee
) internal pure returns (bytes32) {
return
keccak256(abi.encodePacked(accounts, percentAllocations, distributorFee));
}
/** @notice Updates an existing split with recipients `accounts` with ownerships `percentAllocations` and a keeper fee for splitting of `distributorFee`
* @param split Address of mutable split to update
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
*/
function _updateSplit(
address split,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee
) internal {
bytes32 splitHash = _hashSplit(
accounts,
percentAllocations,
distributorFee
);
// store new hash in storage for future verification
splits[split].hash = splitHash;
emit UpdateSplit(split, accounts, percentAllocations, distributorFee);
}
/** @notice Checks hash from `accounts`, `percentAllocations`, and `distributorFee` against the hash stored for `split`
* @param split Address of hash to check
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
*/
function _validSplitHash(
address split,
address[] memory accounts,
uint32[] memory percentAllocations,
uint32 distributorFee
) internal view {
bytes32 hash = _hashSplit(accounts, percentAllocations, distributorFee);
if (splits[split].hash != hash) revert InvalidSplit__InvalidHash(hash);
}
/** @notice Distributes the ETH balance for split `split`
* @dev `accounts`, `percentAllocations`, and `distributorFee` must be verified before calling
* @param split Address of split to distribute balance for
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
* @param distributorAddress Address to pay `distributorFee` to
*/
function _distributeETH(
address split,
address[] memory accounts,
uint32[] memory percentAllocations,
uint32 distributorFee,
address distributorAddress
) internal {
uint256 mainBalance = ethBalances[split];
uint256 proxyBalance = split.balance;
// if mainBalance is positive, leave 1 in SplitMain for gas efficiency
uint256 amountToSplit;
unchecked {
// underflow should be impossible
if (mainBalance > 0) mainBalance -= 1;
// overflow should be impossible
amountToSplit = mainBalance + proxyBalance;
}
if (mainBalance > 0) ethBalances[split] = 1;
// use msg.sender if distributorAddress == address(0)
distributorAddress = distributorAddress != address(0)
? distributorAddress
: msg.sender;
// emit event with gross amountToSplit (before deducting distributorFee)
emit DistributeETH(split, amountToSplit, distributorAddress);
if (distributorFee != 0) {
// given `amountToSplit`, calculate keeper fee
uint256 distributorFeeAmount = _scaleAmountByPercentage(
amountToSplit,
distributorFee
);
unchecked {
// credit keeper with fee
// overflow should be impossible with validated distributorFee
ethBalances[distributorAddress] += distributorFeeAmount;
// given keeper fee, calculate how much to distribute to split recipients
// underflow should be impossible with validated distributorFee
amountToSplit -= distributorFeeAmount;
}
}
unchecked {
// distribute remaining balance
// overflow should be impossible in for-loop index
// cache accounts length to save gas
uint256 accountsLength = accounts.length;
for (uint256 i = 0; i < accountsLength; ++i) {
// overflow should be impossible with validated allocations
ethBalances[accounts[i]] += _scaleAmountByPercentage(
amountToSplit,
percentAllocations[i]
);
}
}
// flush proxy ETH balance to SplitMain
// split proxy should be guaranteed to exist at this address after validating splitHash
// (attacker can't deploy own contract to address with high balance & empty sendETHToMain
// to drain ETH from SplitMain)
// could technically check if (change in proxy balance == change in SplitMain balance)
// before/after external call, but seems like extra gas for no practical benefit
if (proxyBalance > 0) SplitWallet(split).sendETHToMain(proxyBalance);
}
/** @notice Distributes the ERC20 `token` balance for split `split`
* @dev `accounts`, `percentAllocations`, and `distributorFee` must be verified before calling
* @dev pernicious ERC20s may cause overflow in this function inside
* _scaleAmountByPercentage, but results do not affect ETH & other ERC20 balances
* @param split Address of split to distribute balance for
* @param token Address of ERC20 to distribute balance for
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
* @param distributorAddress Address to pay `distributorFee` to
*/
function _distributeERC20(
address split,
ERC20 token,
address[] memory accounts,
uint32[] memory percentAllocations,
uint32 distributorFee,
address distributorAddress
) internal {
uint256 amountToSplit;
uint256 mainBalance = erc20Balances[token][split];
uint256 proxyBalance = token.balanceOf(split);
unchecked {
// if mainBalance &/ proxyBalance are positive, leave 1 for gas efficiency
// underflow should be impossible
if (proxyBalance > 0) proxyBalance -= 1;
// underflow should be impossible
if (mainBalance > 0) {
mainBalance -= 1;
}
// overflow should be impossible
amountToSplit = mainBalance + proxyBalance;
}
if (mainBalance > 0) erc20Balances[token][split] = 1;
// use msg.sender if distributorAddress == address(0)
distributorAddress = distributorAddress != address(0)
? distributorAddress
: msg.sender;
// emit event with gross amountToSplit (before deducting distributorFee)
emit DistributeERC20(split, token, amountToSplit, distributorAddress);
if (distributorFee != 0) {
// given `amountToSplit`, calculate keeper fee
uint256 distributorFeeAmount = _scaleAmountByPercentage(
amountToSplit,
distributorFee
);
// overflow should be impossible with validated distributorFee
unchecked {
// credit keeper with fee
erc20Balances[token][distributorAddress] += distributorFeeAmount;
// given keeper fee, calculate how much to distribute to split recipients
amountToSplit -= distributorFeeAmount;
}
}
// distribute remaining balance
// overflows should be impossible in for-loop with validated allocations
unchecked {
// cache accounts length to save gas
uint256 accountsLength = accounts.length;
for (uint256 i = 0; i < accountsLength; ++i) {
erc20Balances[token][accounts[i]] += _scaleAmountByPercentage(
amountToSplit,
percentAllocations[i]
);
}
}
// split proxy should be guaranteed to exist at this address after validating splitHash
// (attacker can't deploy own contract to address with high ERC20 balance & empty
// sendERC20ToMain to drain ERC20 from SplitMain)
// doesn't support rebasing or fee-on-transfer tokens
// flush extra proxy ERC20 balance to SplitMain
if (proxyBalance > 0)
SplitWallet(split).sendERC20ToMain(token, proxyBalance);
}
/** @notice Multiplies an amount by a scaled percentage
* @param amount Amount to get `scaledPercentage` of
* @param scaledPercent Percent scaled by PERCENTAGE_SCALE
* @return scaledAmount Percent of `amount`.
*/
function _scaleAmountByPercentage(uint256 amount, uint256 scaledPercent)
internal
pure
returns (uint256 scaledAmount)
{
// use assembly to bypass checking for overflow & division by 0
// scaledPercent has been validated to be < PERCENTAGE_SCALE)
// & PERCENTAGE_SCALE will never be 0
// pernicious ERC20s may cause overflow, but results do not affect ETH & other ERC20 balances
assembly {
/* eg (100 * 2*1e4) / (1e6) */
scaledAmount := div(mul(amount, scaledPercent), PERCENTAGE_SCALE)
}
}
/** @notice Withdraw ETH for account `account`
* @param account Account to withdrawn ETH for
* @return withdrawn Amount of ETH withdrawn
*/
function _withdraw(address account) internal returns (uint256 withdrawn) {
// leave balance of 1 for gas efficiency
// underflow if ethBalance is 0
withdrawn = ethBalances[account] - 1;
ethBalances[account] = 1;
account.safeTransferETH(withdrawn);
}
/** @notice Withdraw ERC20 `token` for account `account`
* @param account Account to withdrawn ERC20 `token` for
* @return withdrawn Amount of ERC20 `token` withdrawn
*/
function _withdrawERC20(address account, ERC20 token)
internal
returns (uint256 withdrawn)
{
// leave balance of 1 for gas efficiency
// underflow if erc20Balance is 0
withdrawn = erc20Balances[token][account] - 1;
erc20Balances[token][account] = 1;
token.safeTransfer(account, withdrawn);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;
import {ISplitMain} from './interfaces/ISplitMain.sol';
import {ERC20} from '@rari-capital/solmate/src/tokens/ERC20.sol';
import {SafeTransferLib} from '@rari-capital/solmate/src/utils/SafeTransferLib.sol';
/**
* ERRORS
*/
/// @notice Unauthorized sender
error Unauthorized();
/**
* @title SplitWallet
* @author 0xSplits <[email protected]>
* @notice The implementation logic for `SplitProxy`.
* @dev `SplitProxy` handles `receive()` itself to avoid the gas cost with `DELEGATECALL`.
*/
contract SplitWallet {
using SafeTransferLib for address;
using SafeTransferLib for ERC20;
/**
* EVENTS
*/
/** @notice emitted after each successful ETH transfer to proxy
* @param split Address of the split that received ETH
* @param amount Amount of ETH received
*/
event ReceiveETH(address indexed split, uint256 amount);
/**
* STORAGE
*/
/**
* STORAGE - CONSTANTS & IMMUTABLES
*/
/// @notice address of SplitMain for split distributions & EOA/SC withdrawals
ISplitMain public immutable splitMain;
/**
* MODIFIERS
*/
/// @notice Reverts if the sender isn't SplitMain
modifier onlySplitMain() {
if (msg.sender != address(splitMain)) revert Unauthorized();
_;
}
/**
* CONSTRUCTOR
*/
constructor() {
splitMain = ISplitMain(msg.sender);
}
/**
* FUNCTIONS - PUBLIC & EXTERNAL
*/
/** @notice Sends amount `amount` of ETH in proxy to SplitMain
* @dev payable reduces gas cost; no vulnerability to accidentally lock
* ETH introduced since fn call is restricted to SplitMain
* @param amount Amount to send
*/
function sendETHToMain(uint256 amount) external payable onlySplitMain {
address(splitMain).safeTransferETH(amount);
}
/** @notice Sends amount `amount` of ERC20 `token` in proxy to SplitMain
* @dev payable reduces gas cost; no vulnerability to accidentally lock
* ETH introduced since fn call is restricted to SplitMain
* @param token Token to send
* @param amount Amount to send
*/
function sendERC20ToMain(ERC20 token, uint256 amount)
external
payable
onlySplitMain
{
token.safeTransfer(address(splitMain), amount);
}
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;
import {ERC20} from '@rari-capital/solmate/src/tokens/ERC20.sol';
/**
* @title ISplitMain
* @author 0xSplits <[email protected]>
*/
interface ISplitMain {
/**
* FUNCTIONS
*/
function walletImplementation() external returns (address);
function createSplit(
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address controller
) external returns (address);
function predictImmutableSplitAddress(
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee
) external view returns (address);
function updateSplit(
address split,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee
) external;
function transferControl(address split, address newController) external;
function cancelControlTransfer(address split) external;
function acceptControl(address split) external;
function makeSplitImmutable(address split) external;
function distributeETH(
address split,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
) external;
function updateAndDistributeETH(
address split,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
) external;
function distributeERC20(
address split,
ERC20 token,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
) external;
function updateAndDistributeERC20(
address split,
ERC20 token,
address[] calldata accounts,
uint32[] calldata percentAllocations,
uint32 distributorFee,
address distributorAddress
) external;
function withdraw(
address account,
uint256 withdrawETH,
ERC20[] calldata tokens
) external;
/**
* EVENTS
*/
/** @notice emitted after each successful split creation
* @param split Address of the created split
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
* @param controller Controlling address (0x0 if immutable)
*/
event CreateSplit(
address indexed split,
address[] accounts,
uint32[] percentAllocations,
uint32 distributorFee,
address controller
);
/** @notice emitted after each successful split update
* @param split Address of the updated split
* @param accounts Ordered, unique list of addresses with ownership in the split
* @param percentAllocations Percent allocations associated with each address
* @param distributorFee Keeper fee paid by split to cover gas costs of distribution
*/
event UpdateSplit(
address indexed split,
address[] accounts,
uint32[] percentAllocations,
uint32 distributorFee
);
/** @notice emitted after each initiated split control transfer
* @param split Address of the split control transfer was initiated for
* @param newPotentialController Address of the split's new potential controller
*/
event InitiateControlTransfer(
address indexed split,
address indexed newPotentialController
);
/** @notice emitted after each canceled split control transfer
* @param split Address of the split control transfer was canceled for
*/
event CancelControlTransfer(address indexed split);
/** @notice emitted after each successful split control transfer
* @param split Address of the split control was transferred for
* @param previousController Address of the split's previous controller
* @param newController Address of the split's new controller
*/
event ControlTransfer(
address indexed split,
address indexed previousController,
address indexed newController
);
/** @notice emitted after each successful ETH balance split
* @param split Address of the split that distributed its balance
* @param amount Amount of ETH distributed
* @param distributorAddress Address to credit distributor fee to
*/
event DistributeETH(
address indexed split,
uint256 amount,
address indexed distributorAddress
);
/** @notice emitted after each successful ERC20 balance split
* @param split Address of the split that distributed its balance
* @param token Address of ERC20 distributed
* @param amount Amount of ERC20 distributed
* @param distributorAddress Address to credit distributor fee to
*/
event DistributeERC20(
address indexed split,
ERC20 indexed token,
uint256 amount,
address indexed distributorAddress
);
/** @notice emitted after each successful withdrawal
* @param account Address that funds were withdrawn to
* @param ethAmount Amount of ETH withdrawn
* @param tokens Addresses of ERC20s withdrawn
* @param tokenAmounts Amounts of corresponding ERC20s withdrawn
*/
event Withdrawal(
address indexed account,
uint256 ethAmount,
ERC20[] tokens,
uint256[] tokenAmounts
);
}// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;
/// @notice create opcode failed
error CreateError();
/// @notice create2 opcode failed
error Create2Error();
library Clones {
/**
* @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`
* except when someone calls `receive()` and then it emits an event matching
* `SplitWallet.ReceiveETH(indexed address, amount)`
* Inspired by OZ & 0age's minimal clone implementations based on eip 1167 found at
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.3.0/contracts/proxy/Clones.sol
* and https://medium.com/coinmonks/the-more-minimal-proxy-5756ae08ee48
*
* This function uses the create2 opcode and a `salt` to deterministically deploy
* the clone. Using the same `implementation` and `salt` multiple time will revert, since
* the clones cannot be deployed twice at the same address.
*
* init: 0x3d605d80600a3d3981f3
* 3d returndatasize 0
* 605d push1 0x5d 0x5d 0
* 80 dup1 0x5d 0x5d 0
* 600a push1 0x0a 0x0a 0x5d 0x5d 0
* 3d returndatasize 0 0x0a 0x5d 0x5d 0
* 39 codecopy 0x5d 0 destOffset offset length memory[destOffset:destOffset+length] = address(this).code[offset:offset+length] copy executing contracts bytecode
* 81 dup2 0 0x5d 0
* f3 return 0 offset length return memory[offset:offset+length] returns from this contract call
*
* contract: 0x36603057343d52307f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160203da23d3df35b3d3d3d3d363d3d37363d73bebebebebebebebebebebebebebebebebebebebe5af43d3d93803e605b57fd5bf3
* 0x000 36 calldatasize cds
* 0x001 6030 push1 0x30 0x30 cds
* ,=< 0x003 57 jumpi
* | 0x004 34 callvalue cv
* | 0x005 3d returndatasize 0 cv
* | 0x006 52 mstore
* | 0x007 30 address addr
* | 0x008 7f830d.. push32 0x830d.. id addr
* | 0x029 6020 push1 0x20 0x20 id addr
* | 0x02b 3d returndatasize 0 0x20 id addr
* | 0x02c a2 log2
* | 0x02d 3d returndatasize 0
* | 0x02e 3d returndatasize 0 0
* | 0x02f f3 return
* `-> 0x030 5b jumpdest
* 0x031 3d returndatasize 0
* 0x032 3d returndatasize 0 0
* 0x033 3d returndatasize 0 0 0
* 0x034 3d returndatasize 0 0 0 0
* 0x035 36 calldatasize cds 0 0 0 0
* 0x036 3d returndatasize 0 cds 0 0 0 0
* 0x037 3d returndatasize 0 0 cds 0 0 0 0
* 0x038 37 calldatacopy 0 0 0 0
* 0x039 36 calldatasize cds 0 0 0 0
* 0x03a 3d returndatasize 0 cds 0 0 0 0
* 0x03b 73bebe.. push20 0xbebe.. 0xbebe 0 cds 0 0 0 0
* 0x050 5a gas gas 0xbebe 0 cds 0 0 0 0
* 0x051 f4 delegatecall suc 0 0
* 0x052 3d returndatasize rds suc 0 0
* 0x053 3d returndatasize rds rds suc 0 0
* 0x054 93 swap4 0 rds suc 0 rds
* 0x055 80 dup1 0 0 rds suc 0 rds
* 0x056 3e returndatacopy suc 0 rds
* 0x057 605b push1 0x5b 0x5b suc 0 rds
* ,=< 0x059 57 jumpi 0 rds
* | 0x05a fd revert
* `-> 0x05b 5b jumpdest 0 rds
* 0x05c f3 return
*
*/
function clone(address implementation) internal returns (address instance) {
assembly {
let ptr := mload(0x40)
mstore(
ptr,
0x3d605d80600a3d3981f336603057343d52307f00000000000000000000000000
)
mstore(
add(ptr, 0x13),
0x830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b1
)
mstore(
add(ptr, 0x33),
0x60203da23d3df35b3d3d3d3d363d3d37363d7300000000000000000000000000
)
mstore(add(ptr, 0x46), shl(0x60, implementation))
mstore(
add(ptr, 0x5a),
0x5af43d3d93803e605b57fd5bf300000000000000000000000000000000000000
)
instance := create(0, ptr, 0x67)
}
if (instance == address(0)) revert CreateError();
}
function cloneDeterministic(address implementation, bytes32 salt)
internal
returns (address instance)
{
assembly {
let ptr := mload(0x40)
mstore(
ptr,
0x3d605d80600a3d3981f336603057343d52307f00000000000000000000000000
)
mstore(
add(ptr, 0x13),
0x830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b1
)
mstore(
add(ptr, 0x33),
0x60203da23d3df35b3d3d3d3d363d3d37363d7300000000000000000000000000
)
mstore(add(ptr, 0x46), shl(0x60, implementation))
mstore(
add(ptr, 0x5a),
0x5af43d3d93803e605b57fd5bf300000000000000000000000000000000000000
)
instance := create2(0, ptr, 0x67, salt)
}
if (instance == address(0)) revert Create2Error();
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(
address implementation,
bytes32 salt,
address deployer
) internal pure returns (address predicted) {
assembly {
let ptr := mload(0x40)
mstore(
ptr,
0x3d605d80600a3d3981f336603057343d52307f00000000000000000000000000
)
mstore(
add(ptr, 0x13),
0x830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b1
)
mstore(
add(ptr, 0x33),
0x60203da23d3df35b3d3d3d3d363d3d37363d7300000000000000000000000000
)
mstore(add(ptr, 0x46), shl(0x60, implementation))
mstore(
add(ptr, 0x5a),
0x5af43d3d93803e605b57fd5bf3ff000000000000000000000000000000000000
)
mstore(add(ptr, 0x68), shl(0x60, deployer))
mstore(add(ptr, 0x7c), salt)
mstore(add(ptr, 0x9c), keccak256(ptr, 0x67))
predicted := keccak256(add(ptr, 0x67), 0x55)
}
}
/**
* @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
*/
function predictDeterministicAddress(address implementation, bytes32 salt)
internal
view
returns (address predicted)
{
return predictDeterministicAddress(implementation, salt, address(this));
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
import {ERC20} from "../tokens/ERC20.sol";
/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Gnosis (https://github.com/gnosis/gp-v2-contracts/blob/main/src/contracts/libraries/GPv2SafeERC20.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
library SafeTransferLib {
/*///////////////////////////////////////////////////////////////
ETH OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferETH(address to, uint256 amount) internal {
bool callStatus;
assembly {
// Transfer the ETH and store if it succeeded or not.
callStatus := call(gas(), to, amount, 0, 0, 0, 0)
}
require(callStatus, "ETH_TRANSFER_FAILED");
}
/*///////////////////////////////////////////////////////////////
ERC20 OPERATIONS
//////////////////////////////////////////////////////////////*/
function safeTransferFrom(
ERC20 token,
address from,
address to,
uint256 amount
) internal {
bool callStatus;
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata to memory piece by piece:
mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) // Begin with the function selector.
mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "from" argument.
mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.
mstore(add(freeMemoryPointer, 68), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.
// Call the token and store if it succeeded or not.
// We use 100 because the calldata length is 4 + 32 * 3.
callStatus := call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)
}
require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FROM_FAILED");
}
function safeTransfer(
ERC20 token,
address to,
uint256 amount
) internal {
bool callStatus;
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata to memory piece by piece:
mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // Begin with the function selector.
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.
// Call the token and store if it succeeded or not.
// We use 68 because the calldata length is 4 + 32 * 2.
callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
}
require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FAILED");
}
function safeApprove(
ERC20 token,
address to,
uint256 amount
) internal {
bool callStatus;
assembly {
// Get a pointer to some free memory.
let freeMemoryPointer := mload(0x40)
// Write the abi-encoded calldata to memory piece by piece:
mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) // Begin with the function selector.
mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.
mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.
// Call the token and store if it succeeded or not.
// We use 68 because the calldata length is 4 + 32 * 2.
callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
}
require(didLastOptionalReturnCallSucceed(callStatus), "APPROVE_FAILED");
}
/*///////////////////////////////////////////////////////////////
INTERNAL HELPER LOGIC
//////////////////////////////////////////////////////////////*/
function didLastOptionalReturnCallSucceed(bool callStatus) private pure returns (bool success) {
assembly {
// Get how many bytes the call returned.
let returnDataSize := returndatasize()
// If the call reverted:
if iszero(callStatus) {
// Copy the revert message into memory.
returndatacopy(0, 0, returnDataSize)
// Revert with the same message.
revert(0, returnDataSize)
}
switch returnDataSize
case 32 {
// Copy the return data into memory.
returndatacopy(0, 0, returnDataSize)
// Set success to whether it returned true.
success := iszero(iszero(mload(0)))
}
case 0 {
// There was no return data.
success := 1
}
default {
// It returned some malformed input.
success := 0
}
}
}
}// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;
/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
/*///////////////////////////////////////////////////////////////
EVENTS
//////////////////////////////////////////////////////////////*/
event Transfer(address indexed from, address indexed to, uint256 amount);
event Approval(address indexed owner, address indexed spender, uint256 amount);
/*///////////////////////////////////////////////////////////////
METADATA STORAGE
//////////////////////////////////////////////////////////////*/
string public name;
string public symbol;
uint8 public immutable decimals;
/*///////////////////////////////////////////////////////////////
ERC20 STORAGE
//////////////////////////////////////////////////////////////*/
uint256 public totalSupply;
mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
/*///////////////////////////////////////////////////////////////
EIP-2612 STORAGE
//////////////////////////////////////////////////////////////*/
bytes32 public constant PERMIT_TYPEHASH =
keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
uint256 internal immutable INITIAL_CHAIN_ID;
bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
mapping(address => uint256) public nonces;
/*///////////////////////////////////////////////////////////////
CONSTRUCTOR
//////////////////////////////////////////////////////////////*/
constructor(
string memory _name,
string memory _symbol,
uint8 _decimals
) {
name = _name;
symbol = _symbol;
decimals = _decimals;
INITIAL_CHAIN_ID = block.chainid;
INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
}
/*///////////////////////////////////////////////////////////////
ERC20 LOGIC
//////////////////////////////////////////////////////////////*/
function approve(address spender, uint256 amount) public virtual returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}
function transfer(address to, uint256 amount) public virtual returns (bool) {
balanceOf[msg.sender] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(msg.sender, to, amount);
return true;
}
function transferFrom(
address from,
address to,
uint256 amount
) public virtual returns (bool) {
uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
balanceOf[from] -= amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(from, to, amount);
return true;
}
/*///////////////////////////////////////////////////////////////
EIP-2612 LOGIC
//////////////////////////////////////////////////////////////*/
function permit(
address owner,
address spender,
uint256 value,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) public virtual {
require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
// Unchecked because the only math done is incrementing
// the owner's nonce which cannot realistically overflow.
unchecked {
bytes32 digest = keccak256(
abi.encodePacked(
"\x19\x01",
DOMAIN_SEPARATOR(),
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
allowance[recoveredAddress][spender] = value;
}
emit Approval(owner, spender, value);
}
function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
}
function computeDomainSeparator() internal view virtual returns (bytes32) {
return
keccak256(
abi.encode(
keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
keccak256(bytes(name)),
keccak256("1"),
block.chainid,
address(this)
)
);
}
/*///////////////////////////////////////////////////////////////
INTERNAL MINT/BURN LOGIC
//////////////////////////////////////////////////////////////*/
function _mint(address to, uint256 amount) internal virtual {
totalSupply += amount;
// Cannot overflow because the sum of all user
// balances can't exceed the max uint256 value.
unchecked {
balanceOf[to] += amount;
}
emit Transfer(address(0), to, amount);
}
function _burn(address from, uint256 amount) internal virtual {
balanceOf[from] -= amount;
// Cannot underflow because a user's balance
// will never be larger than the total supply.
unchecked {
totalSupply -= amount;
}
emit Transfer(from, address(0), amount);
}
}{
"optimizer": {
"enabled": true,
"runs": 200
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"metadata": {
"useLiteralContent": true
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Create2Error","type":"error"},{"inputs":[],"name":"CreateError","type":"error"},{"inputs":[{"internalType":"address","name":"newController","type":"address"}],"name":"InvalidNewController","type":"error"},{"inputs":[{"internalType":"uint256","name":"accountsLength","type":"uint256"},{"internalType":"uint256","name":"allocationsLength","type":"uint256"}],"name":"InvalidSplit__AccountsAndAllocationsMismatch","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"InvalidSplit__AccountsOutOfOrder","type":"error"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"InvalidSplit__AllocationMustBePositive","type":"error"},{"inputs":[{"internalType":"uint32","name":"allocationsSum","type":"uint32"}],"name":"InvalidSplit__InvalidAllocationsSum","type":"error"},{"inputs":[{"internalType":"uint32","name":"distributorFee","type":"uint32"}],"name":"InvalidSplit__InvalidDistributorFee","type":"error"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"InvalidSplit__InvalidHash","type":"error"},{"inputs":[{"internalType":"uint256","name":"accountsLength","type":"uint256"}],"name":"InvalidSplit__TooFewAccounts","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"split","type":"address"}],"name":"CancelControlTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"split","type":"address"},{"indexed":true,"internalType":"address","name":"previousController","type":"address"},{"indexed":true,"internalType":"address","name":"newController","type":"address"}],"name":"ControlTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"split","type":"address"},{"indexed":false,"internalType":"address[]","name":"accounts","type":"address[]"},{"indexed":false,"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"},{"indexed":false,"internalType":"uint32","name":"distributorFee","type":"uint32"},{"indexed":false,"internalType":"address","name":"controller","type":"address"}],"name":"CreateSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"split","type":"address"},{"indexed":true,"internalType":"contract ERC20","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"distributorAddress","type":"address"}],"name":"DistributeERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"split","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":true,"internalType":"address","name":"distributorAddress","type":"address"}],"name":"DistributeETH","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"split","type":"address"},{"indexed":true,"internalType":"address","name":"newPotentialController","type":"address"}],"name":"InitiateControlTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"split","type":"address"},{"indexed":false,"internalType":"address[]","name":"accounts","type":"address[]"},{"indexed":false,"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"},{"indexed":false,"internalType":"uint32","name":"distributorFee","type":"uint32"}],"name":"UpdateSplit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"uint256","name":"ethAmount","type":"uint256"},{"indexed":false,"internalType":"contract ERC20[]","name":"tokens","type":"address[]"},{"indexed":false,"internalType":"uint256[]","name":"tokenAmounts","type":"uint256[]"}],"name":"Withdrawal","type":"event"},{"inputs":[],"name":"PERCENTAGE_SCALE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"}],"name":"acceptControl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"}],"name":"cancelControlTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"},{"internalType":"uint32","name":"distributorFee","type":"uint32"},{"internalType":"address","name":"controller","type":"address"}],"name":"createSplit","outputs":[{"internalType":"address","name":"split","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"},{"internalType":"contract ERC20","name":"token","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"},{"internalType":"uint32","name":"distributorFee","type":"uint32"},{"internalType":"address","name":"distributorAddress","type":"address"}],"name":"distributeERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"},{"internalType":"uint32","name":"distributorFee","type":"uint32"},{"internalType":"address","name":"distributorAddress","type":"address"}],"name":"distributeETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"}],"name":"getController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"contract ERC20","name":"token","type":"address"}],"name":"getERC20Balance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getETHBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"}],"name":"getHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"}],"name":"getNewPotentialController","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"}],"name":"makeSplitImmutable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"},{"internalType":"uint32","name":"distributorFee","type":"uint32"}],"name":"predictImmutableSplitAddress","outputs":[{"internalType":"address","name":"split","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"},{"internalType":"address","name":"newController","type":"address"}],"name":"transferControl","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"},{"internalType":"contract ERC20","name":"token","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"},{"internalType":"uint32","name":"distributorFee","type":"uint32"},{"internalType":"address","name":"distributorAddress","type":"address"}],"name":"updateAndDistributeERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"},{"internalType":"uint32","name":"distributorFee","type":"uint32"},{"internalType":"address","name":"distributorAddress","type":"address"}],"name":"updateAndDistributeETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"},{"internalType":"uint32","name":"distributorFee","type":"uint32"}],"name":"updateSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"walletImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"withdrawETH","type":"uint256"},{"internalType":"contract ERC20[]","name":"tokens","type":"address[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]Contract Creation Code
60a06040523480156200001157600080fd5b50604051620000209062000054565b604051809103906000f0801580156200003d573d6000803e3d6000fd5b5060601b6001600160601b03191660805262000062565b6103a0806200322b83390190565b60805160601c61319562000096600039600081816102b001528181610c1a0152818161106c015261109d01526131956000f3fe6080604052600436106101185760003560e01c806377b1e4e9116100a0578063c7de644011610064578063c7de64401461034e578063d0e4b2f41461036e578063e10e51d61461038e578063e61cb05e146103cb578063ecef0ace146103eb57600080fd5b806377b1e4e91461027e5780638117abc11461029e57806388c662aa146102d2578063a5e3909e1461030e578063c3a8962c1461032e57600080fd5b80633bb66a7b116100e75780633bb66a7b146101cf5780633f26479e146101ef57806352844dd3146102065780636e5f69191461023e5780637601f7821461025e57600080fd5b80631267c6da146101245780631581130214610146578063189cbaa0146101665780631da0b8fc1461018657600080fd5b3661011f57005b600080fd5b34801561013057600080fd5b5061014461013f366004612ae0565b61040b565b005b34801561015257600080fd5b50610144610161366004612c7a565b6104a6565b34801561017257600080fd5b50610144610181366004612ae0565b61081a565b34801561019257600080fd5b506101bc6101a1366004612ae0565b6001600160a01b031660009081526002602052604090205490565b6040519081526020015b60405180910390f35b3480156101db57600080fd5b506101bc6101ea366004612ae0565b6108e5565b3480156101fb57600080fd5b506101bc620f424081565b34801561021257600080fd5b50610226610221366004612d8b565b61093e565b6040516001600160a01b0390911681526020016101c6565b34801561024a57600080fd5b50610144610259366004612d31565b610c4d565b34801561026a57600080fd5b50610226610279366004612e09565b610d82565b34801561028a57600080fd5b50610144610299366004612c7a565b611160565b3480156102aa57600080fd5b506102267f000000000000000000000000000000000000000000000000000000000000000081565b3480156102de57600080fd5b506102266102ed366004612ae0565b6001600160a01b039081166000908152600260205260409020600101541690565b34801561031a57600080fd5b50610144610329366004612bc3565b6114a3565b34801561033a57600080fd5b506101bc610349366004612c68565b6117c6565b34801561035a57600080fd5b50610144610369366004612ae0565b61189a565b34801561037a57600080fd5b50610144610389366004612afc565b611969565b34801561039a57600080fd5b506102266103a9366004612ae0565b6001600160a01b03908116600090815260026020819052604090912001541690565b3480156103d757600080fd5b506101446103e6366004612bc3565b611a3b565b3480156103f757600080fd5b50610144610406366004612b34565b611d8b565b6001600160a01b0381811660009081526002602052604090206001015482911633146104515760405163472511eb60e11b81523360048201526024015b60405180910390fd5b6001600160a01b038216600081815260026020819052604080832090910180546001600160a01b0319169055517f6c2460a415b84be3720c209fe02f2cad7a6bcba21e8637afe8957b7ec4b6ef879190a25050565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050610535578251604051630e8c626560e41b815260040161044891815260200190565b8151835114610564578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f42406105718361203c565b63ffffffff16146105a7576105858261203c565b60405163fcc487c160e01b815263ffffffff9091166004820152602401610448565b82516000190160005b8181101561069e578481600101815181106105db57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031685828151811061060c57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161061063e5760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061066657634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16141561069657604051630db7e4c760e01b815260048101829052602401610448565b6001016105b0565b50600063ffffffff168382815181106106c757634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff1614156106f757604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff16111561072a5760405163308440e360e21b815263ffffffff82166004820152602401610448565b61079a8b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b925061208f915050565b61080d8b8b8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92508b91506120e19050565b5050505050505050505050565b6001600160a01b03818116600090815260026020526040902060010154829116331461085b5760405163472511eb60e11b8152336004820152602401610448565b6001600160a01b03808316600081815260026020819052604080832091820180546001600160a01b0319169055600190910154905191931691907f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d0908490a4506001600160a01b0316600090815260026020526040902060010180546001600160a01b0319169055565b6001600160a01b038116600090815260026020526040812054610909576000610915565b816001600160a01b0316315b6001600160a01b03831660009081526020819052604090205461093891906130da565b92915050565b6000858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208089028281018201909352888252909350889250879182918501908490808284376000920191909152505083518692506002111590506109cf578251604051630e8c626560e41b815260040161044891815260200190565b81518351146109fe578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240610a0b8361203c565b63ffffffff1614610a1f576105858261203c565b82516000190160005b81811015610b1657848160010181518110610a5357634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110610a8457634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610610ab65760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110610ade57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610b0e57604051630db7e4c760e01b815260048101829052602401610448565b600101610a28565b50600063ffffffff16838281518110610b3f57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610b6f57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115610ba25760405163308440e360e21b815263ffffffff82166004820152602401610448565b6000610c138a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b92506123b6915050565b9050610c3f7f0000000000000000000000000000000000000000000000000000000000000000826123ec565b9a9950505050505050505050565b60008167ffffffffffffffff811115610c7657634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610c9f578160200160208202803683370190505b50905060008415610cb657610cb386612491565b90505b60005b83811015610d3257610cff87868684818110610ce557634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610cfa9190612ae0565b6124e4565b838281518110610d1f57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152600101610cb9565b50856001600160a01b03167fa9e30bf144f83390a4fe47562a4e16892108102221c674ff538da0b72a83d17482868686604051610d72949392919061304a565b60405180910390a2505050505050565b600086868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050610e13578251604051630e8c626560e41b815260040161044891815260200190565b8151835114610e42578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240610e4f8361203c565b63ffffffff1614610e63576105858261203c565b82516000190160005b81811015610f5a57848160010181518110610e9757634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110610ec857634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610610efa5760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110610f2257634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610f5257604051630db7e4c760e01b815260048101829052602401610448565b600101610e6c565b50600063ffffffff16838281518110610f8357634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610fb357604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115610fe65760405163308440e360e21b815263ffffffff82166004820152602401610448565b60006110578b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92506123b6915050565b90506001600160a01b038616611098576110917f000000000000000000000000000000000000000000000000000000000000000082612550565b94506110f5565b6110c17f0000000000000000000000000000000000000000000000000000000000000000612600565b6001600160a01b03818116600090815260026020526040902060010180546001600160a01b03191691891691909117905594505b6001600160a01b03851660008181526002602052604090819020839055517fd2bcf51a5767c814cfe0266a99141f75a32103bbf8c400fbc1ac0c3b73ce25e89061114a908e908e908e908e908e908e90612ff9565b60405180910390a2505050509695505050505050565b6001600160a01b0388811660009081526002602052604090206001015489911633146111a15760405163472511eb60e11b8152336004820152602401610448565b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050611230578251604051630e8c626560e41b815260040161044891815260200190565b815183511461125f578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061126c8361203c565b63ffffffff1614611280576105858261203c565b82516000190160005b81811015611377578481600101815181106112b457634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03168582815181106112e557634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316106113175760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061133f57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16141561136f57604051630db7e4c760e01b815260048101829052602401610448565b600101611289565b50600063ffffffff168382815181106113a057634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff1614156113d057604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156114035760405163308440e360e21b815263ffffffff82166004820152602401610448565b6114118c8b8b8b8b8b6126af565b6114958c8c8c8c80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508d92508c91506120e19050565b505050505050505050505050565b6001600160a01b0387811660009081526002602052604090206001015488911633146114e45760405163472511eb60e11b8152336004820152602401610448565b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050611573578251604051630e8c626560e41b815260040161044891815260200190565b81518351146115a2578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f42406115af8361203c565b63ffffffff16146115c3576105858261203c565b82516000190160005b818110156116ba578481600101815181106115f757634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031685828151811061162857634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161061165a5760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061168257634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff1614156116b257604051630db7e4c760e01b815260048101829052602401610448565b6001016115cc565b50600063ffffffff168382815181106116e357634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16141561171357604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156117465760405163308440e360e21b815263ffffffff82166004820152602401610448565b6117548b8b8b8b8b8b6126af565b61080d8b8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92508b91506127889050565b6001600160a01b0382166000908152600260205260408120546117ea576000611863565b6040516370a0823160e01b81526001600160a01b0384811660048301528316906370a082319060240160206040518083038186803b15801561182b57600080fd5b505afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118639190612e9a565b6001600160a01b0380841660009081526001602090815260408083209388168352929052205461189391906130da565b9392505050565b6001600160a01b038181166000908152600260208190526040909120015482911633146118dc5760405163472511eb60e11b8152336004820152602401610448565b6001600160a01b03808316600081815260026020819052604080832091820180546001600160a01b0319169055600190910154905133949190911692917f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d091a4506001600160a01b0316600090815260026020526040902060010180546001600160a01b03191633179055565b6001600160a01b0382811660009081526002602052604090206001015483911633146119aa5760405163472511eb60e11b8152336004820152602401610448565b816001600160a01b0381166119dd5760405163c369130760e01b81526001600160a01b0382166004820152602401610448565b6001600160a01b03848116600081815260026020819052604080832090910180546001600160a01b0319169488169485179055517f107cf6ea8668d533df1aab5bb8b6315bb0c25f0b6c955558d09368f290668fc79190a350505050565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050611aca578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611af9578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240611b068361203c565b63ffffffff1614611b1a576105858261203c565b82516000190160005b81811015611c1157848160010181518110611b4e57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110611b7f57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610611bb15760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110611bd957634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611c0957604051630db7e4c760e01b815260048101829052602401610448565b600101611b23565b50600063ffffffff16838281518110611c3a57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611c6a57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115611c9d5760405163308440e360e21b815263ffffffff82166004820152602401610448565b611d0d8a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b925061208f915050565b611d7f8a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b92508a91506127889050565b50505050505050505050565b6001600160a01b038681166000908152600260205260409020600101548791163314611dcc5760405163472511eb60e11b8152336004820152602401610448565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050611e5b578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611e8a578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240611e978361203c565b63ffffffff1614611eab576105858261203c565b82516000190160005b81811015611fa257848160010181518110611edf57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110611f1057634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610611f425760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110611f6a57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611f9a57604051630db7e4c760e01b815260048101829052602401610448565b600101611eb4565b50600063ffffffff16838281518110611fcb57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611ffb57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff16111561202e5760405163308440e360e21b815263ffffffff82166004820152602401610448565b611d7f8a8a8a8a8a8a6126af565b8051600090815b818110156120885783818151811061206b57634e487b7160e01b600052603260045260246000fd5b60200260200101518361207e91906130f2565b9250600101612043565b5050919050565b600061209c8484846123b6565b6001600160a01b03861660009081526002602052604090205490915081146120da5760405163dd5ff45760e01b815260048101829052602401610448565b5050505050565b6001600160a01b038581166000818152600160209081526040808320948b16808452949091528082205490516370a0823160e01b815260048101949094529092909183916370a082319060240160206040518083038186803b15801561214657600080fd5b505afa15801561215a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217e9190612e9a565b9050801561218b57600019015b8115612198576001820391505b818101925081156121cc576001600160a01b038089166000908152600160208181526040808420948e168452939052919020555b6001600160a01b0384166121e057336121e2565b835b9350836001600160a01b0316886001600160a01b03168a6001600160a01b03167fb5ee5dc3d2c31a019bbf2c787e0e9c97971c96aceea1c38c12fc8fd25c536d468660405161223391815260200190565b60405180910390a463ffffffff851615612288576000620f424063ffffffff87168502046001600160a01b03808b166000908152600160209081526040808320938a1683529290522080548201905590930392505b865160005b81811015612340576122d1858983815181106122b957634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16620f424091020490565b6001600160a01b038b1660009081526001602052604081208b519091908c908590811061230e57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b031682528101919091526040016000208054909101905560010161228d565b505080156123ab57604051633e0f9fff60e11b81526001600160a01b038981166004830152602482018390528a1690637c1f3ffe90604401600060405180830381600087803b15801561239257600080fd5b505af11580156123a6573d6000803e3d6000fd5b505050505b505050505050505050565b60008383836040516020016123cd93929190612f32565b6040516020818303038152906040528051906020012090509392505050565b6000611893838330604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b6033820152606093841b60468201526d5af43d3d93803e605b57fd5bf3ff60901b605a820152921b6068830152607c8201526067808220609c830152605591012090565b6001600160a01b0381166000908152602081905260408120546124b69060019061311a565b6001600160a01b0383166000818152602081905260409020600190559091506124df9082612968565b919050565b6001600160a01b03808216600090815260016020818152604080842094871684529390529181205490916125179161311a565b6001600160a01b038084166000818152600160208181526040808420958a168452949052929020919091559091506109389084836129be565b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528360601b60468201526c5af43d3d93803e605b57fd5bf360981b605a820152826067826000f59150506001600160a01b0381166109385760405163380bbe1360e01b815260040160405180910390fd5b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528260601b60468201526c5af43d3d93803e605b57fd5bf360981b605a8201526067816000f09150506001600160a01b0381166124df57604051630985da9b60e41b815260040160405180910390fd5b600061272086868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a028281018201909352898252909350899250889182918501908490808284376000920191909152508792506123b6915050565b6001600160a01b0388166000818152600260205260409081902083905551919250907fce55a01ad467ce2f3080a2cef6eb951b65f489b97956f76c2c04bcddab92aaa9906127779089908990899089908990612fb9565b60405180910390a250505050505050565b6001600160a01b03851660008181526020819052604081205491319082156127b1576001830392505b5081810182156127d8576001600160a01b0388166000908152602081905260409020600190555b6001600160a01b0384166127ec57336127ee565b835b9350836001600160a01b0316886001600160a01b03167f87c3ca0a87d9b82033e4bc55e6d30621f8d7e0c9d8ca7988edfde8932787b77b8360405161283591815260200190565b60405180910390a363ffffffff85161561287a576001600160a01b03841660009081526020819052604090208054620f424063ffffffff881684020490810190915590035b865160005b81811015612900576128ab838983815181106122b957634e487b7160e01b600052603260045260246000fd5b6000808b84815181106128ce57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b031682528101919091526040016000208054909101905560010161287f565b5050811561295e57604051632ac3affd60e21b8152600481018390526001600160a01b0389169063ab0ebff490602401600060405180830381600087803b15801561294a57600080fd5b505af1158015611495573d6000803e3d6000fd5b5050505050505050565b600080600080600085875af19050806129b95760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610448565b505050565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af19150506129f981612a3d565b612a375760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610448565b50505050565b60003d82612a4f57806000803e806000fd5b8060208114612a67578015612a785760009250612088565b816000803e60005115159250612088565b5060019392505050565b60008083601f840112612a93578182fd5b50813567ffffffffffffffff811115612aaa578182fd5b6020830191508360208260051b8501011115612ac557600080fd5b9250929050565b803563ffffffff811681146124df57600080fd5b600060208284031215612af1578081fd5b813561189381613147565b60008060408385031215612b0e578081fd5b8235612b1981613147565b91506020830135612b2981613147565b809150509250929050565b60008060008060008060808789031215612b4c578182fd5b8635612b5781613147565b9550602087013567ffffffffffffffff80821115612b73578384fd5b612b7f8a838b01612a82565b90975095506040890135915080821115612b97578384fd5b50612ba489828a01612a82565b9094509250612bb7905060608801612acc565b90509295509295509295565b600080600080600080600060a0888a031215612bdd578081fd5b8735612be881613147565b9650602088013567ffffffffffffffff80821115612c04578283fd5b612c108b838c01612a82565b909850965060408a0135915080821115612c28578283fd5b50612c358a828b01612a82565b9095509350612c48905060608901612acc565b91506080880135612c5881613147565b8091505092959891949750929550565b60008060408385031215612b0e578182fd5b60008060008060008060008060c0898b031215612c95578081fd5b8835612ca081613147565b97506020890135612cb081613147565b9650604089013567ffffffffffffffff80821115612ccc578283fd5b612cd88c838d01612a82565b909850965060608b0135915080821115612cf0578283fd5b50612cfd8b828c01612a82565b9095509350612d10905060808a01612acc565b915060a0890135612d2081613147565b809150509295985092959890939650565b60008060008060608587031215612d46578384fd5b8435612d5181613147565b935060208501359250604085013567ffffffffffffffff811115612d73578283fd5b612d7f87828801612a82565b95989497509550505050565b600080600080600060608688031215612da2578081fd5b853567ffffffffffffffff80821115612db9578283fd5b612dc589838a01612a82565b90975095506020880135915080821115612ddd578283fd5b50612dea88828901612a82565b9094509250612dfd905060408701612acc565b90509295509295909350565b60008060008060008060808789031215612e21578182fd5b863567ffffffffffffffff80821115612e38578384fd5b612e448a838b01612a82565b90985096506020890135915080821115612e5c578384fd5b50612e6989828a01612a82565b9095509350612e7c905060408801612acc565b91506060870135612e8c81613147565b809150509295509295509295565b600060208284031215612eab578081fd5b5051919050565b81835260006020808501945082825b85811015612eef578135612ed481613147565b6001600160a01b031687529582019590820190600101612ec1565b509495945050505050565b81835260006020808501945082825b85811015612eef5763ffffffff612f1f83612acc565b1687529582019590820190600101612f09565b835160009082906020808801845b83811015612f655781516001600160a01b031685529382019390820190600101612f40565b50508651818801939250845b81811015612f9357845163ffffffff1684529382019392820192600101612f71565b505050612fac818660e01b6001600160e01b0319169052565b6004019695505050505050565b606081526000612fcd606083018789612eb2565b8281036020840152612fe0818688612efa565b91505063ffffffff831660408301529695505050505050565b60808152600061300d60808301888a612eb2565b8281036020840152613020818789612efa565b63ffffffff95909516604084015250506001600160a01b0391909116606090910152949350505050565b84815260606020808301829052908201849052600090859060808401835b8781101561309657833561307b81613147565b6001600160a01b031682529282019290820190600101613068565b5084810360408601528551808252908201925081860190845b818110156130cb578251855293830193918301916001016130af565b50929998505050505050505050565b600082198211156130ed576130ed613131565b500190565b600063ffffffff80831681851680830382111561311157613111613131565b01949350505050565b60008282101561312c5761312c613131565b500390565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461315c57600080fd5b5056fea26469706673582212203623903cdef9a8c0647bc7a19460e0774b453343d6cfb95b942d17a3fd381b4764736f6c6343000804003360a060405234801561001057600080fd5b5033606081901b60805261035461004c60003960008181604b0152818160bc015281816101080152818161013c015261018601526103546000f3fe6080604052600436106100345760003560e01c80630e769b2b146100395780637c1f3ffe14610089578063ab0ebff41461009e575b600080fd5b34801561004557600080fd5b5061006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009c6100973660046102d0565b6100b1565b005b61009c6100ac366004610306565b610131565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100f9576040516282b42960e81b815260040160405180910390fd5b61012d6001600160a01b0383167f0000000000000000000000000000000000000000000000000000000000000000836101af565b5050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610179576040516282b42960e81b815260040160405180910390fd5b6101ac6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682610233565b50565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af19150506101ea81610289565b61022d5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064015b60405180910390fd5b50505050565b600080600080600085875af19050806102845760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610224565b505050565b60003d8261029b57806000803e806000fd5b80602081146102b35780156102c457600092506102c9565b816000803e600051151592506102c9565b600192505b5050919050565b600080604083850312156102e2578182fd5b82356001600160a01b03811681146102f8578283fd5b946020939093013593505050565b600060208284031215610317578081fd5b503591905056fea2646970667358221220dc388eb287f9dcd9a42fd7c8fccffa4f3e1294eac8323bb76e82619efb8e115664736f6c63430008040033
Deployed Bytecode
0x6080604052600436106101185760003560e01c806377b1e4e9116100a0578063c7de644011610064578063c7de64401461034e578063d0e4b2f41461036e578063e10e51d61461038e578063e61cb05e146103cb578063ecef0ace146103eb57600080fd5b806377b1e4e91461027e5780638117abc11461029e57806388c662aa146102d2578063a5e3909e1461030e578063c3a8962c1461032e57600080fd5b80633bb66a7b116100e75780633bb66a7b146101cf5780633f26479e146101ef57806352844dd3146102065780636e5f69191461023e5780637601f7821461025e57600080fd5b80631267c6da146101245780631581130214610146578063189cbaa0146101665780631da0b8fc1461018657600080fd5b3661011f57005b600080fd5b34801561013057600080fd5b5061014461013f366004612ae0565b61040b565b005b34801561015257600080fd5b50610144610161366004612c7a565b6104a6565b34801561017257600080fd5b50610144610181366004612ae0565b61081a565b34801561019257600080fd5b506101bc6101a1366004612ae0565b6001600160a01b031660009081526002602052604090205490565b6040519081526020015b60405180910390f35b3480156101db57600080fd5b506101bc6101ea366004612ae0565b6108e5565b3480156101fb57600080fd5b506101bc620f424081565b34801561021257600080fd5b50610226610221366004612d8b565b61093e565b6040516001600160a01b0390911681526020016101c6565b34801561024a57600080fd5b50610144610259366004612d31565b610c4d565b34801561026a57600080fd5b50610226610279366004612e09565b610d82565b34801561028a57600080fd5b50610144610299366004612c7a565b611160565b3480156102aa57600080fd5b506102267f000000000000000000000000d94c0ce4f8eefa4ebf44bf6665688edeef213b3381565b3480156102de57600080fd5b506102266102ed366004612ae0565b6001600160a01b039081166000908152600260205260409020600101541690565b34801561031a57600080fd5b50610144610329366004612bc3565b6114a3565b34801561033a57600080fd5b506101bc610349366004612c68565b6117c6565b34801561035a57600080fd5b50610144610369366004612ae0565b61189a565b34801561037a57600080fd5b50610144610389366004612afc565b611969565b34801561039a57600080fd5b506102266103a9366004612ae0565b6001600160a01b03908116600090815260026020819052604090912001541690565b3480156103d757600080fd5b506101446103e6366004612bc3565b611a3b565b3480156103f757600080fd5b50610144610406366004612b34565b611d8b565b6001600160a01b0381811660009081526002602052604090206001015482911633146104515760405163472511eb60e11b81523360048201526024015b60405180910390fd5b6001600160a01b038216600081815260026020819052604080832090910180546001600160a01b0319169055517f6c2460a415b84be3720c209fe02f2cad7a6bcba21e8637afe8957b7ec4b6ef879190a25050565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050610535578251604051630e8c626560e41b815260040161044891815260200190565b8151835114610564578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f42406105718361203c565b63ffffffff16146105a7576105858261203c565b60405163fcc487c160e01b815263ffffffff9091166004820152602401610448565b82516000190160005b8181101561069e578481600101815181106105db57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031685828151811061060c57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161061063e5760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061066657634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16141561069657604051630db7e4c760e01b815260048101829052602401610448565b6001016105b0565b50600063ffffffff168382815181106106c757634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff1614156106f757604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff16111561072a5760405163308440e360e21b815263ffffffff82166004820152602401610448565b61079a8b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b925061208f915050565b61080d8b8b8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92508b91506120e19050565b5050505050505050505050565b6001600160a01b03818116600090815260026020526040902060010154829116331461085b5760405163472511eb60e11b8152336004820152602401610448565b6001600160a01b03808316600081815260026020819052604080832091820180546001600160a01b0319169055600190910154905191931691907f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d0908490a4506001600160a01b0316600090815260026020526040902060010180546001600160a01b0319169055565b6001600160a01b038116600090815260026020526040812054610909576000610915565b816001600160a01b0316315b6001600160a01b03831660009081526020819052604090205461093891906130da565b92915050565b6000858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208089028281018201909352888252909350889250879182918501908490808284376000920191909152505083518692506002111590506109cf578251604051630e8c626560e41b815260040161044891815260200190565b81518351146109fe578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240610a0b8361203c565b63ffffffff1614610a1f576105858261203c565b82516000190160005b81811015610b1657848160010181518110610a5357634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110610a8457634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610610ab65760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110610ade57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610b0e57604051630db7e4c760e01b815260048101829052602401610448565b600101610a28565b50600063ffffffff16838281518110610b3f57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610b6f57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115610ba25760405163308440e360e21b815263ffffffff82166004820152602401610448565b6000610c138a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b92506123b6915050565b9050610c3f7f000000000000000000000000d94c0ce4f8eefa4ebf44bf6665688edeef213b33826123ec565b9a9950505050505050505050565b60008167ffffffffffffffff811115610c7657634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610c9f578160200160208202803683370190505b50905060008415610cb657610cb386612491565b90505b60005b83811015610d3257610cff87868684818110610ce557634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610cfa9190612ae0565b6124e4565b838281518110610d1f57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152600101610cb9565b50856001600160a01b03167fa9e30bf144f83390a4fe47562a4e16892108102221c674ff538da0b72a83d17482868686604051610d72949392919061304a565b60405180910390a2505050505050565b600086868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050610e13578251604051630e8c626560e41b815260040161044891815260200190565b8151835114610e42578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240610e4f8361203c565b63ffffffff1614610e63576105858261203c565b82516000190160005b81811015610f5a57848160010181518110610e9757634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110610ec857634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610610efa5760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110610f2257634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610f5257604051630db7e4c760e01b815260048101829052602401610448565b600101610e6c565b50600063ffffffff16838281518110610f8357634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610fb357604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115610fe65760405163308440e360e21b815263ffffffff82166004820152602401610448565b60006110578b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92506123b6915050565b90506001600160a01b038616611098576110917f000000000000000000000000d94c0ce4f8eefa4ebf44bf6665688edeef213b3382612550565b94506110f5565b6110c17f000000000000000000000000d94c0ce4f8eefa4ebf44bf6665688edeef213b33612600565b6001600160a01b03818116600090815260026020526040902060010180546001600160a01b03191691891691909117905594505b6001600160a01b03851660008181526002602052604090819020839055517fd2bcf51a5767c814cfe0266a99141f75a32103bbf8c400fbc1ac0c3b73ce25e89061114a908e908e908e908e908e908e90612ff9565b60405180910390a2505050509695505050505050565b6001600160a01b0388811660009081526002602052604090206001015489911633146111a15760405163472511eb60e11b8152336004820152602401610448565b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050611230578251604051630e8c626560e41b815260040161044891815260200190565b815183511461125f578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061126c8361203c565b63ffffffff1614611280576105858261203c565b82516000190160005b81811015611377578481600101815181106112b457634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03168582815181106112e557634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316106113175760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061133f57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16141561136f57604051630db7e4c760e01b815260048101829052602401610448565b600101611289565b50600063ffffffff168382815181106113a057634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff1614156113d057604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156114035760405163308440e360e21b815263ffffffff82166004820152602401610448565b6114118c8b8b8b8b8b6126af565b6114958c8c8c8c80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508d92508c91506120e19050565b505050505050505050505050565b6001600160a01b0387811660009081526002602052604090206001015488911633146114e45760405163472511eb60e11b8152336004820152602401610448565b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050611573578251604051630e8c626560e41b815260040161044891815260200190565b81518351146115a2578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f42406115af8361203c565b63ffffffff16146115c3576105858261203c565b82516000190160005b818110156116ba578481600101815181106115f757634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031685828151811061162857634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161061165a5760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061168257634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff1614156116b257604051630db7e4c760e01b815260048101829052602401610448565b6001016115cc565b50600063ffffffff168382815181106116e357634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16141561171357604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156117465760405163308440e360e21b815263ffffffff82166004820152602401610448565b6117548b8b8b8b8b8b6126af565b61080d8b8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92508b91506127889050565b6001600160a01b0382166000908152600260205260408120546117ea576000611863565b6040516370a0823160e01b81526001600160a01b0384811660048301528316906370a082319060240160206040518083038186803b15801561182b57600080fd5b505afa15801561183f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118639190612e9a565b6001600160a01b0380841660009081526001602090815260408083209388168352929052205461189391906130da565b9392505050565b6001600160a01b038181166000908152600260208190526040909120015482911633146118dc5760405163472511eb60e11b8152336004820152602401610448565b6001600160a01b03808316600081815260026020819052604080832091820180546001600160a01b0319169055600190910154905133949190911692917f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d091a4506001600160a01b0316600090815260026020526040902060010180546001600160a01b03191633179055565b6001600160a01b0382811660009081526002602052604090206001015483911633146119aa5760405163472511eb60e11b8152336004820152602401610448565b816001600160a01b0381166119dd5760405163c369130760e01b81526001600160a01b0382166004820152602401610448565b6001600160a01b03848116600081815260026020819052604080832090910180546001600160a01b0319169488169485179055517f107cf6ea8668d533df1aab5bb8b6315bb0c25f0b6c955558d09368f290668fc79190a350505050565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050611aca578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611af9578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240611b068361203c565b63ffffffff1614611b1a576105858261203c565b82516000190160005b81811015611c1157848160010181518110611b4e57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110611b7f57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610611bb15760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110611bd957634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611c0957604051630db7e4c760e01b815260048101829052602401610448565b600101611b23565b50600063ffffffff16838281518110611c3a57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611c6a57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115611c9d5760405163308440e360e21b815263ffffffff82166004820152602401610448565b611d0d8a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b925061208f915050565b611d7f8a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b92508a91506127889050565b50505050505050505050565b6001600160a01b038681166000908152600260205260409020600101548791163314611dcc5760405163472511eb60e11b8152336004820152602401610448565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050611e5b578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611e8a578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240611e978361203c565b63ffffffff1614611eab576105858261203c565b82516000190160005b81811015611fa257848160010181518110611edf57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110611f1057634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610611f425760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110611f6a57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611f9a57604051630db7e4c760e01b815260048101829052602401610448565b600101611eb4565b50600063ffffffff16838281518110611fcb57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611ffb57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff16111561202e5760405163308440e360e21b815263ffffffff82166004820152602401610448565b611d7f8a8a8a8a8a8a6126af565b8051600090815b818110156120885783818151811061206b57634e487b7160e01b600052603260045260246000fd5b60200260200101518361207e91906130f2565b9250600101612043565b5050919050565b600061209c8484846123b6565b6001600160a01b03861660009081526002602052604090205490915081146120da5760405163dd5ff45760e01b815260048101829052602401610448565b5050505050565b6001600160a01b038581166000818152600160209081526040808320948b16808452949091528082205490516370a0823160e01b815260048101949094529092909183916370a082319060240160206040518083038186803b15801561214657600080fd5b505afa15801561215a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061217e9190612e9a565b9050801561218b57600019015b8115612198576001820391505b818101925081156121cc576001600160a01b038089166000908152600160208181526040808420948e168452939052919020555b6001600160a01b0384166121e057336121e2565b835b9350836001600160a01b0316886001600160a01b03168a6001600160a01b03167fb5ee5dc3d2c31a019bbf2c787e0e9c97971c96aceea1c38c12fc8fd25c536d468660405161223391815260200190565b60405180910390a463ffffffff851615612288576000620f424063ffffffff87168502046001600160a01b03808b166000908152600160209081526040808320938a1683529290522080548201905590930392505b865160005b81811015612340576122d1858983815181106122b957634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16620f424091020490565b6001600160a01b038b1660009081526001602052604081208b519091908c908590811061230e57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b031682528101919091526040016000208054909101905560010161228d565b505080156123ab57604051633e0f9fff60e11b81526001600160a01b038981166004830152602482018390528a1690637c1f3ffe90604401600060405180830381600087803b15801561239257600080fd5b505af11580156123a6573d6000803e3d6000fd5b505050505b505050505050505050565b60008383836040516020016123cd93929190612f32565b6040516020818303038152906040528051906020012090509392505050565b6000611893838330604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b6033820152606093841b60468201526d5af43d3d93803e605b57fd5bf3ff60901b605a820152921b6068830152607c8201526067808220609c830152605591012090565b6001600160a01b0381166000908152602081905260408120546124b69060019061311a565b6001600160a01b0383166000818152602081905260409020600190559091506124df9082612968565b919050565b6001600160a01b03808216600090815260016020818152604080842094871684529390529181205490916125179161311a565b6001600160a01b038084166000818152600160208181526040808420958a168452949052929020919091559091506109389084836129be565b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528360601b60468201526c5af43d3d93803e605b57fd5bf360981b605a820152826067826000f59150506001600160a01b0381166109385760405163380bbe1360e01b815260040160405180910390fd5b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528260601b60468201526c5af43d3d93803e605b57fd5bf360981b605a8201526067816000f09150506001600160a01b0381166124df57604051630985da9b60e41b815260040160405180910390fd5b600061272086868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a028281018201909352898252909350899250889182918501908490808284376000920191909152508792506123b6915050565b6001600160a01b0388166000818152600260205260409081902083905551919250907fce55a01ad467ce2f3080a2cef6eb951b65f489b97956f76c2c04bcddab92aaa9906127779089908990899089908990612fb9565b60405180910390a250505050505050565b6001600160a01b03851660008181526020819052604081205491319082156127b1576001830392505b5081810182156127d8576001600160a01b0388166000908152602081905260409020600190555b6001600160a01b0384166127ec57336127ee565b835b9350836001600160a01b0316886001600160a01b03167f87c3ca0a87d9b82033e4bc55e6d30621f8d7e0c9d8ca7988edfde8932787b77b8360405161283591815260200190565b60405180910390a363ffffffff85161561287a576001600160a01b03841660009081526020819052604090208054620f424063ffffffff881684020490810190915590035b865160005b81811015612900576128ab838983815181106122b957634e487b7160e01b600052603260045260246000fd5b6000808b84815181106128ce57634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b031682528101919091526040016000208054909101905560010161287f565b5050811561295e57604051632ac3affd60e21b8152600481018390526001600160a01b0389169063ab0ebff490602401600060405180830381600087803b15801561294a57600080fd5b505af1158015611495573d6000803e3d6000fd5b5050505050505050565b600080600080600085875af19050806129b95760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610448565b505050565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af19150506129f981612a3d565b612a375760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610448565b50505050565b60003d82612a4f57806000803e806000fd5b8060208114612a67578015612a785760009250612088565b816000803e60005115159250612088565b5060019392505050565b60008083601f840112612a93578182fd5b50813567ffffffffffffffff811115612aaa578182fd5b6020830191508360208260051b8501011115612ac557600080fd5b9250929050565b803563ffffffff811681146124df57600080fd5b600060208284031215612af1578081fd5b813561189381613147565b60008060408385031215612b0e578081fd5b8235612b1981613147565b91506020830135612b2981613147565b809150509250929050565b60008060008060008060808789031215612b4c578182fd5b8635612b5781613147565b9550602087013567ffffffffffffffff80821115612b73578384fd5b612b7f8a838b01612a82565b90975095506040890135915080821115612b97578384fd5b50612ba489828a01612a82565b9094509250612bb7905060608801612acc565b90509295509295509295565b600080600080600080600060a0888a031215612bdd578081fd5b8735612be881613147565b9650602088013567ffffffffffffffff80821115612c04578283fd5b612c108b838c01612a82565b909850965060408a0135915080821115612c28578283fd5b50612c358a828b01612a82565b9095509350612c48905060608901612acc565b91506080880135612c5881613147565b8091505092959891949750929550565b60008060408385031215612b0e578182fd5b60008060008060008060008060c0898b031215612c95578081fd5b8835612ca081613147565b97506020890135612cb081613147565b9650604089013567ffffffffffffffff80821115612ccc578283fd5b612cd88c838d01612a82565b909850965060608b0135915080821115612cf0578283fd5b50612cfd8b828c01612a82565b9095509350612d10905060808a01612acc565b915060a0890135612d2081613147565b809150509295985092959890939650565b60008060008060608587031215612d46578384fd5b8435612d5181613147565b935060208501359250604085013567ffffffffffffffff811115612d73578283fd5b612d7f87828801612a82565b95989497509550505050565b600080600080600060608688031215612da2578081fd5b853567ffffffffffffffff80821115612db9578283fd5b612dc589838a01612a82565b90975095506020880135915080821115612ddd578283fd5b50612dea88828901612a82565b9094509250612dfd905060408701612acc565b90509295509295909350565b60008060008060008060808789031215612e21578182fd5b863567ffffffffffffffff80821115612e38578384fd5b612e448a838b01612a82565b90985096506020890135915080821115612e5c578384fd5b50612e6989828a01612a82565b9095509350612e7c905060408801612acc565b91506060870135612e8c81613147565b809150509295509295509295565b600060208284031215612eab578081fd5b5051919050565b81835260006020808501945082825b85811015612eef578135612ed481613147565b6001600160a01b031687529582019590820190600101612ec1565b509495945050505050565b81835260006020808501945082825b85811015612eef5763ffffffff612f1f83612acc565b1687529582019590820190600101612f09565b835160009082906020808801845b83811015612f655781516001600160a01b031685529382019390820190600101612f40565b50508651818801939250845b81811015612f9357845163ffffffff1684529382019392820192600101612f71565b505050612fac818660e01b6001600160e01b0319169052565b6004019695505050505050565b606081526000612fcd606083018789612eb2565b8281036020840152612fe0818688612efa565b91505063ffffffff831660408301529695505050505050565b60808152600061300d60808301888a612eb2565b8281036020840152613020818789612efa565b63ffffffff95909516604084015250506001600160a01b0391909116606090910152949350505050565b84815260606020808301829052908201849052600090859060808401835b8781101561309657833561307b81613147565b6001600160a01b031682529282019290820190600101613068565b5084810360408601528551808252908201925081860190845b818110156130cb578251855293830193918301916001016130af565b50929998505050505050505050565b600082198211156130ed576130ed613131565b500190565b600063ffffffff80831681851680830382111561311157613111613131565b01949350505050565b60008282101561312c5761312c613131565b500390565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461315c57600080fd5b5056fea26469706673582212203623903cdef9a8c0647bc7a19460e0774b453343d6cfb95b942d17a3fd381b4764736f6c63430008040033
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$2,800,154.79
Net Worth in ETH
1,395.055567
Token Allocations
ETH
30.25%
WSTETH
25.39%
ETHFI
8.25%
Others
36.11%
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 27.98% | $2,007.54 | 390.2276 | $783,397.94 | |
| ETH | 25.39% | $2,767.01 | 256.932 | $710,933.35 | |
| ETH | 8.25% | $0.479795 | 481,646.3335 | $231,091.5 | |
| ETH | 6.41% | $3.5 | 51,251.5635 | $179,380.47 | |
| ETH | 4.94% | $6.68 | 20,697.1594 | $138,257.02 | |
| ETH | 4.32% | $0.999999 | 120,974.1402 | $120,974.02 | |
| ETH | 2.65% | $0.343792 | 215,630.738 | $74,132.12 | |
| ETH | 2.64% | $0.209137 | 353,154.1331 | $73,857.6 | |
| ETH | 2.28% | $0.125913 | 507,529.5426 | $63,904.76 | |
| ETH | 2.00% | $2,007.54 | 27.8992 | $56,008.7 | |
| ETH | 1.68% | $0.999667 | 47,071.3362 | $47,055.66 | |
| ETH | 1.18% | $0.115232 | 287,651.9369 | $33,146.71 | |
| ETH | 0.85% | $0.999901 | 23,848.4159 | $23,846.05 | |
| ETH | 0.62% | $0.350408 | 49,380.2642 | $17,303.23 | |
| ETH | 0.21% | $0.033155 | 181,280.3669 | $6,010.29 | |
| ETH | 0.20% | $0.049102 | 114,993.5209 | $5,646.42 | |
| ETH | 0.19% | $1.7 | 3,054.3792 | $5,192.44 | |
| ETH | 0.12% | $0.111644 | 29,745.6512 | $3,320.92 | |
| ETH | 0.06% | $0.15759 | 11,017.5333 | $1,736.25 | |
| ETH | 0.05% | $0.486842 | 3,054.421 | $1,487.02 | |
| ETH | 0.03% | $3.32 | 228.9796 | $760.21 | |
| ETH | 0.02% | $76,149 | 0.00750918 | $571.82 | |
| ETH | 0.02% | $0.014686 | 32,922.9316 | $483.52 | |
| ETH | 0.01% | $2,257.37 | 0.1839 | $415.23 | |
| ETH | 0.01% | $0.246347 | 1,327.0828 | $326.92 | |
| ETH | $0.00138 | 174,351.0149 | $240.56 | ||
| ETH | $76,331 | 0.00304354 | $232.32 | ||
| ETH | $126.02 | 1.8001 | $226.85 | ||
| ETH | $0.012185 | 15,580.0216 | $189.84 | ||
| ETH | $0.000005 | 36,752,567.0471 | $171.27 | ||
| ETH | $1.16 | 142.0814 | $164.81 | ||
| ETH | $0.99987 | 129.6848 | $129.67 | ||
| ETH | $8.85 | 12.7725 | $113.04 | ||
| ETH | $1.43 | 70.9517 | $101.46 | ||
| ETH | $99.44 | 0.9955 | $99 | ||
| ETH | $0.000282 | 343,401.9178 | $96.76 | ||
| ETH | $71.51 | 1.3056 | $93.36 | ||
| ETH | $0.00413 | 21,645.3646 | $89.4 | ||
| ETH | $194.74 | 0.3741 | $72.85 | ||
| ETH | $0.105279 | 667.1763 | $70.24 | ||
| ETH | $0.999758 | 58.6992 | $58.69 | ||
| ETH | 263,598,405.1334 | $46.6 | |||
| ETH | $1.46 | 31.5113 | $46.01 | ||
| ETH | $0.999892 | 40.9711 | $40.97 | ||
| ETH | $0.000033 | 1,201,947.8168 | $39.11 | ||
| ETH | $0.252919 | 133.571 | $33.78 | ||
| ETH | $2,879.06 | 0.0111 | $32.09 | ||
| ETH | $0.999521 | 30.8434 | $30.83 | ||
| ETH | $0.170989 | 172.4673 | $29.49 | ||
| ETH | $0.027762 | 1,020.2413 | $28.32 | ||
| ETH | $0.103479 | 240.8686 | $24.92 | ||
| ETH | $0.06674 | 336.5206 | $22.46 | ||
| ETH | $0.998963 | 22.3319 | $22.31 | ||
| ETH | 110,749,707.4794 | $21.15 | |||
| ETH | $0.123191 | 170.1771 | $20.96 | ||
| ETH | $0.000007 | 3,152,341.6325 | $20.84 | ||
| ETH | $0.000306 | 62,805.0267 | $19.24 | ||
| ETH | $0.116927 | 158.0382 | $18.48 | ||
| ETH | $0.240055 | 72.5005 | $17.4 | ||
| ETH | $0.605767 | 26.5139 | $16.06 | ||
| ETH | $0.209601 | 76.521 | $16.04 | ||
| ETH | $0.095498 | 161.9503 | $15.47 | ||
| ETH | $0.279912 | 54.4666 | $15.25 | ||
| ETH | $21.34 | 0.6771 | $14.45 | ||
| ETH | $0.167521 | 82.6036 | $13.84 | ||
| ETH | $0.355092 | 36.1645 | $12.84 | ||
| ETH | $0.13011 | 93.581 | $12.18 | ||
| ETH | $1.04 | 9.9507 | $10.35 | ||
| ETH | $0.147029 | 68.1382 | $10.02 | ||
| ETH | $0.002576 | 3,712.3673 | $9.56 | ||
| ETH | $0.078523 | 115.7234 | $9.09 | ||
| ETH | $0.000077 | 105,624.8046 | $8.18 | ||
| ETH | $0.118628 | 63.6512 | $7.55 | ||
| ETH | $0.143395 | 50.3764 | $7.22 | ||
| ETH | $0.041096 | 171.9899 | $7.07 | ||
| ETH | $0.995041 | 6.8746 | $6.84 | ||
| ETH | $0.108451 | 60.327 | $6.54 | ||
| ETH | $0.007089 | 900.1 | $6.38 | ||
| ETH | $1.82 | 3.4947 | $6.36 | ||
| ETH | $1.3 | 4.8476 | $6.3 | ||
| ETH | $0.087768 | 69.6733 | $6.12 | ||
| ETH | $0.076448 | 79.6122 | $6.09 | ||
| ETH | $0.087889 | 66.266 | $5.82 | ||
| ETH | $0.207631 | 27.6193 | $5.73 | ||
| ETH | $0.0513 | 101.2178 | $5.19 | ||
| ETH | $0.012216 | 391.2836 | $4.78 | ||
| ETH | $0.039776 | 116.9604 | $4.65 | ||
| ETH | $0.229248 | 19.6525 | $4.51 | ||
| ETH | $0.31639 | 14.0674 | $4.45 | ||
| ETH | $2.31 | 1.9261 | $4.45 | ||
| ETH | $1.25 | 3.4449 | $4.31 | ||
| ETH | $0.074958 | 53.9949 | $4.05 | ||
| ETH | $0.001337 | 2,973.4016 | $3.97 | ||
| ETH | $1.36 | 2.8648 | $3.9 | ||
| ETH | $0.294647 | 12.5337 | $3.69 | ||
| ETH | $0.000764 | 4,797.3524 | $3.66 | ||
| ETH | $0.007708 | 467.7638 | $3.61 | ||
| ETH | $0.000033 | 106,286.1364 | $3.53 | ||
| ETH | $0.027233 | 117.9565 | $3.21 | ||
| ETH | $0.023688 | 127.1484 | $3.01 | ||
| ETH | $0.021464 | 139.3295 | $2.99 | ||
| ETH | $6.35 | 0.4158 | $2.64 | ||
| ETH | $2,533.88 | 0.00100893 | $2.56 | ||
| ETH | 333,967,698.165 | $2.48 | |||
| ETH | $0.24533 | 10.0107 | $2.46 | ||
| ETH | $5,000.43 | 0.000466 | $2.33 | ||
| ETH | $0.001347 | 1,718.8403 | $2.32 | ||
| ETH | $0.050913 | 41.7187 | $2.12 | ||
| ETH | $0.008942 | 222.4767 | $1.99 | ||
| ETH | $0.409472 | 4.4911 | $1.84 | ||
| ETH | $0.992645 | 1.7415 | $1.73 | ||
| ETH | $0.017982 | 86.7761 | $1.56 | ||
| ETH | $0.005339 | 288.7506 | $1.54 | ||
| ETH | $0.109862 | 13.8448 | $1.52 | ||
| ETH | $0.000721 | 2,080.3759 | $1.5 | ||
| ETH | $0.581611 | 2.4521 | $1.43 | ||
| ETH | $0.035452 | 38.3275 | $1.36 | ||
| ETH | $0.019598 | 65.9915 | $1.29 | ||
| ETH | $0.998455 | 1.2279 | $1.23 | ||
| ETH | $0.473862 | 2.4698 | $1.17 | ||
| ETH | $0.145873 | 7.7106 | $1.12 | ||
| ETH | $0.027214 | 41.0228 | $1.12 | ||
| ETH | $0.001579 | 675.0781 | $1.07 | ||
| ETH | $0.00 | 0.9702 | $0.00 | ||
| ETH | 2,782,788.136 | $0.9009 | |||
| ETH | $0.015155 | 50.9426 | $0.772 | ||
| ETH | $0.79173 | 0.9745 | $0.7715 | ||
| ETH | $0.00 | 40.8954 | $0.00 | ||
| ETH | $0.040661 | 17.8944 | $0.7276 | ||
| ETH | $4.68 | 0.1509 | $0.7063 | ||
| ETH | $0.00007 | 10,000 | $0.6954 | ||
| ETH | $0.005492 | 122.8533 | $0.6747 | ||
| ETH | $0.999021 | 0.59 | $0.5894 | ||
| ETH | $0.073468 | 5.7951 | $0.4257 | ||
| ETH | $0.988703 | 0.4275 | $0.4226 | ||
| ETH | $0.000906 | 465.3492 | $0.4215 | ||
| ETH | $0.016262 | 25.0025 | $0.4065 | ||
| ETH | $0.006998 | 56.6134 | $0.3961 | ||
| ETH | $0.007996 | 44.1272 | $0.3528 | ||
| ETH | $0.000212 | 1,606.1908 | $0.3409 | ||
| ETH | $1.67 | 0.1982 | $0.3309 | ||
| ETH | $0.000717 | 430.0409 | $0.3085 | ||
| ETH | $0.999993 | 0.3023 | $0.3023 | ||
| ETH | $0.005564 | 50 | $0.2781 | ||
| ETH | $0.000239 | 1,000 | $0.2387 | ||
| ETH | $0.000214 | 1,092 | $0.2332 | ||
| ETH | 557,039,823.0333 | $0.2239 | |||
| ETH | $0.000212 | 1,026.7581 | $0.2179 | ||
| ETH | $0.117715 | 1.7197 | $0.2024 | ||
| ETH | $11.89 | 0.0154 | $0.1833 | ||
| ETH | $0.00078 | 226.7598 | $0.1769 | ||
| ETH | $0.00081 | 156.7334 | $0.1269 | ||
| ETH | $1 | 0.1103 | $0.1106 | ||
| BLAST | 4.43% | $2,263.38 | 54.7875 | $124,004.85 | |
| BLAST | $2,007.52 | 0.000000000000000005 | |||
| OP | 1.16% | $2,007.77 | 16.1663 | $32,458.27 | |
| OP | 0.57% | $0.189273 | 83,692.0977 | $15,840.62 | |
| OP | 0.07% | $1.31 | 1,520.511 | $1,991.87 | |
| OP | $76,114 | 0.00063802 | $48.56 | ||
| OP | $0.999907 | 12.9468 | $12.95 | ||
| OP | $1,108.01 | 0.009 | $9.97 | ||
| OP | $0.79218 | 11.316 | $8.96 | ||
| OP | $0.999337 | 1.76 | $1.76 | ||
| OP | $3.5 | 0.2086 | $0.73 | ||
| OP | $0.999907 | 0.6059 | $0.6058 | ||
| OP | $4.86 | 0.0978 | $0.4752 | ||
| OP | $2,263.38 | 0.0002005 | $0.4538 | ||
| OP | $0.999484 | 0.23 | $0.2298 | ||
| OP | $2,627.86 | 0.00007819 | $0.2054 | ||
| OP | $0.409939 | 0.3776 | $0.1547 | ||
| BASE | 1.10% | $2,007.43 | 15.3772 | $30,868.65 | |
| BASE | $2,263.38 | 0.1213 | $274.62 | ||
| BASE | $0.999907 | 44.0295 | $44.03 | ||
| BASE | $0.00077 | 23,581.0029 | $18.16 | ||
| BASE | $0.019895 | 736.32 | $14.65 | ||
| BASE | $0.000361 | 34,356.9121 | $12.4 | ||
| BASE | 1,644,432,895.091 | $12.17 | |||
| BASE | $0.000625 | 11,183.4639 | $6.98 | ||
| BASE | $0.000001 | 6,111,666.42 | $3.53 | ||
| BASE | $0.652725 | 3.7644 | $2.46 | ||
| BASE | $0.000229 | 10,663.1407 | $2.44 | ||
| BASE | $0.316625 | 3.951 | $1.25 | ||
| BASE | $0.007825 | 128.0267 | $1 | ||
| BASE | $31.44 | 0.0314 | $0.9866 | ||
| BASE | $0.000011 | 54,555.5122 | $0.6088 | ||
| BASE | $2,253.94 | 0.00017898 | $0.4034 | ||
| BASE | $0.000001 | 325,435.2513 | $0.3937 | ||
| BASE | 245,447,638.7354 | $0.3927 | |||
| BASE | $0.00001 | 31,148.8072 | $0.3214 | ||
| BASE | $0.112683 | 2.6421 | $0.2977 | ||
| BASE | $0.001226 | 236.8818 | $0.2904 | ||
| BASE | $0.00124 | 216.602 | $0.2685 | ||
| BASE | 1,488,044.6079 | $0.2626 | |||
| BASE | $0.021197 | 11.3417 | $0.2404 | ||
| BASE | $0.000105 | 2,134.9391 | $0.2246 | ||
| BASE | $0.00024 | 825.938 | $0.198 | ||
| BASE | $0.000615 | 303.7591 | $0.1869 | ||
| BASE | $0.000009 | 19,206.2431 | $0.1801 | ||
| BASE | $0.00048 | 301.7988 | $0.1449 | ||
| BASE | $0.000889 | 137.9814 | $0.1227 | ||
| BASE | $0.011679 | 9.8314 | $0.1148 | ||
| BASE | $0.002703 | 39.6245 | $0.107 | ||
| POL | 0.16% | $0.998295 | 4,440.5346 | $4,432.96 | |
| POL | 0.03% | $0.999998 | 850.2506 | $850.25 | |
| POL | 0.03% | $0.999998 | 745.2131 | $745.21 | |
| POL | 0.02% | $2,007.29 | 0.2495 | $500.75 | |
| POL | $0.105558 | 1,619.5784 | $170.96 | ||
| POL | $0.111672 | 216.9689 | $24.23 | ||
| POL | $0.99929 | 9.999 | $9.99 | ||
| POL | $2,773.1 | 0.00318747 | $8.84 | ||
| POL | $1.43 | 6.0958 | $8.72 | ||
| POL | $0.103434 | 26.3748 | $2.73 | ||
| POL | $0.282892 | 4.9005 | $1.39 | ||
| POL | $0.252726 | 4.9005 | $1.24 | ||
| POL | $0.999552 | 0.3692 | $0.369 | ||
| POL | $0.000012 | 14,523.7914 | $0.177 | ||
| GNO | 0.12% | $131.3 | 26.6047 | $3,493.2 | |
| GNO | 0.02% | $0.999811 | 508.4 | $508.3 | |
| GNO | $0.999811 | 127.4928 | $127.47 | ||
| ARB | 0.01% | $2,007.75 | 0.1894 | $380.21 | |
| ARB | 0.01% | $2,258.88 | 0.1527 | $345.03 | |
| ARB | $2,624.38 | 0.0982 | $257.6 | ||
| ARB | $0.115128 | 791.2863 | $91.1 | ||
| ARB | $0.999514 | 79.7668 | $79.73 | ||
| ARB | $0.999903 | 28.7125 | $28.71 | ||
| ARB | $0.999903 | 17.742 | $17.74 | ||
| ARB | $0.02774 | 564.3222 | $15.65 | ||
| ARB | $79.44 | 0.0253 | $2.01 | ||
| ARB | $2,317.13 | 0.0001105 | $0.256 | ||
| ARB | $2.59 | 0.0924 | $0.2393 | ||
| BSC | $1.02 | 100 | $101.99 | ||
| BSC | 1,690,317.0097 | $0.3909 | |||
| AVAX | $2,263.38 | 0.00502412 | $11.37 | ||
| AVAX | $1 | 6.0777 | $6.08 | ||
| AVAX | $0.999455 | 4.0759 | $4.07 | ||
| AVAX | $9.38 | 0.4155 | $3.9 | ||
| AVAX | $0.999455 | 3.7447 | $3.74 | ||
| AVAX | $1 | 2.7494 | $2.75 | ||
| AVAX | $0.999861 | 0.4966 | $0.4965 |
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.
${zeroWidthWarningMessage} Check the actual text at BaseName.
`;
}
const ensOnL2NoteHtml = ensOnL2Note != "" ? `Additional Info
Full Name:
${ensNameForkIconSrc}
Note:
- Name tag is displayed due to forward and reverse resolution. Find out more.
- A Domain Name is not necessarily held by a person popularly associated with the name. ${ensOnL2NoteHtml}
Other names resolving to this address:
${listOtherENSNames}
${moreOtherENSNames}
`;
return result;
}
// ===== UD name tag
const displayUDName = '';
const primaryUDName = '';
const showUDPublicNote = 'false';
let otherUDNamesHtml = "";
function initUDNamePopOver() {
//required to allow bootstrap popover to support table
$.fn.popover.Constructor.Default.allowList.table = [];
$.fn.popover.Constructor.Default.allowList.tr = [];
$.fn.popover.Constructor.Default.allowList.td = [];
$.fn.popover.Constructor.Default.allowList.th = [];
$.fn.popover.Constructor.Default.allowList.div = [];
$.fn.popover.Constructor.Default.allowList.tbody = [];
$.fn.popover.Constructor.Default.allowList.thead = [];
//allowList my inline styling for bootstrap
$.fn.popover.Constructor.Default.allowList['*'].push('style')
let unicodeWarningHtml = "";
if ($("#hdnIsUDContainUnicodeChars").val() == "true") {
unicodeWarningHtml =
`
${unicodeWarningMessage} Check the actual text at Unstoppable Domains.
`;
}
let zeroWidthWarningHtml = "";
if ($("#hdnIsUDContainZeroWidthChars").val() == "true") {
zeroWidthWarningHtml =
`
${unicodeWarningMessage} Check the actual text at Unstoppable Domains.
`;
}
const contentHtml =
`Additional Info
Full Name:
Note:
- Name tag is displayed due to forward and reverse resolution. Find out more
- A Domain Name is not necessarily held by a person popularly associated with the name.
Other names resolving to this address:
${listOtherUDNames}
${moreOtherUDNames}
`;
return result;
}
// ===== end UD name tag
const tooltipForTokenHolding = 'More than 201 tokens found, listing and displaying the total balance of the first 100 tokens only. Click on the Coins icon to see the full list and balance.';
var adjustPosition = 0;
$(document).ready(function () {
switchAmountToValue(document.getElementById("headerAmountValue"), 'Value (USD)', 'Amount', true);
switchAmountToValue(document.getElementById("headerIntAmountValue"), 'Value (USD)', 'Amount', true);
switchMethodColumn(document.getElementById("headerMethod"), 'Method', 'Action', true);
onDocumentReady();
$("[rel='tooltip']").tooltip();
$("[data-bs-toggle-second='tooltip']").tooltip({ trigger: 'hover' });
$("[rel='tooltipEns']").each(function () {
$(this).tooltip({ title: $(this).attr("tooltip-title") });
});
if (hash != '') {
activaTab(hash);
};
onAddressDocReady();
// Note: this is causing "Copied" tooltip not showing when copy button is clicked in V3, and seems like not applicable to v3, comment out first in case there is issue
//$('[data-bs-toggle="tooltip"]').click(function () {
// $('[data-bs-toggle="tooltip"]').tooltip("hide");
//});
document.getElementById("copyaddressbutton").classList.remove("disabled");
if ($("#txtSearchContract").length) {
initialiseKeyupOnDocReady();
}
if (!!$('#ensName')[0]) {
initEnsNamePopOver();
}
if (!!$("#udName")[0]) {
initUDNamePopOver();
}
handleToggle();
if (window.matchMedia("(max-width: 767px)").matches) {
// Mobile
adjustPosition = 90;
} else {
// Others
adjustPosition = 50;
}
if (tooltipForTokenHolding) {
const dropdownMenuBalance = document.getElementById("dropdownMenuBalance");
if (dropdownMenuBalance) {
const dropdownWrapper = dropdownMenuBalance.closest(".dropdown");
if (dropdownWrapper) {
dropdownWrapper.setAttribute("title", tooltipForTokenHolding);
new bootstrap.Tooltip(dropdownWrapper);
}
}
}
});
function displayAudit() {
$('html, body').animate({
scrollTop: $("#auditReportId").offset().top - adjustPosition
});
}
var cThemeMode = getCookie('displaymode');
function handleToggle() {
var className = document.getElementsByClassName('editor');
var classNameCount = className.length;
for (var j = 0; j t.innerWidth()) {
if (mb + d > tb) {
t.css('padding-bottom', ((mb + d) - tb));
}
}
else {
t.css('overflow', 'visible');
}
}).on('hidden.bs.dropdown', function () {
$(this).css({ 'padding-bottom': '', 'overflow': '' });
});
var btn_ERC20_sort = {
count: 0,
reminder_count: 2,
list: [],
default_list: [],
ERC20_sort_start: function (count) {
if (document.getElementsByClassName('list-custom-divider-ERC20')[0]) {
var self = this
if (count != undefined) {
self.count = count
}
var before_el = document.getElementsByClassName('list-custom-divider-ERC20')[0]
var parent_el = before_el.parentNode
var element_selector = parent_el.querySelectorAll(".list-custom-ERC20");
if (self.list.length == 0) {
element_selector.forEach(function (e) {
self.list.push(e);
self.default_list.push(e);
});
}
$(".list-custom-ERC20").remove()
var type = self.count % self.reminder_count
self.sortList(type, parent_el, before_el);
self.count++
}
},
sortList: function (type, parent_el, before_el) {
var self = this
var sorted_list = []
var icon_el = $(before_el).find('button').find('i')
switch (type) {
case 1:
icon_el.attr("class", "fad fa-sort-up")
sorted_list = self.sortUsdAsc()
break;
default:
icon_el.attr("class", "fad fa-sort-down")
sorted_list = self.sortUsdDesc()
}
for (var i = sorted_list.length - 1; i >= 0; i--) {
before_el.insertAdjacentElement('afterend', sorted_list[i])
}
},
sortUsdAsc: function () {
var self = this
var sort_list = self.list
sort_list.sort(function (a, b) {
var target_a_value = self.formatCurrencyToNumber(a.querySelector('.list-usd-value').textContent.trim() || -1);
var target_b_value = self.formatCurrencyToNumber(b.querySelector('.list-usd-value').textContent.trim() || -1);
if (target_a_value == -1 || target_b_value == -1) {
return 1;
}
if (target_a_value target_b_value) {
return 1;
}
return 0
});
return sort_list
},
sortUsdDesc: function () {
var self = this
var sort_list = self.list
sort_list.sort(function (a, b) {
var target_a_value = self.formatCurrencyToNumber(a.querySelector('.list-usd-value').textContent.trim() || -1);
var target_b_value = self.formatCurrencyToNumber(b.querySelector('.list-usd-value').textContent.trim() || -1);
if (target_a_value target_b_value) {
return -1;
}
return 0
});
return sort_list
},
formatCurrencyToNumber: function (strCurrency) {
if (typeof strCurrency == "number")
return strCurrency
else
return Number(strCurrency.replace(/[^0-9.-]+/g, ""));
},
}
function hrefTokenHolding() {
var location = "/tokenholdings?a=0x2ed6c4b5da6378c7897ac67ba9e43102feb694ee"
var queryString = $("input.form-control.form-control-xs.search.mb-3")[0].value
if (queryString) {
location += "&q=" + queryString
}
window.location.href = location
}
$(document).ready(function () {
$("#btn_ERC20_sort").on("click", function (event) {
event.preventDefault();
setTimeout(function () {
btn_ERC20_sort.ERC20_sort_start()
}, 10)
})
btn_ERC20_sort.ERC20_sort_start()
var mainAddress = $("#hdnAddress").val();
// user search for method filters
var searchFuncTimeOut;
$("#ContentPlaceHolder1_inputMethodName").on("keyup", function ($event) {
if (searchFuncTimeOut) {
clearTimeout(searchFuncTimeOut)
}
var searchTerm = $(this).val();
searchFuncTimeOut = setTimeout(function () {
searchFunctions( searchTerm);
}, 350);
});
var isSearchFunctions = false;
$("#dropdownMethod").on("click", function (e) {
if (isSearchFunctions === false) {
searchFunctions('');
isSearchFunctions = true;
}
});
const litDefaultMethodFilterHtml = '';
function searchFunctions(searchTerm) {
if (searchTerm === '' || searchTerm.length > 3) {
const curPath = encodeURIComponent(window.location.search);
$.ajax({
type: 'Get',
url: `/functionSearchHandler.ashx?ca=${mainAddress}&func=${searchTerm ?? ''}&curPath=${curPath}`,
success: function (response) {
$("#searchFunctionResult").html('');
if (response && response.length > 0) {
for (var i = 0; i
${response[i].name}
${response[i].methodId}
`
);
}
$("[data-bs-toggle='tooltip']").tooltip();
}
else {
$("#searchFunctionResult").append(
`