Source Code
Overview
ETH Balance
0.001 ETH
Token Holdings
More Info
ContractCreator
Multichain Info
N/A
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
Advanced mode:
Parent Transaction Hash | Method | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|---|
0x3d605d80 | 5666684 | 405 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5666679 | 405 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653553 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653541 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653515 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653450 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653445 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653420 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653346 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653341 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653255 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653233 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653178 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653169 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653112 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653088 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653084 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653064 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5653025 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5652985 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5652969 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5652936 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5652881 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5652848 | 407 days ago | Contract Creation | 0 ETH | |||
0x3d605d80 | 5652749 | 407 days ago | Contract Creation | 0 ETH |
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 Source Code Verified (Exact Match)
Contract Name:
SplitMain
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.23; 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); } /** @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); } /** @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; // 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 != address(0) ? distributorAddress : msg.sender ] += 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; // 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 != address(0) ? distributorAddress : msg.sender ] += 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.23; 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 */ event CreateSplit(address indexed split); /** @notice emitted after each successful split update * @param split Address of the updated split */ event UpdateSplit(address indexed split); /** @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.23; 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.23; /// @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; /// @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 //////////////////////////////////////////////////////////////*/ 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 { address recoveredAddress = ecrecover( keccak256( abi.encodePacked( "\x19\x01", DOMAIN_SEPARATOR(), keccak256( abi.encode( keccak256( "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)" ), owner, spender, value, nonces[owner]++, deadline ) ) ) ), 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); } }
// 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) /// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer. /// @dev Note that none of the functions in this library check that a token has code at all! That responsibility is delegated to the caller. library SafeTransferLib { /*////////////////////////////////////////////////////////////// ETH OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferETH(address to, uint256 amount) internal { bool success; assembly { // Transfer the ETH and store if it succeeded or not. success := call(gas(), to, amount, 0, 0, 0, 0) } require(success, "ETH_TRANSFER_FAILED"); } /*////////////////////////////////////////////////////////////// ERC20 OPERATIONS //////////////////////////////////////////////////////////////*/ function safeTransferFrom( ERC20 token, address from, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), from) // Append the "from" argument. mstore(add(freeMemoryPointer, 36), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 68), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 100 because the length of our calldata totals up like so: 4 + 32 * 3. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 100, 0, 32) ) } require(success, "TRANSFER_FROM_FAILED"); } function safeTransfer( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "TRANSFER_FAILED"); } function safeApprove( ERC20 token, address to, uint256 amount ) internal { bool success; assembly { // Get a pointer to some free memory. let freeMemoryPointer := mload(0x40) // Write the abi-encoded calldata into memory, beginning with the function selector. mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) mstore(add(freeMemoryPointer, 4), to) // Append the "to" argument. mstore(add(freeMemoryPointer, 36), amount) // Append the "amount" argument. success := and( // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(and(eq(mload(0), 1), gt(returndatasize(), 31)), iszero(returndatasize())), // We use 68 because the length of our calldata totals up like so: 4 + 32 * 2. // We use 0 and 32 to copy up to 32 bytes of return data into the scratch space. // Counterintuitively, this call must be positioned second to the or() call in the // surrounding and() call or else returndatasize() will be zero during the computation. call(gas(), token, 0, freeMemoryPointer, 68, 0, 32) ) } require(success, "APPROVE_FAILED"); } }
{ "remappings": [ "@openzeppelin/=node_modules/@openzeppelin/", "@rari-capital/=node_modules/@rari-capital/", "hardhat-deploy/=node_modules/hardhat-deploy/", "hardhat/=node_modules/hardhat/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
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"}],"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"}],"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
60a06040523480156200001157600080fd5b50604051620000209062000050565b604051809103906000f0801580156200003d573d6000803e3d6000fd5b506001600160a01b03166080526200005e565b6103598062002ea183390190565b608051612e126200008f600039600081816102b001528181610ba801528181610f960152610fc70152612e126000f3fe6080604052600436106101185760003560e01c806377b1e4e9116100a0578063c7de644011610064578063c7de64401461034e578063d0e4b2f41461036e578063e10e51d61461038e578063e61cb05e146103cb578063ecef0ace146103eb57600080fd5b806377b1e4e91461027e5780638117abc11461029e57806388c662aa146102d2578063a5e3909e1461030e578063c3a8962c1461032e57600080fd5b80633bb66a7b116100e75780633bb66a7b146101cf5780633f26479e146101ef57806352844dd3146102065780636e5f69191461023e5780637601f7821461025e57600080fd5b80631267c6da146101245780631581130214610146578063189cbaa0146101665780631da0b8fc1461018657600080fd5b3661011f57005b600080fd5b34801561013057600080fd5b5061014461013f366004612806565b61040b565b005b34801561015257600080fd5b50610144610161366004612883565b6104a6565b34801561017257600080fd5b50610144610181366004612806565b6107e0565b34801561019257600080fd5b506101bc6101a1366004612806565b6001600160a01b031660009081526002602052604090205490565b6040519081526020015b60405180910390f35b3480156101db57600080fd5b506101bc6101ea366004612806565b6108ab565b3480156101fb57600080fd5b506101bc620f424081565b34801561021257600080fd5b5061022661022136600461293d565b610906565b6040516001600160a01b0390911681526020016101c6565b34801561024a57600080fd5b506101446102593660046129be565b610bdb565b34801561026a57600080fd5b50610226610279366004612a1a565b610ce6565b34801561028a57600080fd5b50610144610299366004612883565b61106e565b3480156102aa57600080fd5b506102267f000000000000000000000000000000000000000000000000000000000000000081565b3480156102de57600080fd5b506102266102ed366004612806565b6001600160a01b039081166000908152600260205260409020600101541690565b34801561031a57600080fd5b50610144610329366004612aae565b611377565b34801561033a57600080fd5b506101bc610349366004612b56565b611660565b34801561035a57600080fd5b50610144610369366004612806565b611727565b34801561037a57600080fd5b50610144610389366004612b56565b6117f6565b34801561039a57600080fd5b506102266103a9366004612806565b6001600160a01b03908116600090815260026020819052604090912001541690565b3480156103d757600080fd5b506101446103e6366004612aae565b6118c8565b3480156103f757600080fd5b50610144610406366004612b8f565b611bde565b6001600160a01b0381811660009081526002602052604090206001015482911633146104515760405163472511eb60e11b81523360048201526024015b60405180910390fd5b6001600160a01b038216600081815260026020819052604080832090910180546001600160a01b0319169055517f6c2460a415b84be3720c209fe02f2cad7a6bcba21e8637afe8957b7ec4b6ef879190a25050565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050610535578251604051630e8c626560e41b815260040161044891815260200190565b8151835114610564578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061057183611e55565b63ffffffff16146105a75761058582611e55565b60405163fcc487c160e01b815263ffffffff9091166004820152602401610448565b82516000190160005b81811015610673578481600101815181106105cd576105cd612c21565b60200260200101516001600160a01b03168582815181106105f0576105f0612c21565b60200260200101516001600160a01b0316106106225760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061063c5761063c612c21565b602002602001015163ffffffff160361066b57604051630db7e4c760e01b815260048101829052602401610448565b6001016105b0565b50600063ffffffff1683828151811061068e5761068e612c21565b602002602001015163ffffffff16036106bd57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156106f05760405163308440e360e21b815263ffffffff82166004820152602401610448565b6107608b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b9250611e9a915050565b6107d38b8b8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92508b9150611eec9050565b5050505050505050505050565b6001600160a01b0381811660009081526002602052604090206001015482911633146108215760405163472511eb60e11b8152336004820152602401610448565b6001600160a01b03808316600081815260026020819052604080832091820180546001600160a01b0319169055600190910154905191931691907f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d0908490a4506001600160a01b0316600090815260026020526040902060010180546001600160a01b0319169055565b6001600160a01b03811660009081526002602052604081205481036108d15760006108dd565b816001600160a01b0316315b6001600160a01b0383166000908152602081905260409020546109009190612c4d565b92915050565b600085858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050610997578251604051630e8c626560e41b815260040161044891815260200190565b81518351146109c6578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f42406109d383611e55565b63ffffffff16146109e75761058582611e55565b82516000190160005b81811015610ab357848160010181518110610a0d57610a0d612c21565b60200260200101516001600160a01b0316858281518110610a3057610a30612c21565b60200260200101516001600160a01b031610610a625760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110610a7c57610a7c612c21565b602002602001015163ffffffff1603610aab57604051630db7e4c760e01b815260048101829052602401610448565b6001016109f0565b50600063ffffffff16838281518110610ace57610ace612c21565b602002602001015163ffffffff1603610afd57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115610b305760405163308440e360e21b815263ffffffff82166004820152602401610448565b6000610ba18a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b925061219b915050565b9050610bcd7f0000000000000000000000000000000000000000000000000000000000000000826121d1565b9a9950505050505050505050565b60008167ffffffffffffffff811115610bf657610bf6612c60565b604051908082528060200260200182016040528015610c1f578160200160208202803683370190505b50905060008415610c3657610c3386612276565b90505b60005b83811015610c9657610c7187868684818110610c5757610c57612c21565b9050602002016020810190610c6c9190612806565b6122c9565b838281518110610c8357610c83612c21565b6020908102919091010152600101610c39565b50856001600160a01b03167fa9e30bf144f83390a4fe47562a4e16892108102221c674ff538da0b72a83d17482868686604051610cd69493929190612c76565b60405180910390a2505050505050565b600086868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050610d77578251604051630e8c626560e41b815260040161044891815260200190565b8151835114610da6578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240610db383611e55565b63ffffffff1614610dc75761058582611e55565b82516000190160005b81811015610e9357848160010181518110610ded57610ded612c21565b60200260200101516001600160a01b0316858281518110610e1057610e10612c21565b60200260200101516001600160a01b031610610e425760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110610e5c57610e5c612c21565b602002602001015163ffffffff1603610e8b57604051630db7e4c760e01b815260048101829052602401610448565b600101610dd0565b50600063ffffffff16838281518110610eae57610eae612c21565b602002602001015163ffffffff1603610edd57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115610f105760405163308440e360e21b815263ffffffff82166004820152602401610448565b6000610f818b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c925061219b915050565b90506001600160a01b038616610fc257610fbb7f000000000000000000000000000000000000000000000000000000000000000082612335565b945061101f565b610feb7f00000000000000000000000000000000000000000000000000000000000000006123e5565b6001600160a01b03818116600090815260026020526040902060010180546001600160a01b03191691891691909117905594505b6001600160a01b038516600081815260026020526040808220849055517f8d5f9943c664a3edaf4d3eb18cc5e2c45a7d2dc5869be33d33bbc0fff9bc25909190a2505050509695505050505050565b6001600160a01b0388811660009081526002602052604090206001015489911633146110af5760405163472511eb60e11b8152336004820152602401610448565b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a0282810182019093528982529093508992508891829185019084908082843760009201919091525050835187925060021115905061113e578251604051630e8c626560e41b815260040161044891815260200190565b815183511461116d578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061117a83611e55565b63ffffffff161461118e5761058582611e55565b82516000190160005b8181101561125a578481600101815181106111b4576111b4612c21565b60200260200101516001600160a01b03168582815181106111d7576111d7612c21565b60200260200101516001600160a01b0316106112095760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061122357611223612c21565b602002602001015163ffffffff160361125257604051630db7e4c760e01b815260048101829052602401610448565b600101611197565b50600063ffffffff1683828151811061127557611275612c21565b602002602001015163ffffffff16036112a457604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156112d75760405163308440e360e21b815263ffffffff82166004820152602401610448565b6112e58c8b8b8b8b8b612494565b6113698c8c8c8c80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508d92508c9150611eec9050565b505050505050505050505050565b6001600160a01b0387811660009081526002602052604090206001015488911633146113b85760405163472511eb60e11b8152336004820152602401610448565b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050611447578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611476578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061148383611e55565b63ffffffff16146114975761058582611e55565b82516000190160005b81811015611563578481600101815181106114bd576114bd612c21565b60200260200101516001600160a01b03168582815181106114e0576114e0612c21565b60200260200101516001600160a01b0316106115125760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061152c5761152c612c21565b602002602001015163ffffffff160361155b57604051630db7e4c760e01b815260048101829052602401610448565b6001016114a0565b50600063ffffffff1683828151811061157e5761157e612c21565b602002602001015163ffffffff16036115ad57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156115e05760405163308440e360e21b815263ffffffff82166004820152602401610448565b6115ee8b8b8b8b8b8b612494565b6107d38b8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92508b91506125549050565b6001600160a01b03821660009081526002602052604081205481036116865760006116f0565b6040516370a0823160e01b81526001600160a01b0384811660048301528316906370a0823190602401602060405180830381865afa1580156116cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f09190612d07565b6001600160a01b038084166000908152600160209081526040808320938816835292905220546117209190612c4d565b9392505050565b6001600160a01b038181166000908152600260208190526040909120015482911633146117695760405163472511eb60e11b8152336004820152602401610448565b6001600160a01b03808316600081815260026020819052604080832091820180546001600160a01b0319169055600190910154905133949190911692917f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d091a4506001600160a01b0316600090815260026020526040902060010180546001600160a01b03191633179055565b6001600160a01b0382811660009081526002602052604090206001015483911633146118375760405163472511eb60e11b8152336004820152602401610448565b816001600160a01b03811661186a5760405163c369130760e01b81526001600160a01b0382166004820152602401610448565b6001600160a01b03848116600081815260026020819052604080832090910180546001600160a01b0319169488169485179055517f107cf6ea8668d533df1aab5bb8b6315bb0c25f0b6c955558d09368f290668fc79190a350505050565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050611957578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611986578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061199383611e55565b63ffffffff16146119a75761058582611e55565b82516000190160005b81811015611a73578481600101815181106119cd576119cd612c21565b60200260200101516001600160a01b03168582815181106119f0576119f0612c21565b60200260200101516001600160a01b031610611a225760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110611a3c57611a3c612c21565b602002602001015163ffffffff1603611a6b57604051630db7e4c760e01b815260048101829052602401610448565b6001016119b0565b50600063ffffffff16838281518110611a8e57611a8e612c21565b602002602001015163ffffffff1603611abd57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115611af05760405163308440e360e21b815263ffffffff82166004820152602401610448565b611b608a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b9250611e9a915050565b611bd28a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b92508a91506125549050565b50505050505050505050565b6001600160a01b038681166000908152600260205260409020600101548791163314611c1f5760405163472511eb60e11b8152336004820152602401610448565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050611cae578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611cdd578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240611cea83611e55565b63ffffffff1614611cfe5761058582611e55565b82516000190160005b81811015611dca57848160010181518110611d2457611d24612c21565b60200260200101516001600160a01b0316858281518110611d4757611d47612c21565b60200260200101516001600160a01b031610611d795760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110611d9357611d93612c21565b602002602001015163ffffffff1603611dc257604051630db7e4c760e01b815260048101829052602401610448565b600101611d07565b50600063ffffffff16838281518110611de557611de5612c21565b602002602001015163ffffffff1603611e1457604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115611e475760405163308440e360e21b815263ffffffff82166004820152602401610448565b611bd28a8a8a8a8a8a612494565b8051600090815b81811015611e9357838181518110611e7657611e76612c21565b602002602001015183611e899190612d20565b9250600101611e5c565b5050919050565b6000611ea784848461219b565b6001600160a01b0386166000908152600260205260409020549091508114611ee55760405163dd5ff45760e01b815260048101829052602401610448565b5050505050565b6001600160a01b038581166000818152600160209081526040808320948b16808452949091528082205490516370a0823160e01b815260048101949094529092909183916370a0823190602401602060405180830381865afa158015611f56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7a9190612d07565b90508015611f8757600019015b8115611f94576001820391505b81810192508115611fc8576001600160a01b038089166000908152600160208181526040808420948e168452939052919020555b836001600160a01b0316886001600160a01b03168a6001600160a01b03167fb5ee5dc3d2c31a019bbf2c787e0e9c97971c96aceea1c38c12fc8fd25c536d468660405161201791815260200190565b60405180910390a463ffffffff851615612089576001600160a01b038881166000908152600160205260408120620f424063ffffffff89168702049283929088166120625733612064565b875b6001600160a01b03168152602081019190915260400160002080549091019055909203915b865160005b81811015612125576120c4858983815181106120ac576120ac612c21565b602002602001015163ffffffff16620f424091020490565b6001600160a01b038b1660009081526001602052604081208b519091908c90859081106120f3576120f3612c21565b6020908102919091018101516001600160a01b031682528101919091526040016000208054909101905560010161208e565b5050801561219057604051633e0f9fff60e11b81526001600160a01b038981166004830152602482018390528a1690637c1f3ffe90604401600060405180830381600087803b15801561217757600080fd5b505af115801561218b573d6000803e3d6000fd5b505050505b505050505050505050565b60008383836040516020016121b293929190612d44565b6040516020818303038152906040528051906020012090509392505050565b6000611720838330604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b6033820152606093841b60468201526d5af43d3d93803e605b57fd5bf3ff60901b605a820152921b6068830152607c8201526067808220609c830152605591012090565b6001600160a01b03811660009081526020819052604081205461229b90600190612dc9565b6001600160a01b0383166000818152602081905260409020600190559091506122c4908261271a565b919050565b6001600160a01b03808216600090815260016020818152604080842094871684529390529181205490916122fc91612dc9565b6001600160a01b038084166000818152600160208181526040808420958a16845294905292902091909155909150610900908483612770565b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528360601b60468201526c5af43d3d93803e605b57fd5bf360981b605a820152826067826000f59150506001600160a01b0381166109005760405163380bbe1360e01b815260040160405180910390fd5b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528260601b60468201526c5af43d3d93803e605b57fd5bf360981b605a8201526067816000f09150506001600160a01b0381166122c457604051630985da9b60e41b815260040160405180910390fd5b600061250586868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a0282810182019093528982529093508992508891829185019084908082843760009201919091525087925061219b915050565b6001600160a01b0388166000818152600260205260408082208490555192935090917f45e1e99513dd915ac128b94953ca64c6375717ea1894b3114db08cdca51debd29190a250505050505050565b6001600160a01b038516600081815260208190526040812054913190821561257d576001830392505b5081810182156125a4576001600160a01b0388166000908152602081905260409020600190555b836001600160a01b0316886001600160a01b03167f87c3ca0a87d9b82033e4bc55e6d30621f8d7e0c9d8ca7988edfde8932787b77b836040516125e991815260200190565b60405180910390a363ffffffff85161561264857620f424063ffffffff8616820204806000806001600160a01b0388166126235733612625565b875b6001600160a01b0316815260208101919091526040016000208054909101905590035b865160005b818110156126b25761266b838983815181106120ac576120ac612c21565b6000808b848151811061268057612680612c21565b6020908102919091018101516001600160a01b031682528101919091526040016000208054909101905560010161264d565b5050811561271057604051632ac3affd60e21b8152600481018390526001600160a01b0389169063ab0ebff490602401600060405180830381600087803b1580156126fc57600080fd5b505af1158015611369573d6000803e3d6000fd5b5050505050505050565b600080600080600085875af190508061276b5760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610448565b505050565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806127e85760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610448565b50505050565b6001600160a01b038116811461280357600080fd5b50565b60006020828403121561281857600080fd5b8135611720816127ee565b60008083601f84011261283557600080fd5b50813567ffffffffffffffff81111561284d57600080fd5b6020830191508360208260051b850101111561286857600080fd5b9250929050565b803563ffffffff811681146122c457600080fd5b60008060008060008060008060c0898b03121561289f57600080fd5b88356128aa816127ee565b975060208901356128ba816127ee565b9650604089013567ffffffffffffffff808211156128d757600080fd5b6128e38c838d01612823565b909850965060608b01359150808211156128fc57600080fd5b506129098b828c01612823565b909550935061291c905060808a0161286f565b915060a089013561292c816127ee565b809150509295985092959890939650565b60008060008060006060868803121561295557600080fd5b853567ffffffffffffffff8082111561296d57600080fd5b61297989838a01612823565b9097509550602088013591508082111561299257600080fd5b5061299f88828901612823565b90945092506129b290506040870161286f565b90509295509295909350565b600080600080606085870312156129d457600080fd5b84356129df816127ee565b935060208501359250604085013567ffffffffffffffff811115612a0257600080fd5b612a0e87828801612823565b95989497509550505050565b60008060008060008060808789031215612a3357600080fd5b863567ffffffffffffffff80821115612a4b57600080fd5b612a578a838b01612823565b90985096506020890135915080821115612a7057600080fd5b50612a7d89828a01612823565b9095509350612a9090506040880161286f565b91506060870135612aa0816127ee565b809150509295509295509295565b600080600080600080600060a0888a031215612ac957600080fd5b8735612ad4816127ee565b9650602088013567ffffffffffffffff80821115612af157600080fd5b612afd8b838c01612823565b909850965060408a0135915080821115612b1657600080fd5b50612b238a828b01612823565b9095509350612b3690506060890161286f565b91506080880135612b46816127ee565b8091505092959891949750929550565b60008060408385031215612b6957600080fd5b8235612b74816127ee565b91506020830135612b84816127ee565b809150509250929050565b60008060008060008060808789031215612ba857600080fd5b8635612bb3816127ee565b9550602087013567ffffffffffffffff80821115612bd057600080fd5b612bdc8a838b01612823565b90975095506040890135915080821115612bf557600080fd5b50612c0289828a01612823565b9094509250612c1590506060880161286f565b90509295509295509295565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561090057610900612c37565b634e487b7160e01b600052604160045260246000fd5b84815260606020808301829052908201849052600090859060808401835b87811015612cc2578335612ca7816127ee565b6001600160a01b031682529282019290820190600101612c94565b508481036040860152855180825290820192508186019060005b81811015612cf857825185529383019391830191600101612cdc565b50929998505050505050505050565b600060208284031215612d1957600080fd5b5051919050565b63ffffffff818116838216019080821115612d3d57612d3d612c37565b5092915050565b835160009082906020808801845b83811015612d775781516001600160a01b031685529382019390820190600101612d52565b5050865181880193925060005b81811015612da657845163ffffffff1684529382019392820192600101612d84565b50505060e09490941b6001600160e01b0319168452505060049091019392505050565b8181038181111561090057610900612c3756fea2646970667358221220ddbc0708d8e0f5bd7d5419396866023857b64aa69c0362963b654a1c828d919364736f6c6343000817003360a060405234801561001057600080fd5b503360805260805161030f61004a60003960008181604b0152818160bc015281816101080152818161013c0152610186015261030f6000f3fe6080604052600436106100345760003560e01c80630e769b2b146100395780637c1f3ffe14610089578063ab0ebff41461009e575b600080fd5b34801561004557600080fd5b5061006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009c610097366004610288565b6100b1565b005b61009c6100ac3660046102c0565b610131565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100f9576040516282b42960e81b815260040160405180910390fd5b61012d6001600160a01b0383167f0000000000000000000000000000000000000000000000000000000000000000836101af565b5050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610179576040516282b42960e81b815260040160405180910390fd5b6101ac6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682610232565b50565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d116001600051141617169150508061022c5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064015b60405180910390fd5b50505050565b600080600080600085875af19050806102835760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610223565b505050565b6000806040838503121561029b57600080fd5b82356001600160a01b03811681146102b257600080fd5b946020939093013593505050565b6000602082840312156102d257600080fd5b503591905056fea26469706673582212208d240fb24b9b12ea652bf1d39cf7a4cf0989a0ce82168ffb4cf0da1afd721a2b64736f6c63430008170033
Deployed Bytecode
0x6080604052600436106101185760003560e01c806377b1e4e9116100a0578063c7de644011610064578063c7de64401461034e578063d0e4b2f41461036e578063e10e51d61461038e578063e61cb05e146103cb578063ecef0ace146103eb57600080fd5b806377b1e4e91461027e5780638117abc11461029e57806388c662aa146102d2578063a5e3909e1461030e578063c3a8962c1461032e57600080fd5b80633bb66a7b116100e75780633bb66a7b146101cf5780633f26479e146101ef57806352844dd3146102065780636e5f69191461023e5780637601f7821461025e57600080fd5b80631267c6da146101245780631581130214610146578063189cbaa0146101665780631da0b8fc1461018657600080fd5b3661011f57005b600080fd5b34801561013057600080fd5b5061014461013f366004612806565b61040b565b005b34801561015257600080fd5b50610144610161366004612883565b6104a6565b34801561017257600080fd5b50610144610181366004612806565b6107e0565b34801561019257600080fd5b506101bc6101a1366004612806565b6001600160a01b031660009081526002602052604090205490565b6040519081526020015b60405180910390f35b3480156101db57600080fd5b506101bc6101ea366004612806565b6108ab565b3480156101fb57600080fd5b506101bc620f424081565b34801561021257600080fd5b5061022661022136600461293d565b610906565b6040516001600160a01b0390911681526020016101c6565b34801561024a57600080fd5b506101446102593660046129be565b610bdb565b34801561026a57600080fd5b50610226610279366004612a1a565b610ce6565b34801561028a57600080fd5b50610144610299366004612883565b61106e565b3480156102aa57600080fd5b506102267f000000000000000000000000c071e3a3d647506ee4c2c57b2ba6df331acb53a381565b3480156102de57600080fd5b506102266102ed366004612806565b6001600160a01b039081166000908152600260205260409020600101541690565b34801561031a57600080fd5b50610144610329366004612aae565b611377565b34801561033a57600080fd5b506101bc610349366004612b56565b611660565b34801561035a57600080fd5b50610144610369366004612806565b611727565b34801561037a57600080fd5b50610144610389366004612b56565b6117f6565b34801561039a57600080fd5b506102266103a9366004612806565b6001600160a01b03908116600090815260026020819052604090912001541690565b3480156103d757600080fd5b506101446103e6366004612aae565b6118c8565b3480156103f757600080fd5b50610144610406366004612b8f565b611bde565b6001600160a01b0381811660009081526002602052604090206001015482911633146104515760405163472511eb60e11b81523360048201526024015b60405180910390fd5b6001600160a01b038216600081815260026020819052604080832090910180546001600160a01b0319169055517f6c2460a415b84be3720c209fe02f2cad7a6bcba21e8637afe8957b7ec4b6ef879190a25050565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050610535578251604051630e8c626560e41b815260040161044891815260200190565b8151835114610564578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061057183611e55565b63ffffffff16146105a75761058582611e55565b60405163fcc487c160e01b815263ffffffff9091166004820152602401610448565b82516000190160005b81811015610673578481600101815181106105cd576105cd612c21565b60200260200101516001600160a01b03168582815181106105f0576105f0612c21565b60200260200101516001600160a01b0316106106225760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061063c5761063c612c21565b602002602001015163ffffffff160361066b57604051630db7e4c760e01b815260048101829052602401610448565b6001016105b0565b50600063ffffffff1683828151811061068e5761068e612c21565b602002602001015163ffffffff16036106bd57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156106f05760405163308440e360e21b815263ffffffff82166004820152602401610448565b6107608b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b9250611e9a915050565b6107d38b8b8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92508b9150611eec9050565b5050505050505050505050565b6001600160a01b0381811660009081526002602052604090206001015482911633146108215760405163472511eb60e11b8152336004820152602401610448565b6001600160a01b03808316600081815260026020819052604080832091820180546001600160a01b0319169055600190910154905191931691907f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d0908490a4506001600160a01b0316600090815260026020526040902060010180546001600160a01b0319169055565b6001600160a01b03811660009081526002602052604081205481036108d15760006108dd565b816001600160a01b0316315b6001600160a01b0383166000908152602081905260409020546109009190612c4d565b92915050565b600085858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050610997578251604051630e8c626560e41b815260040161044891815260200190565b81518351146109c6578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f42406109d383611e55565b63ffffffff16146109e75761058582611e55565b82516000190160005b81811015610ab357848160010181518110610a0d57610a0d612c21565b60200260200101516001600160a01b0316858281518110610a3057610a30612c21565b60200260200101516001600160a01b031610610a625760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110610a7c57610a7c612c21565b602002602001015163ffffffff1603610aab57604051630db7e4c760e01b815260048101829052602401610448565b6001016109f0565b50600063ffffffff16838281518110610ace57610ace612c21565b602002602001015163ffffffff1603610afd57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115610b305760405163308440e360e21b815263ffffffff82166004820152602401610448565b6000610ba18a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b925061219b915050565b9050610bcd7f000000000000000000000000c071e3a3d647506ee4c2c57b2ba6df331acb53a3826121d1565b9a9950505050505050505050565b60008167ffffffffffffffff811115610bf657610bf6612c60565b604051908082528060200260200182016040528015610c1f578160200160208202803683370190505b50905060008415610c3657610c3386612276565b90505b60005b83811015610c9657610c7187868684818110610c5757610c57612c21565b9050602002016020810190610c6c9190612806565b6122c9565b838281518110610c8357610c83612c21565b6020908102919091010152600101610c39565b50856001600160a01b03167fa9e30bf144f83390a4fe47562a4e16892108102221c674ff538da0b72a83d17482868686604051610cd69493929190612c76565b60405180910390a2505050505050565b600086868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050610d77578251604051630e8c626560e41b815260040161044891815260200190565b8151835114610da6578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240610db383611e55565b63ffffffff1614610dc75761058582611e55565b82516000190160005b81811015610e9357848160010181518110610ded57610ded612c21565b60200260200101516001600160a01b0316858281518110610e1057610e10612c21565b60200260200101516001600160a01b031610610e425760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110610e5c57610e5c612c21565b602002602001015163ffffffff1603610e8b57604051630db7e4c760e01b815260048101829052602401610448565b600101610dd0565b50600063ffffffff16838281518110610eae57610eae612c21565b602002602001015163ffffffff1603610edd57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115610f105760405163308440e360e21b815263ffffffff82166004820152602401610448565b6000610f818b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c925061219b915050565b90506001600160a01b038616610fc257610fbb7f000000000000000000000000c071e3a3d647506ee4c2c57b2ba6df331acb53a382612335565b945061101f565b610feb7f000000000000000000000000c071e3a3d647506ee4c2c57b2ba6df331acb53a36123e5565b6001600160a01b03818116600090815260026020526040902060010180546001600160a01b03191691891691909117905594505b6001600160a01b038516600081815260026020526040808220849055517f8d5f9943c664a3edaf4d3eb18cc5e2c45a7d2dc5869be33d33bbc0fff9bc25909190a2505050509695505050505050565b6001600160a01b0388811660009081526002602052604090206001015489911633146110af5760405163472511eb60e11b8152336004820152602401610448565b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a0282810182019093528982529093508992508891829185019084908082843760009201919091525050835187925060021115905061113e578251604051630e8c626560e41b815260040161044891815260200190565b815183511461116d578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061117a83611e55565b63ffffffff161461118e5761058582611e55565b82516000190160005b8181101561125a578481600101815181106111b4576111b4612c21565b60200260200101516001600160a01b03168582815181106111d7576111d7612c21565b60200260200101516001600160a01b0316106112095760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061122357611223612c21565b602002602001015163ffffffff160361125257604051630db7e4c760e01b815260048101829052602401610448565b600101611197565b50600063ffffffff1683828151811061127557611275612c21565b602002602001015163ffffffff16036112a457604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156112d75760405163308440e360e21b815263ffffffff82166004820152602401610448565b6112e58c8b8b8b8b8b612494565b6113698c8c8c8c80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508d92508c9150611eec9050565b505050505050505050505050565b6001600160a01b0387811660009081526002602052604090206001015488911633146113b85760405163472511eb60e11b8152336004820152602401610448565b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050611447578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611476578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061148383611e55565b63ffffffff16146114975761058582611e55565b82516000190160005b81811015611563578481600101815181106114bd576114bd612c21565b60200260200101516001600160a01b03168582815181106114e0576114e0612c21565b60200260200101516001600160a01b0316106115125760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061152c5761152c612c21565b602002602001015163ffffffff160361155b57604051630db7e4c760e01b815260048101829052602401610448565b6001016114a0565b50600063ffffffff1683828151811061157e5761157e612c21565b602002602001015163ffffffff16036115ad57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156115e05760405163308440e360e21b815263ffffffff82166004820152602401610448565b6115ee8b8b8b8b8b8b612494565b6107d38b8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92508b91506125549050565b6001600160a01b03821660009081526002602052604081205481036116865760006116f0565b6040516370a0823160e01b81526001600160a01b0384811660048301528316906370a0823190602401602060405180830381865afa1580156116cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116f09190612d07565b6001600160a01b038084166000908152600160209081526040808320938816835292905220546117209190612c4d565b9392505050565b6001600160a01b038181166000908152600260208190526040909120015482911633146117695760405163472511eb60e11b8152336004820152602401610448565b6001600160a01b03808316600081815260026020819052604080832091820180546001600160a01b0319169055600190910154905133949190911692917f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d091a4506001600160a01b0316600090815260026020526040902060010180546001600160a01b03191633179055565b6001600160a01b0382811660009081526002602052604090206001015483911633146118375760405163472511eb60e11b8152336004820152602401610448565b816001600160a01b03811661186a5760405163c369130760e01b81526001600160a01b0382166004820152602401610448565b6001600160a01b03848116600081815260026020819052604080832090910180546001600160a01b0319169488169485179055517f107cf6ea8668d533df1aab5bb8b6315bb0c25f0b6c955558d09368f290668fc79190a350505050565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050611957578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611986578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061199383611e55565b63ffffffff16146119a75761058582611e55565b82516000190160005b81811015611a73578481600101815181106119cd576119cd612c21565b60200260200101516001600160a01b03168582815181106119f0576119f0612c21565b60200260200101516001600160a01b031610611a225760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110611a3c57611a3c612c21565b602002602001015163ffffffff1603611a6b57604051630db7e4c760e01b815260048101829052602401610448565b6001016119b0565b50600063ffffffff16838281518110611a8e57611a8e612c21565b602002602001015163ffffffff1603611abd57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115611af05760405163308440e360e21b815263ffffffff82166004820152602401610448565b611b608a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b9250611e9a915050565b611bd28a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b92508a91506125549050565b50505050505050505050565b6001600160a01b038681166000908152600260205260409020600101548791163314611c1f5760405163472511eb60e11b8152336004820152602401610448565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050611cae578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611cdd578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240611cea83611e55565b63ffffffff1614611cfe5761058582611e55565b82516000190160005b81811015611dca57848160010181518110611d2457611d24612c21565b60200260200101516001600160a01b0316858281518110611d4757611d47612c21565b60200260200101516001600160a01b031610611d795760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110611d9357611d93612c21565b602002602001015163ffffffff1603611dc257604051630db7e4c760e01b815260048101829052602401610448565b600101611d07565b50600063ffffffff16838281518110611de557611de5612c21565b602002602001015163ffffffff1603611e1457604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115611e475760405163308440e360e21b815263ffffffff82166004820152602401610448565b611bd28a8a8a8a8a8a612494565b8051600090815b81811015611e9357838181518110611e7657611e76612c21565b602002602001015183611e899190612d20565b9250600101611e5c565b5050919050565b6000611ea784848461219b565b6001600160a01b0386166000908152600260205260409020549091508114611ee55760405163dd5ff45760e01b815260048101829052602401610448565b5050505050565b6001600160a01b038581166000818152600160209081526040808320948b16808452949091528082205490516370a0823160e01b815260048101949094529092909183916370a0823190602401602060405180830381865afa158015611f56573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611f7a9190612d07565b90508015611f8757600019015b8115611f94576001820391505b81810192508115611fc8576001600160a01b038089166000908152600160208181526040808420948e168452939052919020555b836001600160a01b0316886001600160a01b03168a6001600160a01b03167fb5ee5dc3d2c31a019bbf2c787e0e9c97971c96aceea1c38c12fc8fd25c536d468660405161201791815260200190565b60405180910390a463ffffffff851615612089576001600160a01b038881166000908152600160205260408120620f424063ffffffff89168702049283929088166120625733612064565b875b6001600160a01b03168152602081019190915260400160002080549091019055909203915b865160005b81811015612125576120c4858983815181106120ac576120ac612c21565b602002602001015163ffffffff16620f424091020490565b6001600160a01b038b1660009081526001602052604081208b519091908c90859081106120f3576120f3612c21565b6020908102919091018101516001600160a01b031682528101919091526040016000208054909101905560010161208e565b5050801561219057604051633e0f9fff60e11b81526001600160a01b038981166004830152602482018390528a1690637c1f3ffe90604401600060405180830381600087803b15801561217757600080fd5b505af115801561218b573d6000803e3d6000fd5b505050505b505050505050505050565b60008383836040516020016121b293929190612d44565b6040516020818303038152906040528051906020012090509392505050565b6000611720838330604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b6033820152606093841b60468201526d5af43d3d93803e605b57fd5bf3ff60901b605a820152921b6068830152607c8201526067808220609c830152605591012090565b6001600160a01b03811660009081526020819052604081205461229b90600190612dc9565b6001600160a01b0383166000818152602081905260409020600190559091506122c4908261271a565b919050565b6001600160a01b03808216600090815260016020818152604080842094871684529390529181205490916122fc91612dc9565b6001600160a01b038084166000818152600160208181526040808420958a16845294905292902091909155909150610900908483612770565b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528360601b60468201526c5af43d3d93803e605b57fd5bf360981b605a820152826067826000f59150506001600160a01b0381166109005760405163380bbe1360e01b815260040160405180910390fd5b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528260601b60468201526c5af43d3d93803e605b57fd5bf360981b605a8201526067816000f09150506001600160a01b0381166122c457604051630985da9b60e41b815260040160405180910390fd5b600061250586868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a0282810182019093528982529093508992508891829185019084908082843760009201919091525087925061219b915050565b6001600160a01b0388166000818152600260205260408082208490555192935090917f45e1e99513dd915ac128b94953ca64c6375717ea1894b3114db08cdca51debd29190a250505050505050565b6001600160a01b038516600081815260208190526040812054913190821561257d576001830392505b5081810182156125a4576001600160a01b0388166000908152602081905260409020600190555b836001600160a01b0316886001600160a01b03167f87c3ca0a87d9b82033e4bc55e6d30621f8d7e0c9d8ca7988edfde8932787b77b836040516125e991815260200190565b60405180910390a363ffffffff85161561264857620f424063ffffffff8616820204806000806001600160a01b0388166126235733612625565b875b6001600160a01b0316815260208101919091526040016000208054909101905590035b865160005b818110156126b25761266b838983815181106120ac576120ac612c21565b6000808b848151811061268057612680612c21565b6020908102919091018101516001600160a01b031682528101919091526040016000208054909101905560010161264d565b5050811561271057604051632ac3affd60e21b8152600481018390526001600160a01b0389169063ab0ebff490602401600060405180830381600087803b1580156126fc57600080fd5b505af1158015611369573d6000803e3d6000fd5b5050505050505050565b600080600080600085875af190508061276b5760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610448565b505050565b600060405163a9059cbb60e01b8152836004820152826024820152602060006044836000895af13d15601f3d11600160005114161716915050806127e85760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610448565b50505050565b6001600160a01b038116811461280357600080fd5b50565b60006020828403121561281857600080fd5b8135611720816127ee565b60008083601f84011261283557600080fd5b50813567ffffffffffffffff81111561284d57600080fd5b6020830191508360208260051b850101111561286857600080fd5b9250929050565b803563ffffffff811681146122c457600080fd5b60008060008060008060008060c0898b03121561289f57600080fd5b88356128aa816127ee565b975060208901356128ba816127ee565b9650604089013567ffffffffffffffff808211156128d757600080fd5b6128e38c838d01612823565b909850965060608b01359150808211156128fc57600080fd5b506129098b828c01612823565b909550935061291c905060808a0161286f565b915060a089013561292c816127ee565b809150509295985092959890939650565b60008060008060006060868803121561295557600080fd5b853567ffffffffffffffff8082111561296d57600080fd5b61297989838a01612823565b9097509550602088013591508082111561299257600080fd5b5061299f88828901612823565b90945092506129b290506040870161286f565b90509295509295909350565b600080600080606085870312156129d457600080fd5b84356129df816127ee565b935060208501359250604085013567ffffffffffffffff811115612a0257600080fd5b612a0e87828801612823565b95989497509550505050565b60008060008060008060808789031215612a3357600080fd5b863567ffffffffffffffff80821115612a4b57600080fd5b612a578a838b01612823565b90985096506020890135915080821115612a7057600080fd5b50612a7d89828a01612823565b9095509350612a9090506040880161286f565b91506060870135612aa0816127ee565b809150509295509295509295565b600080600080600080600060a0888a031215612ac957600080fd5b8735612ad4816127ee565b9650602088013567ffffffffffffffff80821115612af157600080fd5b612afd8b838c01612823565b909850965060408a0135915080821115612b1657600080fd5b50612b238a828b01612823565b9095509350612b3690506060890161286f565b91506080880135612b46816127ee565b8091505092959891949750929550565b60008060408385031215612b6957600080fd5b8235612b74816127ee565b91506020830135612b84816127ee565b809150509250929050565b60008060008060008060808789031215612ba857600080fd5b8635612bb3816127ee565b9550602087013567ffffffffffffffff80821115612bd057600080fd5b612bdc8a838b01612823565b90975095506040890135915080821115612bf557600080fd5b50612c0289828a01612823565b9094509250612c1590506060880161286f565b90509295509295509295565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b8082018082111561090057610900612c37565b634e487b7160e01b600052604160045260246000fd5b84815260606020808301829052908201849052600090859060808401835b87811015612cc2578335612ca7816127ee565b6001600160a01b031682529282019290820190600101612c94565b508481036040860152855180825290820192508186019060005b81811015612cf857825185529383019391830191600101612cdc565b50929998505050505050505050565b600060208284031215612d1957600080fd5b5051919050565b63ffffffff818116838216019080821115612d3d57612d3d612c37565b5092915050565b835160009082906020808801845b83811015612d775781516001600160a01b031685529382019390820190600101612d52565b5050865181880193925060005b81811015612da657845163ffffffff1684529382019392820192600101612d84565b50505060e09490941b6001600160e01b0319168452505060049091019392505050565b8181038181111561090057610900612c3756fea2646970667358221220ddbc0708d8e0f5bd7d5419396866023857b64aa69c0362963b654a1c828d919364736f6c63430008170033
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.