Contract 0x2ed6c4B5dA6378c7897AC67Ba9e43102Feb694EE 9

 
Txn Hash
Method
Block
From
To
Value
0x4cb0c64ba4f90d2d6db6370422c3380acd5732aa70415d39845b8cbd3a96e600Withdraw156488512022-09-30 21:30:352 hrs 5 mins ago0x697ed6dcdb5d3781f043571d912c9cb29ad01b58 IN 0xSplits: Split Main0 Ether0.00044862 11.93243842
0x6c0a68d0eae1ba81eac379d220dc00fd3116c0aa875b8e4a26649b025f080157Withdraw156487942022-09-30 21:19:112 hrs 17 mins agoENS Name huasotech.3gate.eth IN 0xSplits: Split Main0 Ether0.0037597 100
0x317fd20ef011438e859cd9dea04abb2012fd36e6c161aace6a8f2f06c0f3794fWithdraw156487772022-09-30 21:15:472 hrs 20 mins agoENS Name agent-l.eth IN 0xSplits: Split Main0 Ether0.00060725 15.14470922
0x7e1244d6f8d65c5f059430244623691dfc6bac13dd815f22836db42d1a00046bWithdraw156486562022-09-30 20:51:352 hrs 44 mins agoENS Name vault.mr0.eth IN 0xSplits: Split Main0 Ether0.00064055 17.03740369
0xb2ce31c4d16200edeaaf3b10c6f4e0cd471a3122949367ccc84294388c0cf5e4Distribute ETH156486452022-09-30 20:49:232 hrs 47 mins agoENS Name mr0.eth IN 0xSplits: Split Main0 Ether0.00220431 15
0x285ed3fabecc65328860e1f8a838b69aa30501bd869e1110a8f2877f1e472036Create Split156480962022-09-30 18:59:234 hrs 37 mins agoENS Name jackintheway.eth IN 0xSplits: Split Main0 Ether0.001762 16.65601769
0x1bf1d3a836cf820939d3bc0bb62fdb3aba862ff596c1442716df244557057960Distribute ETH156478282022-09-30 18:05:115 hrs 31 mins agoStateful Works IN 0xSplits: Split Main0 Ether0.00187712 23.15660036
0x873b31b263f0cac8dc77e4e736b94abbe241a40424ac3045eb66ac22fcf0ee96Withdraw156478242022-09-30 18:04:235 hrs 32 mins ago0xca44dfc6488d8332f7c7936ab8d764636be03530 IN 0xSplits: Split Main0 Ether0.00087914 23.38328485
0x108fe16a796d8f7a0fc697cd6544ec4e6e03dd508365cb18d1ecf52f250e5b7cDistribute ETH156478222022-09-30 18:03:595 hrs 32 mins ago0xca44dfc6488d8332f7c7936ab8d764636be03530 IN 0xSplits: Split Main0 Ether0.00135955 23.52494855
0x1ed7f168539c197cf48cb4c451ebcf53b7a794eee7f1703724933da94c9a9f52Withdraw156477752022-09-30 17:54:355 hrs 41 mins ago0xdb35bd7a7e6b3861ab0b46c2fee7e0107fc5e53f IN 0xSplits: Split Main0 Ether0.0007143419
0x84e78b5a915878191cc7f1cf94822612607a6b6693892f61155cd0336c9c8416Withdraw156471992022-09-30 15:58:597 hrs 37 mins agoENS Name seedstore.eth IN 0xSplits: Split Main0 Ether0.00154204 41.015082
0xd8c2a0208714086ea885d98cac9e01b62e5b431aa1ab787b31ec0371b71f0faaDistribute ETH156471712022-09-30 15:53:237 hrs 43 mins agoENS Name seedstore.eth IN 0xSplits: Split Main0 Ether0.00266235 37.50646455
0xcc25140efbcc85d4859fbb1c78fad106c28d57367989877f74e52db2fc1bfcd7Distribute ETH156469062022-09-30 14:59:478 hrs 36 mins ago0x7a562e13ef6810aeafdfd7a9b0438c1c7799d946 IN 0xSplits: Split Main0 Ether0.00213533 18.74879877
0xb2a35dadc772c15726c728618cb8bd4c409186e3a4f76ffe1cc5ad1d4afb8275Withdraw156449372022-09-30 8:24:2315 hrs 12 mins agoSound.xyz: Deployer 2 IN 0xSplits: Split Main0 Ether0.00030505 10.85720992
0x850a279460565155d94b3f7dc3e070bbc39a8198cfbdcc58285e6b3ef2a9f125Withdraw156449362022-09-30 8:24:1115 hrs 12 mins agoSound.xyz: Deployer 2 IN 0xSplits: Split Main0 Ether0.0003809 10.13130123
0x2063258df72ec1c71068374db130e26604a7ea9c9a7f5cc4f13419da40d47645Withdraw156447802022-09-30 7:52:1115 hrs 44 mins agoEmerge: Deployer IN 0xSplits: Split Main0 Ether0.00041426 11.01846944
0x53bc4edce3b2b795e56732ed0e08a2b86c0eb9921ca68596e0f66daa5036f537Withdraw156442612022-09-30 6:07:4717 hrs 28 mins agoENS Name rugthug.eth IN 0xSplits: Split Main0 Ether0.00078842 9.94523607
0x301068ecb1e3374e6663eff5ad1041afbd7818b66ba2793eb9f05e54f6ec2868Withdraw156442582022-09-30 6:07:1117 hrs 29 mins agoENS Name rugthug.eth IN 0xSplits: Split Main0 Ether0.00086179 10.87071939
0xc2b3b94e2e046d3a6190625f74bdc97231a30f03b03d51320b29bc2c446ba2e7Distribute ERC20156442562022-09-30 6:06:4717 hrs 29 mins agoENS Name rugthug.eth IN 0xSplits: Split Main0 Ether0.00066596 10.81703893
0xb384ef7cbe4a91dda3ccd922439d3e6ed5ad173954b77164b0c6d195dd82da48Distribute ERC20156442442022-09-30 6:04:2317 hrs 32 mins agoENS Name rugthug.eth IN 0xSplits: Split Main0 Ether0.00092573 11.12644822
0x180538533efb84f34c9ad1dddbae8ce982893739487434bd8af003effff4bf64Withdraw156430482022-09-30 2:03:3521 hrs 32 mins agoENS Name jmackent.eth IN 0xSplits: Split Main0 Ether0.0004586 12.19792162
0x8dd2de678b5a08bb51a3ebc7ccd496555b540eab7773f4d25a15375577814038Distribute ETH156430342022-09-30 2:00:4721 hrs 35 mins agoENS Name sweetman.eth IN 0xSplits: Split Main0 Ether0.00120481 11.45829827
0x808576df7cf70c592663dd2a6c66880a8d64df451bd472b72b55a83bb5304623Withdraw156427402022-09-30 1:01:3522 hrs 34 mins ago0x72b48f94c67e7fb5aa556e2872c585e3943e7c51 IN 0xSplits: Split Main0 Ether0.00028611 10.18327665
0x1f286a7327bd52c9e517cca3bc81f1a3586e62b091270b50f37320f2c444648bWithdraw156427342022-09-30 1:00:2322 hrs 36 mins ago0x72b48f94c67e7fb5aa556e2872c585e3943e7c51 IN 0xSplits: Split Main0 Ether0.00040996 10.90429464
0xb7fdc85c7ba3bcd268bddc497f46dbbafde0ed9f6d5b57d4fad53b75b708f6a4Withdraw156422312022-09-29 23:19:471 day 16 mins agoENS Name zaydworks.eth IN 0xSplits: Split Main0 Ether0.00036495 9.70703731
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x4cb0c64ba4f90d2d6db6370422c3380acd5732aa70415d39845b8cbd3a96e600156488512022-09-30 21:30:352 hrs 5 mins ago 0xSplits: Split Main0x697ed6dcdb5d3781f043571d912c9cb29ad01b580.54047923 Ether
0x6c0a68d0eae1ba81eac379d220dc00fd3116c0aa875b8e4a26649b025f080157156487942022-09-30 21:19:112 hrs 17 mins ago 0xSplits: Split MainENS Name huasotech.3gate.eth0.141075 Ether
0x317fd20ef011438e859cd9dea04abb2012fd36e6c161aace6a8f2f06c0f3794f156487772022-09-30 21:15:472 hrs 20 mins ago 0xSplits: Split Main0x7df05b684e3e66c30287e0c0c4c8954ed26ede970.141075 Ether
0x7e1244d6f8d65c5f059430244623691dfc6bac13dd815f22836db42d1a00046b156486562022-09-30 20:51:352 hrs 44 mins ago 0xSplits: Split MainENS Name vault.mr0.eth0.141075 Ether
0xb2ce31c4d16200edeaaf3b10c6f4e0cd471a3122949367ccc84294388c0cf5e4156486452022-09-30 20:49:232 hrs 47 mins ago 0x72b1202c820e4b2f8ac9573188b638866c7d92740xSplits: Split Main1.881 Ether
0x285ed3fabecc65328860e1f8a838b69aa30501bd869e1110a8f2877f1e472036156480962022-09-30 18:59:234 hrs 37 mins ago 0xSplits: Split Main  Contract Creation0 Ether
0x1bf1d3a836cf820939d3bc0bb62fdb3aba862ff596c1442716df244557057960156478282022-09-30 18:05:115 hrs 31 mins ago 0x5d11d392cb38235a3cfcc9681e8195081f314cab0xSplits: Split Main3.8 Ether
0x873b31b263f0cac8dc77e4e736b94abbe241a40424ac3045eb66ac22fcf0ee96156478242022-09-30 18:04:235 hrs 32 mins ago 0xSplits: Split Main0xca44dfc6488d8332f7c7936ab8d764636be035300.04505478 Ether
0x108fe16a796d8f7a0fc697cd6544ec4e6e03dd508365cb18d1ecf52f250e5b7c156478222022-09-30 18:03:595 hrs 32 mins ago 0xd369eaf9f28dc4930ebf94617b150be55e14278c0xSplits: Split Main0.06346293 Ether
0x1ed7f168539c197cf48cb4c451ebcf53b7a794eee7f1703724933da94c9a9f52156477752022-09-30 17:54:355 hrs 41 mins ago 0xSplits: Split Main0xdb35bd7a7e6b3861ab0b46c2fee7e0107fc5e53f0.05609999 Ether
0x84e78b5a915878191cc7f1cf94822612607a6b6693892f61155cd0336c9c8416156471992022-09-30 15:58:597 hrs 37 mins ago 0xSplits: Split MainENS Name seedstore.eth0.03969565 Ether
0xd8c2a0208714086ea885d98cac9e01b62e5b431aa1ab787b31ec0371b71f0faa156471712022-09-30 15:53:237 hrs 43 mins ago 0x71916104e789e1028079efb19a133281d4cd237a0xSplits: Split Main0.079312 Ether
0xcc25140efbcc85d4859fbb1c78fad106c28d57367989877f74e52db2fc1bfcd7156469062022-09-30 14:59:478 hrs 36 mins ago 0xea0fb3ee0da3029ead6d11cd7743f4a618a1527e0xSplits: Split Main0.07 Ether
0x850a279460565155d94b3f7dc3e070bbc39a8198cfbdcc58285e6b3ef2a9f125156449362022-09-30 8:24:1115 hrs 12 mins ago 0xSplits: Split MainSound.xyz: Deployer 24.3725255 Ether
0x2063258df72ec1c71068374db130e26604a7ea9c9a7f5cc4f13419da40d47645156447802022-09-30 7:52:1115 hrs 44 mins ago 0xSplits: Split MainEmerge: Deployer4.58849999 Ether
0x180538533efb84f34c9ad1dddbae8ce982893739487434bd8af003effff4bf64156430482022-09-30 2:03:3521 hrs 32 mins ago 0xSplits: Split MainENS Name jmackent.eth0.15860124 Ether
0x8dd2de678b5a08bb51a3ebc7ccd496555b540eab7773f4d25a15375577814038156430342022-09-30 2:00:4721 hrs 35 mins ago 0x60ee2cb0952c6db9fb41731b81b12b983fbfd3f20xSplits: Split Main0.17982 Ether
0x1f286a7327bd52c9e517cca3bc81f1a3586e62b091270b50f37320f2c444648b156427342022-09-30 1:00:2322 hrs 36 mins ago 0xSplits: Split Main0x72b48f94c67e7fb5aa556e2872c585e3943e7c510.50496999 Ether
0xb7fdc85c7ba3bcd268bddc497f46dbbafde0ed9f6d5b57d4fad53b75b708f6a4156422312022-09-29 23:19:471 day 16 mins ago 0xSplits: Split MainENS Name zaydworks.eth0.12959999 Ether
0x5ec624a441f8d8cfa03e7ed7d5bf88d9de9a816f9ca54fcf343ed6c384afb80d156420122022-09-29 22:35:591 day 1 hr ago 0xSplits: Split Main0x186845619de9f7ddaadfb48c095f36f4bf5a41120.0465886 Ether
0x76e97ba478a6fd90fa2fdeeb23e495c882e9cc3e443ddde55ce46c8d70d146a4156420122022-09-29 22:35:591 day 1 hr ago 0xSplits: Split Main0x307bcaeecf9bb106cf9dcb399c583ea45f5be0110.0465886 Ether
0x29cb002fac5c8d9404473a992fe8972eb9279af3375c9df5ca6a2b4ca30d1ce5156420092022-09-29 22:35:231 day 1 hr ago 0xSplits: Split MainENS Name akshaan.eth0.0465886 Ether
0x6e2bfb273407b2c2d0d55ecb2e068b247dcf5ddb4e560599f5b2c1c8b1f65773156420092022-09-29 22:35:231 day 1 hr ago 0xSplits: Split Main0x5ab3c9a8695043d82bef29e26b4355f9af156bd20.0465886 Ether
0x381cdd5efea2b95389bc7fc6b47e23754f7019586506def53807c4b6d512bd1d156420092022-09-29 22:35:231 day 1 hr ago 0xSplits: Split Main0x687a0caf93a1a239c6fcbd458a5e7a5d650a86830.0465886 Ether
0x49474bcd184d0c9b4de240a84788878de3177a671987cf44ef388c5e0c9ebb51156420092022-09-29 22:35:231 day 1 hr ago 0xSplits: Split Main0x8487249fbde8c1b568033c2145b7682e11996df10.0465886 Ether
[ Download CSV Export 
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.4+commit.c7e474f2

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, Audited
File 1 of 6 : SplitMain.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;

import {ISplitMain} from 'contracts/interfaces/ISplitMain.sol';
import {SplitWallet} from 'contracts/SplitWallet.sol';
import {Clones} from 'contracts/libraries/Clones.sol';
import {ERC20} from '@rari-capital/solmate/src/tokens/ERC20.sol';
import {SafeTransferLib} from '@rari-capital/solmate/src/utils/SafeTransferLib.sol';

/**

                                             █████████
                                          ███████████████                  █████████
                                         █████████████████               █████████████                 ███████
                                        ███████████████████             ███████████████               █████████
                                        ███████████████████             ███████████████              ███████████
                                        ███████████████████             ███████████████               █████████
                                         █████████████████               █████████████                 ███████
                                          ███████████████                  █████████
                                             █████████

                             ███████████
                          █████████████████                 █████████
                         ███████████████████             ███████████████                  █████████
                        █████████████████████           █████████████████               █████████████                ███████
                       ███████████████████████         ███████████████████             ███████████████              █████████
                       ███████████████████████         ███████████████████             ███████████████             ███████████
                       ███████████████████████         ███████████████████             ███████████████              █████████
                        █████████████████████           █████████████████               █████████████                ███████
                         ███████████████████              █████████████                   █████████
                          █████████████████                 █████████
                             ███████████

           ███████████
       ███████████████████                  ███████████
     ███████████████████████              ███████████████                  █████████
    █████████████████████████           ███████████████████             ███████████████               █████████
   ███████████████████████████         █████████████████████           █████████████████            █████████████              ███████
   ███████████████████████████        ███████████████████████         ███████████████████          ███████████████            █████████
   ███████████████████████████        ███████████████████████         ███████████████████          ███████████████           ███████████
   ███████████████████████████        ███████████████████████         ███████████████████          ███████████████            █████████
   ███████████████████████████         █████████████████████           █████████████████            █████████████              ███████
    █████████████████████████           ███████████████████              █████████████                █████████
      █████████████████████               ███████████████                  █████████
        █████████████████                   ███████████
           ███████████

                             ███████████
                          █████████████████                 █████████
                         ███████████████████             ███████████████                  █████████
                        █████████████████████           █████████████████               █████████████                ███████
                       ███████████████████████         ███████████████████             ███████████████              █████████
                       ███████████████████████         ███████████████████             ███████████████             ███████████
                       ███████████████████████         ███████████████████             ███████████████              █████████
                        █████████████████████           █████████████████               █████████████                ███████
                         ███████████████████              █████████████                   █████████
                          █████████████████                 █████████
                             ███████████

                                             █████████
                                          ███████████████                  █████████
                                         █████████████████               █████████████                 ███████
                                        ███████████████████             ███████████████               █████████
                                        ███████████████████             ███████████████              ███████████
                                        ███████████████████             ███████████████               █████████
                                         █████████████████               █████████████                 ███████
                                          ███████████████                  █████████
                                             █████████

 */

/**
 * ERRORS
 */

/// @notice Unauthorized sender `sender`
/// @param sender Transaction sender
error Unauthorized(address sender);
/// @notice Invalid number of accounts `accountsLength`, must have at least 2
/// @param accountsLength Length of accounts array
error InvalidSplit__TooFewAccounts(uint256 accountsLength);
/// @notice Array lengths of accounts & percentAllocations don't match (`accountsLength` != `allocationsLength`)
/// @param accountsLength Length of accounts array
/// @param allocationsLength Length of percentAllocations array
error InvalidSplit__AccountsAndAllocationsMismatch(
  uint256 accountsLength,
  uint256 allocationsLength
);
/// @notice Invalid percentAllocations sum `allocationsSum` must equal `PERCENTAGE_SCALE`
/// @param allocationsSum Sum of percentAllocations array
error InvalidSplit__InvalidAllocationsSum(uint32 allocationsSum);
/// @notice Invalid accounts ordering at `index`
/// @param index Index of out-of-order account
error InvalidSplit__AccountsOutOfOrder(uint256 index);
/// @notice Invalid percentAllocation of zero at `index`
/// @param index Index of zero percentAllocation
error InvalidSplit__AllocationMustBePositive(uint256 index);
/// @notice Invalid distributorFee `distributorFee` cannot be greater than 10% (1e5)
/// @param distributorFee Invalid distributorFee amount
error InvalidSplit__InvalidDistributorFee(uint32 distributorFee);
/// @notice Invalid hash `hash` from split data (accounts, percentAllocations, distributorFee)
/// @param hash Invalid hash
error InvalidSplit__InvalidHash(bytes32 hash);
/// @notice Invalid new controlling address `newController` for mutable split
/// @param newController Invalid new controller
error InvalidNewController(address newController);

/**
 * @title SplitMain
 * @author 0xSplits <[email protected]>
 * @notice A composable and gas-efficient protocol for deploying splitter contracts.
 * @dev Split recipients, ownerships, and keeper fees are stored onchain as calldata & re-passed as args / validated
 * via hashing when needed. Each split gets its own address & proxy for maximum composability with other contracts onchain.
 * For these proxies, we extended EIP-1167 Minimal Proxy Contract to avoid `DELEGATECALL` inside `receive()` to accept
 * hard gas-capped `sends` & `transfers`.
 */
contract SplitMain is ISplitMain {
  using SafeTransferLib for address;
  using SafeTransferLib for ERC20;

  /**
   * STRUCTS
   */

  /// @notice holds Split metadata
  struct Split {
    bytes32 hash;
    address controller;
    address newPotentialController;
  }

  /**
   * STORAGE
   */

  /**
   * STORAGE - CONSTANTS & IMMUTABLES
   */

  /// @notice constant to scale uints into percentages (1e6 == 100%)
  uint256 public constant PERCENTAGE_SCALE = 1e6;
  /// @notice maximum distributor fee; 1e5 = 10% * PERCENTAGE_SCALE
  uint256 internal constant MAX_DISTRIBUTOR_FEE = 1e5;
  /// @notice address of wallet implementation for split proxies
  address public immutable override walletImplementation;

  /**
   * STORAGE - VARIABLES - PRIVATE & INTERNAL
   */

  /// @notice mapping to account ETH balances
  mapping(address => uint256) internal ethBalances;
  /// @notice mapping to account ERC20 balances
  mapping(ERC20 => mapping(address => uint256)) internal erc20Balances;
  /// @notice mapping to Split metadata
  mapping(address => Split) internal splits;

  /**
   * MODIFIERS
   */

  /** @notice Reverts if the sender doesn't own the split `split`
   *  @param split Address to check for control
   */
  modifier onlySplitController(address split) {
    if (msg.sender != splits[split].controller) revert Unauthorized(msg.sender);
    _;
  }

  /** @notice Reverts if the sender isn't the new potential controller of split `split`
   *  @param split Address to check for new potential control
   */
  modifier onlySplitNewPotentialController(address split) {
    if (msg.sender != splits[split].newPotentialController)
      revert Unauthorized(msg.sender);
    _;
  }

  /** @notice Reverts if the split with recipients represented by `accounts` and `percentAllocations` is malformed
   *  @param accounts Ordered, unique list of addresses with ownership in the split
   *  @param percentAllocations Percent allocations associated with each address
   *  @param distributorFee Keeper fee paid by split to cover gas costs of distribution
   */
  modifier validSplit(
    address[] memory accounts,
    uint32[] memory percentAllocations,
    uint32 distributorFee
  ) {
    if (accounts.length < 2)
      revert InvalidSplit__TooFewAccounts(accounts.length);
    if (accounts.length != percentAllocations.length)
      revert InvalidSplit__AccountsAndAllocationsMismatch(
        accounts.length,
        percentAllocations.length
      );
    // _getSum should overflow if any percentAllocation[i] < 0
    if (_getSum(percentAllocations) != PERCENTAGE_SCALE)
      revert InvalidSplit__InvalidAllocationsSum(_getSum(percentAllocations));
    unchecked {
      // overflow should be impossible in for-loop index
      // cache accounts length to save gas
      uint256 loopLength = accounts.length - 1;
      for (uint256 i = 0; i < loopLength; ++i) {
        // overflow should be impossible in array access math
        if (accounts[i] >= accounts[i + 1])
          revert InvalidSplit__AccountsOutOfOrder(i);
        if (percentAllocations[i] == uint32(0))
          revert InvalidSplit__AllocationMustBePositive(i);
      }
      // overflow should be impossible in array access math with validated equal array lengths
      if (percentAllocations[loopLength] == uint32(0))
        revert InvalidSplit__AllocationMustBePositive(loopLength);
    }
    if (distributorFee > MAX_DISTRIBUTOR_FEE)
      revert InvalidSplit__InvalidDistributorFee(distributorFee);
    _;
  }

  /** @notice Reverts if `newController` is the zero address
   *  @param newController Proposed new controlling address
   */
  modifier validNewController(address newController) {
    if (newController == address(0)) revert InvalidNewController(newController);
    _;
  }

  /**
   * CONSTRUCTOR
   */

  constructor() {
    walletImplementation = address(new SplitWallet());
  }

  /**
   * FUNCTIONS
   */

  /**
   * FUNCTIONS - PUBLIC & EXTERNAL
   */

  /** @notice Receive ETH
   *  @dev Used by split proxies in `distributeETH` to transfer ETH to `SplitMain`
   *  Funds sent outside of `distributeETH` will be unrecoverable
   */
  receive() external payable {}

  /** @notice Creates a new split with recipients `accounts` with ownerships `percentAllocations`, a keeper fee for splitting of `distributorFee` and the controlling address `controller`
   *  @param accounts Ordered, unique list of addresses with ownership in the split
   *  @param percentAllocations Percent allocations associated with each address
   *  @param distributorFee Keeper fee paid by split to cover gas costs of distribution
   *  @param controller Controlling address (0x0 if immutable)
   *  @return split Address of newly created split
   */
  function createSplit(
    address[] calldata accounts,
    uint32[] calldata percentAllocations,
    uint32 distributorFee,
    address controller
  )
    external
    override
    validSplit(accounts, percentAllocations, distributorFee)
    returns (address split)
  {
    bytes32 splitHash = _hashSplit(
      accounts,
      percentAllocations,
      distributorFee
    );
    if (controller == address(0)) {
      // create immutable split
      split = Clones.cloneDeterministic(walletImplementation, splitHash);
    } else {
      // create mutable split
      split = Clones.clone(walletImplementation);
      splits[split].controller = controller;
    }
    // store split's hash in storage for future verification
    splits[split].hash = splitHash;
    emit CreateSplit(split);
  }

  /** @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);
  }
}

File 2 of 6 : ISplitMain.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;

import {ERC20} from '@rari-capital/solmate/src/tokens/ERC20.sol';

/**
 * @title ISplitMain
 * @author 0xSplits <[email protected]>
 */
interface ISplitMain {
  /**
   * FUNCTIONS
   */

  function walletImplementation() external returns (address);

  function createSplit(
    address[] calldata accounts,
    uint32[] calldata percentAllocations,
    uint32 distributorFee,
    address controller
  ) external returns (address);

  function predictImmutableSplitAddress(
    address[] calldata accounts,
    uint32[] calldata percentAllocations,
    uint32 distributorFee
  ) external view returns (address);

  function updateSplit(
    address split,
    address[] calldata accounts,
    uint32[] calldata percentAllocations,
    uint32 distributorFee
  ) external;

  function transferControl(address split, address newController) external;

  function cancelControlTransfer(address split) external;

  function acceptControl(address split) external;

  function makeSplitImmutable(address split) external;

  function distributeETH(
    address split,
    address[] calldata accounts,
    uint32[] calldata percentAllocations,
    uint32 distributorFee,
    address distributorAddress
  ) external;

  function updateAndDistributeETH(
    address split,
    address[] calldata accounts,
    uint32[] calldata percentAllocations,
    uint32 distributorFee,
    address distributorAddress
  ) external;

  function distributeERC20(
    address split,
    ERC20 token,
    address[] calldata accounts,
    uint32[] calldata percentAllocations,
    uint32 distributorFee,
    address distributorAddress
  ) external;

  function updateAndDistributeERC20(
    address split,
    ERC20 token,
    address[] calldata accounts,
    uint32[] calldata percentAllocations,
    uint32 distributorFee,
    address distributorAddress
  ) external;

  function withdraw(
    address account,
    uint256 withdrawETH,
    ERC20[] calldata tokens
  ) external;

  /**
   * EVENTS
   */

  /** @notice emitted after each successful split creation
   *  @param split Address of the created split
   */
  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
  );
}

File 3 of 6 : SplitWallet.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;

import {ISplitMain} from './interfaces/ISplitMain.sol';
import {ERC20} from '@rari-capital/solmate/src/tokens/ERC20.sol';
import {SafeTransferLib} from '@rari-capital/solmate/src/utils/SafeTransferLib.sol';

/**
 * ERRORS
 */

/// @notice Unauthorized sender
error Unauthorized();

/**
 * @title SplitWallet
 * @author 0xSplits <[email protected]>
 * @notice The implementation logic for `SplitProxy`.
 * @dev `SplitProxy` handles `receive()` itself to avoid the gas cost with `DELEGATECALL`.
 */
contract SplitWallet {
  using SafeTransferLib for address;
  using SafeTransferLib for ERC20;

  /**
   * EVENTS
   */

  /** @notice emitted after each successful ETH transfer to proxy
   *  @param split Address of the split that received ETH
   *  @param amount Amount of ETH received
   */
  event ReceiveETH(address indexed split, uint256 amount);

  /**
   * STORAGE
   */

  /**
   * STORAGE - CONSTANTS & IMMUTABLES
   */

  /// @notice address of SplitMain for split distributions & EOA/SC withdrawals
  ISplitMain public immutable splitMain;

  /**
   * MODIFIERS
   */

  /// @notice Reverts if the sender isn't SplitMain
  modifier onlySplitMain() {
    if (msg.sender != address(splitMain)) revert Unauthorized();
    _;
  }

  /**
   * CONSTRUCTOR
   */

  constructor() {
    splitMain = ISplitMain(msg.sender);
  }

  /**
   * FUNCTIONS - PUBLIC & EXTERNAL
   */

  /** @notice Sends amount `amount` of ETH in proxy to SplitMain
   *  @dev payable reduces gas cost; no vulnerability to accidentally lock
   *  ETH introduced since fn call is restricted to SplitMain
   *  @param amount Amount to send
   */
  function sendETHToMain(uint256 amount) external payable onlySplitMain() {
    address(splitMain).safeTransferETH(amount);
  }

  /** @notice Sends amount `amount` of ERC20 `token` in proxy to SplitMain
   *  @dev payable reduces gas cost; no vulnerability to accidentally lock
   *  ETH introduced since fn call is restricted to SplitMain
   *  @param token Token to send
   *  @param amount Amount to send
   */
  function sendERC20ToMain(ERC20 token, uint256 amount)
    external
    payable
    onlySplitMain()
  {
    token.safeTransfer(address(splitMain), amount);
  }
}

File 4 of 6 : Clones.sol
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.4;

/// @notice create opcode failed
error CreateError();
/// @notice create2 opcode failed
error Create2Error();

library Clones {
  /**
   * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`
   * except when someone calls `receive()` and then it emits an event matching
   * `SplitWallet.ReceiveETH(indexed address, amount)`
   * Inspired by OZ & 0age's minimal clone implementations based on eip 1167 found at
   * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.3.0/contracts/proxy/Clones.sol
   * and https://medium.com/coinmonks/the-more-minimal-proxy-5756ae08ee48
   *
   * This function uses the create2 opcode and a `salt` to deterministically deploy
   * the clone. Using the same `implementation` and `salt` multiple time will revert, since
   * the clones cannot be deployed twice at the same address.
   *
   * init: 0x3d605d80600a3d3981f3
   * 3d   returndatasize  0
   * 605d push1 0x5d      0x5d 0
   * 80   dup1            0x5d 0x5d 0
   * 600a push1 0x0a      0x0a 0x5d 0x5d 0
   * 3d   returndatasize  0 0x0a 0x5d 0x5d 0
   * 39   codecopy        0x5d 0                      destOffset offset length     memory[destOffset:destOffset+length] = address(this).code[offset:offset+length]       copy executing contracts bytecode
   * 81   dup2            0 0x5d 0
   * f3   return          0                           offset length                return memory[offset:offset+length]                                                   returns from this contract call
   *
   * contract: 0x36603057343d52307f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160203da23d3df35b3d3d3d3d363d3d37363d73bebebebebebebebebebebebebebebebebebebebe5af43d3d93803e605b57fd5bf3
   *     0x000     36       calldatasize      cds
   *     0x001     6030     push1 0x30        0x30 cds
   * ,=< 0x003     57       jumpi
   * |   0x004     34       callvalue         cv
   * |   0x005     3d       returndatasize    0 cv
   * |   0x006     52       mstore
   * |   0x007     30       address           addr
   * |   0x008     7f830d.. push32 0x830d..   id addr
   * |   0x029     6020     push1 0x20        0x20 id addr
   * |   0x02b     3d       returndatasize    0 0x20 id addr
   * |   0x02c     a2       log2
   * |   0x02d     3d       returndatasize    0
   * |   0x02e     3d       returndatasize    0 0
   * |   0x02f     f3       return
   * `-> 0x030     5b       jumpdest
   *     0x031     3d       returndatasize    0
   *     0x032     3d       returndatasize    0 0
   *     0x033     3d       returndatasize    0 0 0
   *     0x034     3d       returndatasize    0 0 0 0
   *     0x035     36       calldatasize      cds 0 0 0 0
   *     0x036     3d       returndatasize    0 cds 0 0 0 0
   *     0x037     3d       returndatasize    0 0 cds 0 0 0 0
   *     0x038     37       calldatacopy      0 0 0 0
   *     0x039     36       calldatasize      cds 0 0 0 0
   *     0x03a     3d       returndatasize    0 cds 0 0 0 0
   *     0x03b     73bebe.. push20 0xbebe..   0xbebe 0 cds 0 0 0 0
   *     0x050     5a       gas               gas 0xbebe 0 cds 0 0 0 0
   *     0x051     f4       delegatecall      suc 0 0
   *     0x052     3d       returndatasize    rds suc 0 0
   *     0x053     3d       returndatasize    rds rds suc 0 0
   *     0x054     93       swap4             0 rds suc 0 rds
   *     0x055     80       dup1              0 0 rds suc 0 rds
   *     0x056     3e       returndatacopy    suc 0 rds
   *     0x057     605b     push1 0x5b        0x5b suc 0 rds
   * ,=< 0x059     57       jumpi             0 rds
   * |   0x05a     fd       revert
   * `-> 0x05b     5b       jumpdest          0 rds
   *     0x05c     f3       return
   *
   */
  function clone(address implementation) internal returns (address instance) {
    assembly {
      let ptr := mload(0x40)
      mstore(
        ptr,
        0x3d605d80600a3d3981f336603057343d52307f00000000000000000000000000
      )
      mstore(
        add(ptr, 0x13),
        0x830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b1
      )
      mstore(
        add(ptr, 0x33),
        0x60203da23d3df35b3d3d3d3d363d3d37363d7300000000000000000000000000
      )
      mstore(add(ptr, 0x46), shl(0x60, implementation))
      mstore(
        add(ptr, 0x5a),
        0x5af43d3d93803e605b57fd5bf300000000000000000000000000000000000000
      )
      instance := create(0, ptr, 0x67)
    }
    if (instance == address(0)) revert CreateError();
  }

  function cloneDeterministic(address implementation, bytes32 salt)
    internal
    returns (address instance)
  {
    assembly {
      let ptr := mload(0x40)
      mstore(
        ptr,
        0x3d605d80600a3d3981f336603057343d52307f00000000000000000000000000
      )
      mstore(
        add(ptr, 0x13),
        0x830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b1
      )
      mstore(
        add(ptr, 0x33),
        0x60203da23d3df35b3d3d3d3d363d3d37363d7300000000000000000000000000
      )
      mstore(add(ptr, 0x46), shl(0x60, implementation))
      mstore(
        add(ptr, 0x5a),
        0x5af43d3d93803e605b57fd5bf300000000000000000000000000000000000000
      )
      instance := create2(0, ptr, 0x67, salt)
    }
    if (instance == address(0)) revert Create2Error();
  }

  /**
   * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
   */
  function predictDeterministicAddress(
    address implementation,
    bytes32 salt,
    address deployer
  ) internal pure returns (address predicted) {
    assembly {
      let ptr := mload(0x40)
      mstore(
        ptr,
        0x3d605d80600a3d3981f336603057343d52307f00000000000000000000000000
      )
      mstore(
        add(ptr, 0x13),
        0x830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b1
      )
      mstore(
        add(ptr, 0x33),
        0x60203da23d3df35b3d3d3d3d363d3d37363d7300000000000000000000000000
      )
      mstore(add(ptr, 0x46), shl(0x60, implementation))
      mstore(
        add(ptr, 0x5a),
        0x5af43d3d93803e605b57fd5bf3ff000000000000000000000000000000000000
      )
      mstore(add(ptr, 0x68), shl(0x60, deployer))
      mstore(add(ptr, 0x7c), salt)
      mstore(add(ptr, 0x9c), keccak256(ptr, 0x67))
      predicted := keccak256(add(ptr, 0x67), 0x55)
    }
  }

  /**
   * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
   */
  function predictDeterministicAddress(address implementation, bytes32 salt)
    internal
    view
    returns (address predicted)
  {
    return predictDeterministicAddress(implementation, salt, address(this));
  }
}

File 5 of 6 : ERC20.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)
/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
abstract contract ERC20 {
    /*///////////////////////////////////////////////////////////////
                                  EVENTS
    //////////////////////////////////////////////////////////////*/

    event Transfer(address indexed from, address indexed to, uint256 amount);

    event Approval(address indexed owner, address indexed spender, uint256 amount);

    /*///////////////////////////////////////////////////////////////
                             METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

    string public name;

    string public symbol;

    uint8 public immutable decimals;

    /*///////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

    uint256 public totalSupply;

    mapping(address => uint256) public balanceOf;

    mapping(address => mapping(address => uint256)) public allowance;

    /*///////////////////////////////////////////////////////////////
                             EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

    bytes32 public constant PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    uint256 internal immutable INITIAL_CHAIN_ID;

    bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

    mapping(address => uint256) public nonces;

    /*///////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals
    ) {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;

        INITIAL_CHAIN_ID = block.chainid;
        INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
    }

    /*///////////////////////////////////////////////////////////////
                              ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

    function approve(address spender, uint256 amount) public virtual returns (bool) {
        allowance[msg.sender][spender] = amount;

        emit Approval(msg.sender, spender, amount);

        return true;
    }

    function transfer(address to, uint256 amount) public virtual returns (bool) {
        balanceOf[msg.sender] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(msg.sender, to, amount);

        return true;
    }

    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) public virtual returns (bool) {
        uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

        if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

        balanceOf[from] -= amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(from, to, amount);

        return true;
    }

    /*///////////////////////////////////////////////////////////////
                              EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");

        // Unchecked because the only math done is incrementing
        // the owner's nonce which cannot realistically overflow.
        unchecked {
            bytes32 digest = keccak256(
                abi.encodePacked(
                    "\x19\x01",
                    DOMAIN_SEPARATOR(),
                    keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
                )
            );

            address recoveredAddress = ecrecover(digest, v, r, s);

            require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");

            allowance[recoveredAddress][spender] = value;
        }

        emit Approval(owner, spender, value);
    }

    function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
        return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
    }

    function computeDomainSeparator() internal view virtual returns (bytes32) {
        return
            keccak256(
                abi.encode(
                    keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                    keccak256(bytes(name)),
                    keccak256("1"),
                    block.chainid,
                    address(this)
                )
            );
    }

    /*///////////////////////////////////////////////////////////////
                       INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

    function _mint(address to, uint256 amount) internal virtual {
        totalSupply += amount;

        // Cannot overflow because the sum of all user
        // balances can't exceed the max uint256 value.
        unchecked {
            balanceOf[to] += amount;
        }

        emit Transfer(address(0), to, amount);
    }

    function _burn(address from, uint256 amount) internal virtual {
        balanceOf[from] -= amount;

        // Cannot underflow because a user's balance
        // will never be larger than the total supply.
        unchecked {
            totalSupply -= amount;
        }

        emit Transfer(from, address(0), amount);
    }
}

File 6 of 6 : SafeTransferLib.sol
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.0;

import {ERC20} from "../tokens/ERC20.sol";

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Gnosis (https://github.com/gnosis/gp-v2-contracts/blob/main/src/contracts/libraries/GPv2SafeERC20.sol)
/// @dev Use with caution! Some functions in this library knowingly create dirty bits at the destination of the free memory pointer.
library SafeTransferLib {
    /*///////////////////////////////////////////////////////////////
                            ETH OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferETH(address to, uint256 amount) internal {
        bool callStatus;

        assembly {
            // Transfer the ETH and store if it succeeded or not.
            callStatus := call(gas(), to, amount, 0, 0, 0, 0)
        }

        require(callStatus, "ETH_TRANSFER_FAILED");
    }

    /*///////////////////////////////////////////////////////////////
                           ERC20 OPERATIONS
    //////////////////////////////////////////////////////////////*/

    function safeTransferFrom(
        ERC20 token,
        address from,
        address to,
        uint256 amount
    ) internal {
        bool callStatus;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata to memory piece by piece:
            mstore(freeMemoryPointer, 0x23b872dd00000000000000000000000000000000000000000000000000000000) // Begin with the function selector.
            mstore(add(freeMemoryPointer, 4), and(from, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "from" argument.
            mstore(add(freeMemoryPointer, 36), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.
            mstore(add(freeMemoryPointer, 68), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.

            // Call the token and store if it succeeded or not.
            // We use 100 because the calldata length is 4 + 32 * 3.
            callStatus := call(gas(), token, 0, freeMemoryPointer, 100, 0, 0)
        }

        require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FROM_FAILED");
    }

    function safeTransfer(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool callStatus;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata to memory piece by piece:
            mstore(freeMemoryPointer, 0xa9059cbb00000000000000000000000000000000000000000000000000000000) // Begin with the function selector.
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.

            // Call the token and store if it succeeded or not.
            // We use 68 because the calldata length is 4 + 32 * 2.
            callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
        }

        require(didLastOptionalReturnCallSucceed(callStatus), "TRANSFER_FAILED");
    }

    function safeApprove(
        ERC20 token,
        address to,
        uint256 amount
    ) internal {
        bool callStatus;

        assembly {
            // Get a pointer to some free memory.
            let freeMemoryPointer := mload(0x40)

            // Write the abi-encoded calldata to memory piece by piece:
            mstore(freeMemoryPointer, 0x095ea7b300000000000000000000000000000000000000000000000000000000) // Begin with the function selector.
            mstore(add(freeMemoryPointer, 4), and(to, 0xffffffffffffffffffffffffffffffffffffffff)) // Mask and append the "to" argument.
            mstore(add(freeMemoryPointer, 36), amount) // Finally append the "amount" argument. No mask as it's a full 32 byte value.

            // Call the token and store if it succeeded or not.
            // We use 68 because the calldata length is 4 + 32 * 2.
            callStatus := call(gas(), token, 0, freeMemoryPointer, 68, 0, 0)
        }

        require(didLastOptionalReturnCallSucceed(callStatus), "APPROVE_FAILED");
    }

    /*///////////////////////////////////////////////////////////////
                         INTERNAL HELPER LOGIC
    //////////////////////////////////////////////////////////////*/

    function didLastOptionalReturnCallSucceed(bool callStatus) private pure returns (bool success) {
        assembly {
            // Get how many bytes the call returned.
            let returnDataSize := returndatasize()

            // If the call reverted:
            if iszero(callStatus) {
                // Copy the revert message into memory.
                returndatacopy(0, 0, returnDataSize)

                // Revert with the same message.
                revert(0, returnDataSize)
            }

            switch returnDataSize
            case 32 {
                // Copy the return data into memory.
                returndatacopy(0, 0, returnDataSize)

                // Set success to whether it returned true.
                success := iszero(iszero(mload(0)))
            }
            case 0 {
                // There was no return data.
                success := 1
            }
            default {
                // It returned some malformed input.
                success := 0
            }
        }
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"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"}]

60a06040523480156200001157600080fd5b50604051620000209062000054565b604051809103906000f0801580156200003d573d6000803e3d6000fd5b5060601b6001600160601b03191660805262000062565b6103a080620030e983390190565b60805160601c61305362000096600039600081816102b001528181610c1a0152818161106c015261109d01526130536000f3fe6080604052600436106101185760003560e01c806377b1e4e9116100a0578063c7de644011610064578063c7de64401461034e578063d0e4b2f41461036e578063e10e51d61461038e578063e61cb05e146103cb578063ecef0ace146103eb57600080fd5b806377b1e4e91461027e5780638117abc11461029e57806388c662aa146102d2578063a5e3909e1461030e578063c3a8962c1461032e57600080fd5b80633bb66a7b116100e75780633bb66a7b146101cf5780633f26479e146101ef57806352844dd3146102065780636e5f69191461023e5780637601f7821461025e57600080fd5b80631267c6da146101245780631581130214610146578063189cbaa0146101665780631da0b8fc1461018657600080fd5b3661011f57005b600080fd5b34801561013057600080fd5b5061014461013f366004612ab2565b61040b565b005b34801561015257600080fd5b50610144610161366004612c4c565b6104a6565b34801561017257600080fd5b50610144610181366004612ab2565b61081a565b34801561019257600080fd5b506101bc6101a1366004612ab2565b6001600160a01b031660009081526002602052604090205490565b6040519081526020015b60405180910390f35b3480156101db57600080fd5b506101bc6101ea366004612ab2565b6108e5565b3480156101fb57600080fd5b506101bc620f424081565b34801561021257600080fd5b50610226610221366004612d5d565b61093e565b6040516001600160a01b0390911681526020016101c6565b34801561024a57600080fd5b50610144610259366004612d03565b610c4d565b34801561026a57600080fd5b50610226610279366004612ddb565b610d82565b34801561028a57600080fd5b50610144610299366004612c4c565b611144565b3480156102aa57600080fd5b506102267f000000000000000000000000000000000000000000000000000000000000000081565b3480156102de57600080fd5b506102266102ed366004612ab2565b6001600160a01b039081166000908152600260205260409020600101541690565b34801561031a57600080fd5b50610144610329366004612b95565b611487565b34801561033a57600080fd5b506101bc610349366004612c3a565b6117aa565b34801561035a57600080fd5b50610144610369366004612ab2565b61187e565b34801561037a57600080fd5b50610144610389366004612ace565b61194d565b34801561039a57600080fd5b506102266103a9366004612ab2565b6001600160a01b03908116600090815260026020819052604090912001541690565b3480156103d757600080fd5b506101446103e6366004612b95565b611a1f565b3480156103f757600080fd5b50610144610406366004612b06565b611d6f565b6001600160a01b0381811660009081526002602052604090206001015482911633146104515760405163472511eb60e11b81523360048201526024015b60405180910390fd5b6001600160a01b038216600081815260026020819052604080832090910180546001600160a01b0319169055517f6c2460a415b84be3720c209fe02f2cad7a6bcba21e8637afe8957b7ec4b6ef879190a25050565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050610535578251604051630e8c626560e41b815260040161044891815260200190565b8151835114610564578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061057183612020565b63ffffffff16146105a75761058582612020565b60405163fcc487c160e01b815263ffffffff9091166004820152602401610448565b82516000190160005b8181101561069e578481600101815181106105db57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031685828151811061060c57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161061063e5760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061066657634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16141561069657604051630db7e4c760e01b815260048101829052602401610448565b6001016105b0565b50600063ffffffff168382815181106106c757634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff1614156106f757604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff16111561072a5760405163308440e360e21b815263ffffffff82166004820152602401610448565b61079a8b8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b9250612073915050565b61080d8b8b8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92508b91506120c59050565b5050505050505050505050565b6001600160a01b03818116600090815260026020526040902060010154829116331461085b5760405163472511eb60e11b8152336004820152602401610448565b6001600160a01b03808316600081815260026020819052604080832091820180546001600160a01b0319169055600190910154905191931691907f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d0908490a4506001600160a01b0316600090815260026020526040902060010180546001600160a01b0319169055565b6001600160a01b038116600090815260026020526040812054610909576000610915565b816001600160a01b0316315b6001600160a01b0383166000908152602081905260409020546109389190612f98565b92915050565b6000858580806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208089028281018201909352888252909350889250879182918501908490808284376000920191909152505083518692506002111590506109cf578251604051630e8c626560e41b815260040161044891815260200190565b81518351146109fe578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240610a0b83612020565b63ffffffff1614610a1f5761058582612020565b82516000190160005b81811015610b1657848160010181518110610a5357634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110610a8457634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610610ab65760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110610ade57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610b0e57604051630db7e4c760e01b815260048101829052602401610448565b600101610a28565b50600063ffffffff16838281518110610b3f57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610b6f57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115610ba25760405163308440e360e21b815263ffffffff82166004820152602401610448565b6000610c138a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b925061239f915050565b9050610c3f7f0000000000000000000000000000000000000000000000000000000000000000826123d5565b9a9950505050505050505050565b60008167ffffffffffffffff811115610c7657634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610c9f578160200160208202803683370190505b50905060008415610cb657610cb38661247a565b90505b60005b83811015610d3257610cff87868684818110610ce557634e487b7160e01b600052603260045260246000fd5b9050602002016020810190610cfa9190612ab2565b6124cd565b838281518110610d1f57634e487b7160e01b600052603260045260246000fd5b6020908102919091010152600101610cb9565b50856001600160a01b03167fa9e30bf144f83390a4fe47562a4e16892108102221c674ff538da0b72a83d17482868686604051610d729493929190612f08565b60405180910390a2505050505050565b600086868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050610e13578251604051630e8c626560e41b815260040161044891815260200190565b8151835114610e42578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240610e4f83612020565b63ffffffff1614610e635761058582612020565b82516000190160005b81811015610f5a57848160010181518110610e9757634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110610ec857634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610610efa5760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110610f2257634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610f5257604051630db7e4c760e01b815260048101829052602401610448565b600101610e6c565b50600063ffffffff16838281518110610f8357634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415610fb357604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115610fe65760405163308440e360e21b815263ffffffff82166004820152602401610448565b60006110578b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c925061239f915050565b90506001600160a01b038616611098576110917f000000000000000000000000000000000000000000000000000000000000000082612539565b94506110f5565b6110c17f00000000000000000000000000000000000000000000000000000000000000006125e9565b6001600160a01b03818116600090815260026020526040902060010180546001600160a01b03191691891691909117905594505b6001600160a01b038516600081815260026020526040808220849055517f8d5f9943c664a3edaf4d3eb18cc5e2c45a7d2dc5869be33d33bbc0fff9bc25909190a2505050509695505050505050565b6001600160a01b0388811660009081526002602052604090206001015489911633146111855760405163472511eb60e11b8152336004820152602401610448565b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050611214578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611243578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061125083612020565b63ffffffff16146112645761058582612020565b82516000190160005b8181101561135b5784816001018151811061129857634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03168582815181106112c957634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316106112fb5760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061132357634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16141561135357604051630db7e4c760e01b815260048101829052602401610448565b60010161126d565b50600063ffffffff1683828151811061138457634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff1614156113b457604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156113e75760405163308440e360e21b815263ffffffff82166004820152602401610448565b6113f58c8b8b8b8b8b612698565b6114798c8c8c8c80806020026020016040519081016040528093929190818152602001838360200280828437600081840152601f19601f820116905080830192505050505050508b8b808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152508d92508c91506120c59050565b505050505050505050505050565b6001600160a01b0387811660009081526002602052604090206001015488911633146114c85760405163472511eb60e11b8152336004820152602401610448565b86868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a02828101820190935289825290935089925088918291850190849080828437600092019190915250508351879250600211159050611557578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611586578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f424061159383612020565b63ffffffff16146115a75761058582612020565b82516000190160005b8181101561169e578481600101815181106115db57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031685828151811061160c57634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b03161061163e5760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff1684828151811061166657634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16141561169657604051630db7e4c760e01b815260048101829052602401610448565b6001016115b0565b50600063ffffffff168382815181106116c757634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff1614156116f757604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff16111561172a5760405163308440e360e21b815263ffffffff82166004820152602401610448565b6117388b8b8b8b8b8b612698565b61080d8b8b8b8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808f0282810182019093528e82529093508e92508d9182918501908490808284376000920191909152508c92508b91506127589050565b6001600160a01b0382166000908152600260205260408120546117ce576000611847565b6040516370a0823160e01b81526001600160a01b0384811660048301528316906370a082319060240160206040518083038186803b15801561180f57600080fd5b505afa158015611823573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118479190612e6c565b6001600160a01b038084166000908152600160209081526040808320938816835292905220546118779190612f98565b9392505050565b6001600160a01b038181166000908152600260208190526040909120015482911633146118c05760405163472511eb60e11b8152336004820152602401610448565b6001600160a01b03808316600081815260026020819052604080832091820180546001600160a01b0319169055600190910154905133949190911692917f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d091a4506001600160a01b0316600090815260026020526040902060010180546001600160a01b03191633179055565b6001600160a01b03828116600090815260026020526040902060010154839116331461198e5760405163472511eb60e11b8152336004820152602401610448565b816001600160a01b0381166119c15760405163c369130760e01b81526001600160a01b0382166004820152602401610448565b6001600160a01b03848116600081815260026020819052604080832090910180546001600160a01b0319169488169485179055517f107cf6ea8668d533df1aab5bb8b6315bb0c25f0b6c955558d09368f290668fc79190a350505050565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050611aae578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611add578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240611aea83612020565b63ffffffff1614611afe5761058582612020565b82516000190160005b81811015611bf557848160010181518110611b3257634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110611b6357634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610611b955760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110611bbd57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611bed57604051630db7e4c760e01b815260048101829052602401610448565b600101611b07565b50600063ffffffff16838281518110611c1e57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611c4e57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff161115611c815760405163308440e360e21b815263ffffffff82166004820152602401610448565b611cf18a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b9250612073915050565b611d638a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c9182918501908490808284376000920191909152508b92508a91506127589050565b50505050505050505050565b6001600160a01b038681166000908152600260205260409020600101548791163314611db05760405163472511eb60e11b8152336004820152602401610448565b85858080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808902828101820190935288825290935088925087918291850190849080828437600092019190915250508351869250600211159050611e3f578251604051630e8c626560e41b815260040161044891815260200190565b8151835114611e6e578251825160405163b34f351d60e01b815260048101929092526024820152604401610448565b620f4240611e7b83612020565b63ffffffff1614611e8f5761058582612020565b82516000190160005b81811015611f8657848160010181518110611ec357634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b0316858281518110611ef457634e487b7160e01b600052603260045260246000fd5b60200260200101516001600160a01b031610611f265760405163ac6bd23360e01b815260048101829052602401610448565b600063ffffffff16848281518110611f4e57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611f7e57604051630db7e4c760e01b815260048101829052602401610448565b600101611e98565b50600063ffffffff16838281518110611faf57634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff161415611fdf57604051630db7e4c760e01b815260048101829052602401610448565b50620186a08163ffffffff1611156120125760405163308440e360e21b815263ffffffff82166004820152602401610448565b611d638a8a8a8a8a8a612698565b8051600090815b8181101561206c5783818151811061204f57634e487b7160e01b600052603260045260246000fd5b6020026020010151836120629190612fb0565b9250600101612027565b5050919050565b600061208084848461239f565b6001600160a01b03861660009081526002602052604090205490915081146120be5760405163dd5ff45760e01b815260048101829052602401610448565b5050505050565b6001600160a01b038581166000818152600160209081526040808320948b16808452949091528082205490516370a0823160e01b815260048101949094529092909183916370a082319060240160206040518083038186803b15801561212a57600080fd5b505afa15801561213e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121629190612e6c565b9050801561216f57600019015b811561217c576001820391505b818101925081156121b0576001600160a01b038089166000908152600160208181526040808420948e168452939052919020555b836001600160a01b0316886001600160a01b03168a6001600160a01b03167fb5ee5dc3d2c31a019bbf2c787e0e9c97971c96aceea1c38c12fc8fd25c536d46866040516121ff91815260200190565b60405180910390a463ffffffff851615612271576001600160a01b038881166000908152600160205260408120620f424063ffffffff891687020492839290881661224a573361224c565b875b6001600160a01b03168152602081019190915260400160002080549091019055909203915b865160005b81811015612329576122ba858983815181106122a257634e487b7160e01b600052603260045260246000fd5b602002602001015163ffffffff16620f424091020490565b6001600160a01b038b1660009081526001602052604081208b519091908c90859081106122f757634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b0316825281019190915260400160002080549091019055600101612276565b5050801561239457604051633e0f9fff60e11b81526001600160a01b038981166004830152602482018390528a1690637c1f3ffe90604401600060405180830381600087803b15801561237b57600080fd5b505af115801561238f573d6000803e3d6000fd5b505050505b505050505050505050565b60008383836040516020016123b693929190612e84565b6040516020818303038152906040528051906020012090509392505050565b6000611877838330604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b6033820152606093841b60468201526d5af43d3d93803e605b57fd5bf3ff60901b605a820152921b6068830152607c8201526067808220609c830152605591012090565b6001600160a01b03811660009081526020819052604081205461249f90600190612fd8565b6001600160a01b0383166000818152602081905260409020600190559091506124c8908261293a565b919050565b6001600160a01b038082166000908152600160208181526040808420948716845293905291812054909161250091612fd8565b6001600160a01b038084166000818152600160208181526040808420958a16845294905292902091909155909150610938908483612990565b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528360601b60468201526c5af43d3d93803e605b57fd5bf360981b605a820152826067826000f59150506001600160a01b0381166109385760405163380bbe1360e01b815260040160405180910390fd5b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528260601b60468201526c5af43d3d93803e605b57fd5bf360981b605a8201526067816000f09150506001600160a01b0381166124c857604051630985da9b60e41b815260040160405180910390fd5b600061270986868080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808a0282810182019093528982529093508992508891829185019084908082843760009201919091525087925061239f915050565b6001600160a01b0388166000818152600260205260408082208490555192935090917f45e1e99513dd915ac128b94953ca64c6375717ea1894b3114db08cdca51debd29190a250505050505050565b6001600160a01b0385166000818152602081905260408120549131908215612781576001830392505b5081810182156127a8576001600160a01b0388166000908152602081905260409020600190555b836001600160a01b0316886001600160a01b03167f87c3ca0a87d9b82033e4bc55e6d30621f8d7e0c9d8ca7988edfde8932787b77b836040516127ed91815260200190565b60405180910390a363ffffffff85161561284c57620f424063ffffffff8616820204806000806001600160a01b0388166128275733612829565b875b6001600160a01b0316815260208101919091526040016000208054909101905590035b865160005b818110156128d25761287d838983815181106122a257634e487b7160e01b600052603260045260246000fd5b6000808b84815181106128a057634e487b7160e01b600052603260045260246000fd5b6020908102919091018101516001600160a01b0316825281019190915260400160002080549091019055600101612851565b5050811561293057604051632ac3affd60e21b8152600481018390526001600160a01b0389169063ab0ebff490602401600060405180830381600087803b15801561291c57600080fd5b505af1158015611479573d6000803e3d6000fd5b5050505050505050565b600080600080600085875af190508061298b5760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610448565b505050565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af19150506129cb81612a0f565b612a095760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b6044820152606401610448565b50505050565b60003d82612a2157806000803e806000fd5b8060208114612a39578015612a4a576000925061206c565b816000803e6000511515925061206c565b5060019392505050565b60008083601f840112612a65578182fd5b50813567ffffffffffffffff811115612a7c578182fd5b6020830191508360208260051b8501011115612a9757600080fd5b9250929050565b803563ffffffff811681146124c857600080fd5b600060208284031215612ac3578081fd5b813561187781613005565b60008060408385031215612ae0578081fd5b8235612aeb81613005565b91506020830135612afb81613005565b809150509250929050565b60008060008060008060808789031215612b1e578182fd5b8635612b2981613005565b9550602087013567ffffffffffffffff80821115612b45578384fd5b612b518a838b01612a54565b90975095506040890135915080821115612b69578384fd5b50612b7689828a01612a54565b9094509250612b89905060608801612a9e565b90509295509295509295565b600080600080600080600060a0888a031215612baf578081fd5b8735612bba81613005565b9650602088013567ffffffffffffffff80821115612bd6578283fd5b612be28b838c01612a54565b909850965060408a0135915080821115612bfa578283fd5b50612c078a828b01612a54565b9095509350612c1a905060608901612a9e565b91506080880135612c2a81613005565b8091505092959891949750929550565b60008060408385031215612ae0578182fd5b60008060008060008060008060c0898b031215612c67578081fd5b8835612c7281613005565b97506020890135612c8281613005565b9650604089013567ffffffffffffffff80821115612c9e578283fd5b612caa8c838d01612a54565b909850965060608b0135915080821115612cc2578283fd5b50612ccf8b828c01612a54565b9095509350612ce2905060808a01612a9e565b915060a0890135612cf281613005565b809150509295985092959890939650565b60008060008060608587031215612d18578384fd5b8435612d2381613005565b935060208501359250604085013567ffffffffffffffff811115612d45578283fd5b612d5187828801612a54565b95989497509550505050565b600080600080600060608688031215612d74578081fd5b853567ffffffffffffffff80821115612d8b578283fd5b612d9789838a01612a54565b90975095506020880135915080821115612daf578283fd5b50612dbc88828901612a54565b9094509250612dcf905060408701612a9e565b90509295509295909350565b60008060008060008060808789031215612df3578182fd5b863567ffffffffffffffff80821115612e0a578384fd5b612e168a838b01612a54565b90985096506020890135915080821115612e2e578384fd5b50612e3b89828a01612a54565b9095509350612e4e905060408801612a9e565b91506060870135612e5e81613005565b809150509295509295509295565b600060208284031215612e7d578081fd5b5051919050565b835160009082906020808801845b83811015612eb75781516001600160a01b031685529382019390820190600101612e92565b50508651818801939250845b81811015612ee557845163ffffffff1684529382019392820192600101612ec3565b50505060e09490941b6001600160e01b0319168452505060049091019392505050565b84815260606020808301829052908201849052600090859060808401835b87811015612f54578335612f3981613005565b6001600160a01b031682529282019290820190600101612f26565b5084810360408601528551808252908201925081860190845b81811015612f8957825185529383019391830191600101612f6d565b50929998505050505050505050565b60008219821115612fab57612fab612fef565b500190565b600063ffffffff808316818516808303821115612fcf57612fcf612fef565b01949350505050565b600082821015612fea57612fea612fef565b500390565b634e487b7160e01b600052601160045260246000fd5b6001600160a01b038116811461301a57600080fd5b5056fea264697066735822122078638564d8f0338df6cf15b5c2680d5c2ef45167f59938471977e9756316b94964736f6c6343000804003360a060405234801561001057600080fd5b5033606081901b60805261035461004c60003960008181604b0152818160bc015281816101080152818161013c015261018601526103546000f3fe6080604052600436106100345760003560e01c80630e769b2b146100395780637c1f3ffe14610089578063ab0ebff41461009e575b600080fd5b34801561004557600080fd5b5061006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009c6100973660046102d0565b6100b1565b005b61009c6100ac366004610306565b610131565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100f9576040516282b42960e81b815260040160405180910390fd5b61012d6001600160a01b0383167f0000000000000000000000000000000000000000000000000000000000000000836101af565b5050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610179576040516282b42960e81b815260040160405180910390fd5b6101ac6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682610233565b50565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af19150506101ea81610289565b61022d5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064015b60405180910390fd5b50505050565b600080600080600085875af19050806102845760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610224565b505050565b60003d8261029b57806000803e806000fd5b80602081146102b35780156102c457600092506102c9565b816000803e600051151592506102c9565b600192505b5050919050565b600080604083850312156102e2578182fd5b82356001600160a01b03811681146102f8578283fd5b946020939093013593505050565b600060208284031215610317578081fd5b503591905056fea26469706673582212208e095a368bcb2efb2a8afd9b560ad94441e926086a4bc92edf16c33900df798e64736f6c63430008040033

Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.

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.