Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Create Split | 19328749 | 321 days ago | IN | 0 ETH | 0.00798642 |
Latest 2 internal transactions
Advanced mode:
Parent Transaction Hash | Block |
From
|
To
|
|||
---|---|---|---|---|---|---|
19328749 | 321 days ago | Contract Creation | 0 ETH | |||
18582491 | 425 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
SplitMain
Compiler Version
v0.8.18+commit.87f61d96
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.16; import { ISplitMain } from "./interfaces/ISplitMain.sol"; import { SplitWallet } from "./SplitWallet.sol"; import { Clones } from "../utils/Clones.sol"; import { IERC20Upgradeable as IERC20 } from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import { SafeTransferLib } from "solady/utils/SafeTransferLib.sol"; import { IWETH } from "../interfaces/IWETH.sol"; import { ISonaSwap } from "lib/common/ISonaSwap.sol"; import { Ownable } from "solady/auth/Ownable.sol"; /// @title SplitMain /// @author @SonaEngineering; forked from 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, Ownable { using SafeTransferLib for address; using SafeTransferLib for IERC20; /// ERRORS /// @notice Unauthorized sender `sender` /// @param sender Transaction sender error UnauthorizedController(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); // // 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; /// @notice address of the WETH token IWETH public immutable WETH9; /// @notice address of the USDC token IERC20 public immutable USDC; /// @notice address of the swapper contract that converts (W)ETH to USDC ISonaSwap public swap; // // STORAGE - VARIABLES - PRIVATE & INTERNAL // /// @notice mapping to account ETH balances mapping(address => uint256) internal _ethBalances; /// @notice mapping to account ERC20 balances mapping(IERC20 => 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 UnauthorizedController(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 UnauthorizedController(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 modifier validSplit( address[] memory accounts, uint32[] memory percentAllocations ) { _validSplit(accounts, percentAllocations); _; } /// @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(IWETH _weth, IERC20 _usdc, ISonaSwap _swap) { walletImplementation = address(new SplitWallet()); WETH9 = _weth; USDC = _usdc; swap = _swap; _initializeOwner(msg.sender); } // 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 {} // solhint-disable-line no-empty-blocks /// @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 /// @return split Address of newly created split function createSplit( address[] calldata accounts, uint32[] calldata percentAllocations ) public override validSplit(accounts, percentAllocations) returns (address split) { bytes32 splitHash = _hashSplit(accounts, percentAllocations); // create mutable split split = Clones.clone(walletImplementation); _splits[split].controller = msg.sender; // store split's hash in storage for future verification _splits[split].hash = splitHash; emit CreateSplit(split); } /// @notice create multiple splits in a one call /// @dev the same config can be created multiple times /// @param splits the array structured objects representing the split configs function createSplits( SplitInput[] calldata splits ) external override returns (address[] memory splitAddresses) { uint256 splitsLength = splits.length; splitAddresses = new address[](splitsLength); for (uint256 idx; idx < splitsLength; idx++) { splitAddresses[idx] = createSplit( splits[idx].accounts, splits[idx].percentAllocations ); } } /// @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 function updateSplit( address split, address[] calldata accounts, uint32[] calldata percentAllocations ) external override onlySplitController(split) validSplit(accounts, percentAllocations) { _updateSplit(split, accounts, percentAllocations); } /// @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 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 function distributeETH( address split, address[] calldata accounts, uint32[] calldata percentAllocations ) external override validSplit(accounts, percentAllocations) { // use internal fn instead of modifier to avoid stack depth compiler errors _validSplitHash(split, accounts, percentAllocations); _convertWETHToUSDCAndDistribute(split, accounts, percentAllocations); } /// @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 function updateAndDistributeETH( address split, address[] calldata accounts, uint32[] calldata percentAllocations ) external override onlySplitController(split) validSplit(accounts, percentAllocations) { _updateSplit(split, accounts, percentAllocations); // know splitHash is valid immediately after updating; only accessible via controller _convertWETHToUSDCAndDistribute(split, accounts, percentAllocations); } /// @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 function distributeERC20( address split, IERC20 token, address[] calldata accounts, uint32[] calldata percentAllocations ) external override validSplit(accounts, percentAllocations) { // use internal fn instead of modifier to avoid stack depth compiler errors _validSplitHash(split, accounts, percentAllocations); if (address(token) == address(USDC)) { _distributeERC20(split, token, accounts, percentAllocations); } else if (address(token) == address(WETH9)) { _convertWETHToUSDCAndDistribute(split, accounts, percentAllocations); } else { uint256 proxyBalance = token.balanceOf(split); SplitWallet(split).sendERC20ToMain(token, proxyBalance); _erc20Balances[token][_splits[split].controller] += proxyBalance; } } /// @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 function updateAndDistributeERC20( address split, IERC20 token, address[] calldata accounts, uint32[] calldata percentAllocations ) external override onlySplitController(split) validSplit(accounts, percentAllocations) { _updateSplit(split, accounts, percentAllocations); // know splitHash is valid immediately after updating; only accessible via controller _distributeERC20(split, token, accounts, percentAllocations); } /// @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, IERC20[] 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); } } /// @notice the owner updates the SonaSwap implementation to `_newSwap` /// @param _newSwap the new ISonaSwapImplementation to be utilized function updateSwap(ISonaSwap _newSwap) external onlyOwner { swap = _newSwap; } /// 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 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, IERC20 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 ensure a split configuration is valid in both contents and organization /// @dev reverts if there are fewer than 2 accounts, the arrays are different length, /// the allocations don't add up to 1e6, or accounts aren't sorted in the array /// @param accounts Ordered, unique list of addresses with ownership in the split /// @param percentAllocations Percent allocations associated with each address function _validSplit( address[] memory accounts, uint32[] memory percentAllocations ) internal pure { 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); } } /// @notice Hashes a split /// @param accounts Ordered, unique list of addresses with ownership in the split /// @param percentAllocations Percent allocations associated with each address /// @return computedHash Hash of the split. function _hashSplit( address[] memory accounts, uint32[] memory percentAllocations ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(accounts, percentAllocations)); } /// @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 function _updateSplit( address split, address[] calldata accounts, uint32[] calldata percentAllocations ) internal { bytes32 splitHash = _hashSplit(accounts, percentAllocations); // store new hash in storage for future verification _splits[split].hash = splitHash; emit UpdateSplit(split); } /// @notice Checks hash from `accounts`, `percentAllocations` 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 function _validSplitHash( address split, address[] memory accounts, uint32[] memory percentAllocations ) internal view { bytes32 hash = _hashSplit(accounts, percentAllocations); 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 function _distributeETH( address split, address[] memory accounts, uint32[] memory percentAllocations ) 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 emit DistributeETH(split, amountToSplit); // 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); 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) { uint256 balance = _scaleAmountByPercentage( amountToSplit, percentAllocations[i] ); if (!_trySendingETH(accounts[i], balance)) { // overflow should be impossible with validated allocations _ethBalances[accounts[i]] += balance; } } } } function _convertWETHToUSDCAndDistribute( address split, address[] memory accounts, uint32[] memory percentAllocations ) internal returns (uint256 usdcToSplit) { uint256 wethToSwap; uint256 mainBalance = _erc20Balances[WETH9][split]; uint256 mainETHBalance = _ethBalances[split]; uint256 proxyBalance = WETH9.balanceOf(split); uint256 proxyETHBalance = split.balance; 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; } if (mainETHBalance > 0) { mainETHBalance -= 1; } // overflow should be impossible wethToSwap = mainBalance + mainETHBalance + proxyBalance + proxyETHBalance; // 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(WETH9, proxyBalance); if (proxyETHBalance > 0) { SplitWallet(split).sendETHToMain(proxyETHBalance); WETH9.deposit{ value: proxyETHBalance }(); } if (mainETHBalance > 0) { WETH9.deposit{ value: mainETHBalance }(); } } WETH9.approve(address(swap), wethToSwap); usdcToSplit = swap.swapWEthForUSDC(wethToSwap); unchecked { // cache accounts length to save gas uint256 accountsLength = accounts.length; for (uint256 i = 0; i < accountsLength; ++i) { uint256 balance = _scaleAmountByPercentage( usdcToSplit, percentAllocations[i] ); if (!_trySendingERC20(USDC, accounts[i], balance)) _erc20Balances[USDC][accounts[i]] += balance; } } } function _trySendingETH( address account, uint256 amount ) internal returns (bool success) { // solhint-disable-next-line check-send-result return payable(account).send(amount); } /// @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 function _distributeERC20( address split, IERC20 token, address[] memory accounts, uint32[] memory percentAllocations ) 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); // 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); // 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) { uint256 balance = _scaleAmountByPercentage( amountToSplit, percentAllocations[i] ); if (!_trySendingERC20(token, accounts[i], balance)) _erc20Balances[token][accounts[i]] += balance; } } } function _trySendingERC20( IERC20 token, address account, uint256 amount ) internal returns (bool success) { // TODO for and modify the solady `safeTransfer` function to return false // when the receiver contract doesn't have the right interface return token.transfer(account, amount); } /// @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 // solhint-disable-next-line no-inline-assembly assembly ("memory-safe") { /* 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, IERC20 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; address(token).safeTransfer(account, withdrawn); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.16; import { IERC20Upgradeable as IERC20 } from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol"; /// @title ISplitMain /// @author 0xSplits <[email protected]> interface ISplitMain { /// Structs struct SplitInput { address[] accounts; uint32[] percentAllocations; } /// FUNCTIONS function walletImplementation() external returns (address); function createSplit( address[] calldata accounts, uint32[] calldata percentAllocations ) external returns (address); function updateSplit( address split, address[] calldata accounts, uint32[] calldata percentAllocations ) external; function distributeETH( address split, address[] calldata accounts, uint32[] calldata percentAllocations ) external; function updateAndDistributeETH( address split, address[] calldata accounts, uint32[] calldata percentAllocations ) external; function distributeERC20( address split, IERC20 token, address[] calldata accounts, uint32[] calldata percentAllocations ) external; function updateAndDistributeERC20( address split, IERC20 token, address[] calldata accounts, uint32[] calldata percentAllocations ) external; function withdraw( address account, uint256 withdrawETH, IERC20[] calldata tokens ) external; function createSplits( SplitInput[] calldata splits ) external returns (address[] memory split); function transferControl(address split, address newController) external; function cancelControlTransfer(address split) external; function acceptControl(address split) 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 event DistributeETH(address indexed split, uint256 amount); /// @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 event DistributeERC20( address indexed split, IERC20 indexed token, uint256 amount ); /// @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, IERC20[] tokens, uint256[] tokenAmounts ); }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.16; import { ISplitMain } from "./interfaces/ISplitMain.sol"; import { IERC20Upgradeable as IERC20 } from "openzeppelin-upgradeable/token/ERC20/IERC20Upgradeable.sol"; import { SafeTransferLib } from "solady/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; ///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( IERC20 token, uint256 amount ) external payable onlySplitMain { address(token).safeTransfer(address(splitMain), amount); } }
// SPDX-License-Identifier: GPL-3.0-or-later pragma solidity ^0.8.16; /// @notice create opcode failed error CreateError(); /// @notice create2 opcode failed error Create2Error(); // solhint-disable no-inline-assembly /// @author 0xSplits <[email protected]> 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 * * code: 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 ("memory-safe") { 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 ("memory-safe") { 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 ("memory-safe") { let ptr := mload(0x40) mstore( ptr, 0x3d605d80600a3d3981f336603057343d52307f00000000000000000000000000 ) mstore( add(ptr, 0x13), 0x830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b1 ) mstore( add(ptr, 0x33), 0x60203da23d3df35b3d3d3d3d363d3d37363d7300000000000000000000000000 ) mstore(add(ptr, 0x46), shl(0x60, implementation)) mstore( add(ptr, 0x5a), 0x5af43d3d93803e605b57fd5bf3ff000000000000000000000000000000000000 ) mstore(add(ptr, 0x68), shl(0x60, deployer)) mstore(add(ptr, 0x7c), salt) mstore(add(ptr, 0x9c), keccak256(ptr, 0x67)) predicted := keccak256(add(ptr, 0x67), 0x55) } } /** * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}. */ function predictDeterministicAddress( address implementation, bytes32 salt ) internal view returns (address predicted) { return predictDeterministicAddress(implementation, salt, address(this)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20Upgradeable { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom(address from, address to, uint256 amount) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol) /// @dev Caution! This library won't check that a token has code, responsibility is delegated to the caller. library SafeTransferLib { /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH /// that disallows any storage writes. uint256 internal constant _GAS_STIPEND_NO_STORAGE_WRITES = 2300; /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. /// Multiply by a small constant (e.g. 2), if needed. uint256 internal constant _GAS_STIPEND_NO_GRIEF = 100000; /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev Sends `amount` (in wei) ETH to `to`. /// Reverts upon failure. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. if iszero(call(gas(), to, amount, 0, 0, 0, 0)) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// The `gasStipend` can be set to a low enough value to prevent /// storage writes or gas griefing. /// /// If sending via the normal procedure fails, force sends the ETH by /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH. /// /// Reverts if the current contract has insufficient balance. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal { /// @solidity memory-safe-assembly assembly { // If insufficient balance, revert. if lt(selfbalance(), amount) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } // Transfer the ETH and check if it succeeded or not. if iszero(call(gasStipend, to, amount, 0, 0, 0, 0)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. // We can directly use `SELFDESTRUCT` in the contract creation. // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758 pop(create(amount, 0x0b, 0x16)) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a gas stipend /// equal to `_GAS_STIPEND_NO_GRIEF`. This gas stipend is a reasonable default /// for 99% of cases and can be overriden with the three-argument version of this /// function if necessary. /// /// If sending via the normal procedure fails, force sends the ETH by /// creating a temporary contract which uses `SELFDESTRUCT` to force send the ETH. /// /// Reverts if the current contract has insufficient balance. function forceSafeTransferETH(address to, uint256 amount) internal { // Manually inlined because the compiler doesn't inline functions with branches. /// @solidity memory-safe-assembly assembly { // If insufficient balance, revert. if lt(selfbalance(), amount) { // Store the function selector of `ETHTransferFailed()`. mstore(0x00, 0xb12d13eb) // Revert with (offset, size). revert(0x1c, 0x04) } // Transfer the ETH and check if it succeeded or not. if iszero(call(_GAS_STIPEND_NO_GRIEF, to, amount, 0, 0, 0, 0)) { mstore(0x00, to) // Store the address in scratch space. mstore8(0x0b, 0x73) // Opcode `PUSH20`. mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`. // We can directly use `SELFDESTRUCT` in the contract creation. // Compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758 pop(create(amount, 0x0b, 0x16)) } } } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// The `gasStipend` can be set to a low enough value to prevent /// storage writes or gas griefing. /// /// Simply use `gasleft()` for `gasStipend` if you don't need a gas stipend. /// /// Note: Does NOT revert upon failure. /// Returns whether the transfer of ETH is successful instead. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { // Transfer the ETH and check if it succeeded or not. success := call(gasStipend, to, amount, 0, 0, 0, 0) } } /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x00, 0x23b872dd) mstore(0x20, from) // Store the `from` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x60, amount) // Store the `amount` argument. if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferAllFrom(address token, address from, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, from) // Store the `from` argument. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } // Store the function selector of `transferFrom(address,address,uint256)`. mstore(0x00, 0x23b872dd) mstore(0x40, to) // Store the `to` argument. // The `amount` argument is already written to the memory word at 0x6a. amount := mload(0x60) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) ) ) { // Store the function selector of `TransferFromFailed()`. mstore(0x00, 0x7939f424) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x1a, to) // Store the `to` argument. mstore(0x3a, amount) // Store the `amount` argument. // Store the function selector of `transfer(address,uint256)`, // left by 6 bytes (enough for 8tb of memory represented by the free memory pointer). // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL). mstore(0x00, 0xa9059cbb000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x16, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, if less than 8tb of memory is used. mstore(0x3a, 0) } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x3a, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } mstore(0x1a, to) // Store the `to` argument. // The `amount` argument is already written to the memory word at 0x3a. amount := mload(0x3a) // Store the function selector of `transfer(address,uint256)`, // left by 6 bytes (enough for 8tb of memory represented by the free memory pointer). // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL). mstore(0x00, 0xa9059cbb000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x16, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `TransferFailed()`. mstore(0x00, 0x90b8ec18) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, if less than 8tb of memory is used. mstore(0x3a, 0) } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x1a, to) // Store the `to` argument. mstore(0x3a, amount) // Store the `amount` argument. // Store the function selector of `approve(address,uint256)`, // left by 6 bytes (enough for 8tb of memory represented by the free memory pointer). // We waste 6-3 = 3 bytes to save on 6 runtime gas (PUSH1 0x224 SHL). mstore(0x00, 0x095ea7b3000000000000) if iszero( and( // The arguments of `and` are evaluated from right to left. // Set success to whether the call reverted, if not we check it either // returned exactly 1 (can't just be non-zero data), or had no return data. or(eq(mload(0x00), 1), iszero(returndatasize())), call(gas(), token, 0, 0x16, 0x44, 0x00, 0x20) ) ) { // Store the function selector of `ApproveFailed()`. mstore(0x00, 0x3e3f8f73) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore the part of the free memory pointer that was overwritten, // which is guaranteed to be zero, if less than 8tb of memory is used. mstore(0x3a, 0) } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, account) // Store the `account` argument. amount := mul( mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x20, 0x20) ) ) } } }
// SPDX-License-Identifier: GPL-3.0 pragma solidity ^0.8.16; import { IERC20Upgradeable as IERC20 } from "openzeppelin-upgradeable/interfaces/IERC20Upgradeable.sol"; interface IWETH is IERC20 { event Deposit(address indexed dst, uint wad); event Withdrawal(address indexed src, uint wad); function deposit() external payable; function withdraw(uint wad) external; }
// SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.6; interface ISonaSwap { function getUsdEthPrice() external view returns (uint256 price); function swapWEthForUSDC(uint256 _amount) external returns (uint256 amountOut); function swapEthForUSDC() external payable returns (uint256 amountOut); function getQuote( uint256 _amount, uint256 _rate ) external pure returns (uint256 minimumAmount) ; function getQuote( uint256 _amount ) external view returns (uint256 minimumAmount); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) /// for compatibility, the nomenclature for the 2-step ownership handover /// may be unique to this codebase. abstract contract Ownable { /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev `bytes4(keccak256(bytes("Unauthorized()")))`. uint256 private constant _UNAUTHORIZED_ERROR_SELECTOR = 0x82b42900; /// @dev `bytes4(keccak256(bytes("NewOwnerIsZeroAddress()")))`. uint256 private constant _NEW_OWNER_IS_ZERO_ADDRESS_ERROR_SELECTOR = 0x7448fbae; /// @dev `bytes4(keccak256(bytes("NoHandoverRequest()")))`. uint256 private constant _NO_HANDOVER_REQUEST_ERROR_SELECTOR = 0x6f5e8818; /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. /// It is intentionally choosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(not(_OWNER_SLOT_NOT), newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { let ownerSlot := not(_OWNER_SLOT_NOT) // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } } /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, _NEW_OWNER_IS_ZERO_ADDRESS_ERROR_SELECTOR) revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will be automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, _NO_HANDOVER_REQUEST_ERROR_SELECTOR) revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(not(_OWNER_SLOT_NOT)) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. function ownershipHandoverValidFor() public view virtual returns (uint64) { return 48 * 3600; } /*´:°â€¢.°+.*•´.*:Ëš.°*.˚•´.°:°â€¢.°â€¢.*•´.*:Ëš.°*.˚•´.°:°â€¢.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+Ëš.*°.Ëš:*.´â€¢*.+°.•°:´*.´â€¢*.•°.•°:°.´:•˚°.*°.Ëš:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol) pragma solidity ^0.8.0; import "../token/ERC20/IERC20Upgradeable.sol";
{ "remappings": [ "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "@openzeppelin/=lib_v7/v3-periphery/node_modules/@openzeppelin/", "erc721a-upgradeable/=lib/ERC721A-Upgradeable/contracts/", "openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/", "solady/=lib/solady/src/", "closedsea/=lib/closedsea/src/", "solmate/=lib/solmate/src/", "murky/=lib/murky/src/", "ERC721A-Upgradeable/=lib/ERC721A-Upgradeable/contracts/", "chainlink/=lib/chainlink/", "common/=lib/common/", "erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/", "erc721a/=lib/closedsea/lib/erc721a/contracts/", "openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "operator-filter-registry/=lib/closedsea/lib/operator-filter-registry/", "v3-core/=lib/v3-core/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "none", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": { "contracts/utils/AddressableTokenId.sol": { "AddressableTokenId": "0xe5e085EA620d100e951Fb6687d8064d2a2aAB48A" }, "contracts/utils/ZeroCheck.sol": { "ZeroCheck": "0xdABAAD81d0453699A7d25D277Ea5edD7b89ceDD4" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"contract IWETH","name":"_weth","type":"address"},{"internalType":"contract IERC20Upgradeable","name":"_usdc","type":"address"},{"internalType":"contract ISonaSwap","name":"_swap","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"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":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"UnauthorizedController","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 IERC20Upgradeable","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"DistributeERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"split","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"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":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","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 IERC20Upgradeable[]","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":[],"name":"USDC","outputs":[{"internalType":"contract IERC20Upgradeable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WETH9","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"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":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"}],"name":"createSplit","outputs":[{"internalType":"address","name":"split","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"}],"internalType":"struct ISplitMain.SplitInput[]","name":"splits","type":"tuple[]"}],"name":"createSplits","outputs":[{"internalType":"address[]","name":"splitAddresses","type":"address[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"},{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"}],"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[]"}],"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 IERC20Upgradeable","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":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipHandoverValidFor","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"swap","outputs":[{"internalType":"contract ISonaSwap","name":"","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":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"split","type":"address"},{"internalType":"contract IERC20Upgradeable","name":"token","type":"address"},{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint32[]","name":"percentAllocations","type":"uint32[]"}],"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[]"}],"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[]"}],"name":"updateSplit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract ISonaSwap","name":"_newSwap","type":"address"}],"name":"updateSwap","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 IERC20Upgradeable[]","name":"tokens","type":"address[]"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
Contract Creation Code
60e06040523480156200001157600080fd5b5060405162002caa38038062002caa833981016040819052620000349162000108565b6040516200004290620000e1565b604051809103906000f0801580156200005f573d6000803e3d6000fd5b506001600160a01b0390811660805283811660a05282811660c052600080546001600160a01b0319169183169190911790556200009c33620000a5565b5050506200015c565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6102bc80620029ee83390190565b6001600160a01b03811681146200010557600080fd5b50565b6000806000606084860312156200011e57600080fd5b83516200012b81620000ef565b60208501519093506200013e81620000ef565b60408501519092506200015181620000ef565b809150509250925092565b60805160a05160c05161281c620001d2600039600081816103da01528181610b6401528181611d410152611d8e0152600081816102ae01528181610c110152818161192d01528181611a3601528181611b0401528181611b7f0152611c1b01526000818161032a0152611379015261281c6000f3fe6080604052600436106101c65760003560e01c806389a30271116100f7578063c7de644011610095578063f04e283e11610064578063f04e283e14610540578063f2fde38b14610553578063f76decfe14610566578063fee81cf41461058657600080fd5b8063c7de6440146104c2578063d0e4b2f4146104e2578063d7533f0214610502578063e40dcfe31461052057600080fd5b80639ffab000116100d15780639ffab00014610435578063afaed66314610455578063c3a8962c14610482578063c458f5ed146104a257600080fd5b806389a30271146103c85780638da5cb5b146103fc57806394e6fd601461041557600080fd5b806354d1f13d116101645780638117abc11161013e5780638117abc1146103185780638119c0651461034c57806388c662aa1461036c57806389063570146103a857600080fd5b806354d1f13d146102e85780636e5f6919146102f0578063715018a61461031057600080fd5b806329701c3f116101a057806329701c3f146102455780633bb66a7b146102655780633f26479e146102855780634aa4a4fc1461029c57600080fd5b80631267c6da146101d25780631da0b8fc146101f4578063256929621461023d57600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506101f26101ed3660046122c0565b6105b9565b005b34801561020057600080fd5b5061022a61020f3660046122c0565b6001600160a01b031660009081526003602052604090205490565b6040519081526020015b60405180910390f35b6101f2610652565b34801561025157600080fd5b506101f2610260366004612329565b6106a2565b34801561027157600080fd5b5061022a6102803660046122c0565b61076b565b34801561029157600080fd5b5061022a620f424081565b3480156102a857600080fd5b506102d07f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b039091168152602001610234565b6101f26107c6565b3480156102fc57600080fd5b506101f261030b3660046123ac565b610802565b6101f261090d565b34801561032457600080fd5b506102d07f000000000000000000000000000000000000000000000000000000000000000081565b34801561035857600080fd5b506000546102d0906001600160a01b031681565b34801561037857600080fd5b506102d06103873660046122c0565b6001600160a01b039081166000908152600360205260409020600101541690565b3480156103b457600080fd5b506101f26103c3366004612329565b610921565b3480156103d457600080fd5b506102d07f000000000000000000000000000000000000000000000000000000000000000081565b34801561040857600080fd5b50638b78c6d819546102d0565b34801561042157600080fd5b506101f26104303660046122c0565b610a59565b34801561044157600080fd5b506101f2610450366004612408565b610a83565b34801561046157600080fd5b5061047561047036600461249d565b610de7565b60405161023491906124df565b34801561048e57600080fd5b5061022a61049d36600461252c565b610ee1565b3480156104ae57600080fd5b506101f26104bd366004612329565b610fa8565b3480156104ce57600080fd5b506101f26104dd3660046122c0565b6110f5565b3480156104ee57600080fd5b506101f26104fd36600461252c565b6111c0565b34801561050e57600080fd5b506040516202a3008152602001610234565b34801561052c57600080fd5b506102d061053b366004612565565b611290565b6101f261054e3660046122c0565b611402565b6101f26105613660046122c0565b611442565b34801561057257600080fd5b506101f2610581366004612408565b611469565b34801561059257600080fd5b5061022a6105a13660046122c0565b63389a75e1600c908152600091909152602090205490565b6001600160a01b0381811660009081526003602052604090206001015482911633146105ff576040516311ca4b2760e31b81523360048201526024015b60405180910390fd5b6001600160a01b03821660008181526003602052604080822060020180546001600160a01b0319169055517f6c2460a415b84be3720c209fe02f2cad7a6bcba21e8637afe8957b7ec4b6ef879190a25050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6001600160a01b0385811660009081526003602052604090206001015486911633146106e3576040516311ca4b2760e31b81523360048201526024016105f6565b848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208088028281018201909352878252909350879250869182918501908490808284376000920191909152506107549250849150839050611597565b610761888888888861174c565b5050505050505050565b6001600160a01b038116600090815260036020526040812054810361079157600061079d565b816001600160a01b0316315b6001600160a01b0383166000908152600160205260409020546107c091906125db565b92915050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b60008167ffffffffffffffff81111561081d5761081d6125ee565b604051908082528060200260200182016040528015610846578160200160208202803683370190505b5090506000841561085d5761085a86611809565b90505b60005b838110156108bd576108988786868481811061087e5761087e612604565b905060200201602081019061089391906122c0565b61185c565b8382815181106108aa576108aa612604565b6020908102919091010152600101610860565b50856001600160a01b03167fa9e30bf144f83390a4fe47562a4e16892108102221c674ff538da0b72a83d174828686866040516108fd949392919061261a565b60405180910390a2505050505050565b6109156118ca565b61091f60006118e5565b565b6001600160a01b038581166000908152600360205260409020600101548691163314610962576040516311ca4b2760e31b81523360048201526024016105f6565b848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208088028281018201909352878252909350879250869182918501908490808284376000920191909152506109d39250849150839050611597565b6109e0888888888861174c565b610a4e8888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a91829185019084908082843760009201919091525061192392505050565b505050505050505050565b610a616118ca565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808702828101820190935286825290935086925085918291850190849080828437600092019190915250610af49250849150839050611597565b610b628887878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a925089918291850190849080828437600092019190915250611e1592505050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b031603610c0f57610c0a888888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250611e6592505050565b610761565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316876001600160a01b031603610cbc57610cb68887878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a92508991829185019084908082843760009201919091525061192392505050565b50610761565b6040516370a0823160e01b81526001600160a01b038981166004830152600091908916906370a0823190602401602060405180830381865afa158015610d06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2a91906126ab565b604051633e0f9fff60e11b81526001600160a01b038a8116600483015260248201839052919250908a1690637c1f3ffe90604401600060405180830381600087803b158015610d7857600080fd5b505af1158015610d8c573d6000803e3d6000fd5b505050506001600160a01b0388811660009081526002602090815260408083208d85168452600383528184206001015490941683529290529081208054839290610dd79084906125db565b9091555050505050505050505050565b6060818067ffffffffffffffff811115610e0357610e036125ee565b604051908082528060200260200182016040528015610e2c578160200160208202803683370190505b50915060005b81811015610ed957610e9d858583818110610e4f57610e4f612604565b9050602002810190610e6191906126c4565b610e6b90806126e4565b878785818110610e7d57610e7d612604565b9050602002810190610e8f91906126c4565b61053b9060208101906126e4565b838281518110610eaf57610eaf612604565b6001600160a01b039092166020928302919091019091015280610ed18161272e565b915050610e32565b505092915050565b6001600160a01b0382166000908152600360205260408120548103610f07576000610f71565b6040516370a0823160e01b81526001600160a01b0384811660048301528316906370a0823190602401602060405180830381865afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7191906126ab565b6001600160a01b03808416600090815260026020908152604080832093881683529290522054610fa191906125db565b9392505050565b838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208087028281018201909352868252909350869250859182918501908490808284376000920191909152506110199250849150839050611597565b6110878787878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a925089918291850190849080828437600092019190915250611e1592505050565b6107618787878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a92508991829185019084908082843760009201919091525061192392505050565b6001600160a01b038181166000908152600360205260409020600201548291163314611136576040516311ca4b2760e31b81523360048201526024016105f6565b6001600160a01b038083166000818152600360205260408082206002810180546001600160a01b031916905560010154905133949190911692917f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d091a4506001600160a01b0316600090815260036020526040902060010180546001600160a01b03191633179055565b6001600160a01b038281166000908152600360205260409020600101548391163314611201576040516311ca4b2760e31b81523360048201526024016105f6565b816001600160a01b0381166112345760405163c369130760e01b81526001600160a01b03821660048201526024016105f6565b6001600160a01b0384811660008181526003602052604080822060020180546001600160a01b0319169488169485179055517f107cf6ea8668d533df1aab5bb8b6315bb0c25f0b6c955558d09368f290668fc79190a350505050565b6000848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208088028281018201909352878252909350879250869182918501908490808284376000920191909152506113039250849150839050611597565b600061137288888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a91829185019084908082843760009201919091525061209c92505050565b905061139d7f00000000000000000000000000000000000000000000000000000000000000006120cf565b6001600160a01b0381166000818152600360205260408082206001810180546001600160a01b031916331790558590555192965090917f8d5f9943c664a3edaf4d3eb18cc5e2c45a7d2dc5869be33d33bbc0fff9bc25909190a2505050949350505050565b61140a6118ca565b63389a75e1600c52806000526020600c20805442111561143257636f5e88186000526004601cfd5b6000905561143f816118e5565b50565b61144a6118ca565b8060601b61146057637448fbae6000526004601cfd5b61143f816118e5565b6001600160a01b0386811660009081526003602052604090206001015487911633146114aa576040516311ca4b2760e31b81523360048201526024016105f6565b8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061151b9250849150839050611597565b611528898888888861174c565b610a4e898989898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b918291850190849080828437600092019190915250611e6592505050565b6002825110156115bf578151604051630e8c626560e41b81526004016105f691815260200190565b80518251146115ee578151815160405163b34f351d60e01b8152600481019290925260248201526044016105f6565b620f42406115fb8261217e565b63ffffffff16146116315761160f8161217e565b60405163fcc487c160e01b815263ffffffff90911660048201526024016105f6565b81516000190160005b818110156116fd5783816001018151811061165757611657612604565b60200260200101516001600160a01b031684828151811061167a5761167a612604565b60200260200101516001600160a01b0316106116ac5760405163ac6bd23360e01b8152600481018290526024016105f6565b600063ffffffff168382815181106116c6576116c6612604565b602002602001015163ffffffff16036116f557604051630db7e4c760e01b8152600481018290526024016105f6565b60010161163a565b50600063ffffffff1682828151811061171857611718612604565b602002602001015163ffffffff160361174757604051630db7e4c760e01b8152600481018290526024016105f6565b505050565b60006117bb8585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061209c92505050565b6001600160a01b0387166000818152600360205260408082208490555192935090917f45e1e99513dd915ac128b94953ca64c6375717ea1894b3114db08cdca51debd29190a2505050505050565b6001600160a01b038116600090815260016020819052604082205461182e9190612747565b6001600160a01b03831660008181526001602081905260409091205590915061185790826121c3565b919050565b6001600160a01b03808216600090815260026020908152604080832093861683529290529081205461189090600190612747565b6001600160a01b038084166000818152600260209081526040808320948916835293905291909120600190559091506107c09084836121e3565b638b78c6d81954331461091f576382b429006000526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000811660008181526002602090815260408083209488168084529482528083205460019092528083205490516370a0823160e01b815260048101959095529193849391929184916370a0823190602401602060405180830381865afa1580156119b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dc91906126ab565b90506001600160a01b0388163181156119f6576001820391505b8315611a03576001840393505b8215611a10576001830392505b8383018201810194508115611aa257604051633e0f9fff60e11b81526001600160a01b037f000000000000000000000000000000000000000000000000000000000000000081166004830152602482018490528a1690637c1f3ffe90604401600060405180830381600087803b158015611a8957600080fd5b505af1158015611a9d573d6000803e3d6000fd5b505050505b8015611b7757604051632ac3affd60e21b8152600481018290526001600160a01b038a169063ab0ebff490602401600060405180830381600087803b158015611aea57600080fd5b505af1158015611afe573d6000803e3d6000fd5b505050507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b5d57600080fd5b505af1158015611b71573d6000803e3d6000fd5b50505050505b8215611bf2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611bd857600080fd5b505af1158015611bec573d6000803e3d6000fd5b50505050505b60005460405163095ea7b360e01b81526001600160a01b039182166004820152602481018790527f00000000000000000000000000000000000000000000000000000000000000009091169063095ea7b3906044016020604051808303816000875af1158015611c66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8a919061275a565b506000546040516322287e0b60e21b8152600481018790526001600160a01b03909116906388a1f82c906024016020604051808303816000875af1158015611cd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfa91906126ab565b885190965060005b81811015611e07576000611d3a898b8481518110611d2257611d22612604565b602002602001015163ffffffff16620f424091020490565b9050611d807f00000000000000000000000000000000000000000000000000000000000000008c8481518110611d7257611d72612604565b60200260200101518361222c565b611dfe576001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660009081526002602052604081208c518392908e9086908110611dd357611dd3612604565b6020908102919091018101516001600160a01b03168252810191909152604001600020805490910190555b50600101611d02565b505050505050509392505050565b6000611e21838361209c565b6001600160a01b0385166000908152600360205260409020549091508114611e5f5760405163dd5ff45760e01b8152600481018290526024016105f6565b50505050565b6001600160a01b038381166000818152600260209081526040808320948916808452949091528082205490516370a0823160e01b815260048101949094529092909183916370a0823190602401602060405180830381865afa158015611ecf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef391906126ab565b90508015611f0057600019015b8115611f0d576001820391505b81810192508115611f42576001600160a01b038087166000908152600260209081526040808320938b16835292905220600190555b856001600160a01b0316876001600160a01b03167f5ce93041411cc768a3969c4b4575a472183e7487eb37987fef9f0044d9a95e2185604051611f8791815260200190565b60405180910390a38015611ff857604051633e0f9fff60e11b81526001600160a01b03878116600483015260248201839052881690637c1f3ffe90604401600060405180830381600087803b158015611fdf57600080fd5b505af1158015611ff3573d6000803e3d6000fd5b505050505b845160005b81811015610a4e57600061201d86888481518110611d2257611d22612604565b905061203589898481518110611d7257611d72612604565b612093576001600160a01b038916600090815260026020526040812089518392908b908690811061206857612068612604565b6020908102919091018101516001600160a01b03168252810191909152604001600020805490910190555b50600101611ffd565b600082826040516020016120b192919061277c565b60405160208183030381529060405280519060200120905092915050565b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528260601b60468201526c5af43d3d93803e605b57fd5bf360981b605a8201526067816000f09150506001600160a01b03811661185757604051630985da9b60e41b815260040160405180910390fd5b8051600090815b818110156121bc5783818151811061219f5761219f612604565b6020026020010151836121b291906127eb565b9250600101612185565b5050919050565b60008060008084865af16121df5763b12d13eb6000526004601cfd5b5050565b81601a5280603a5269a9059cbb00000000000060005260206000604460166000875af13d156001600051141716612222576390b8ec186000526004601cfd5b6000603a52505050565b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390526000919085169063a9059cbb906044016020604051808303816000875af115801561227f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122a3919061275a565b949350505050565b6001600160a01b038116811461143f57600080fd5b6000602082840312156122d257600080fd5b8135610fa1816122ab565b60008083601f8401126122ef57600080fd5b50813567ffffffffffffffff81111561230757600080fd5b6020830191508360208260051b850101111561232257600080fd5b9250929050565b60008060008060006060868803121561234157600080fd5b853561234c816122ab565b9450602086013567ffffffffffffffff8082111561236957600080fd5b61237589838a016122dd565b9096509450604088013591508082111561238e57600080fd5b5061239b888289016122dd565b969995985093965092949392505050565b600080600080606085870312156123c257600080fd5b84356123cd816122ab565b935060208501359250604085013567ffffffffffffffff8111156123f057600080fd5b6123fc878288016122dd565b95989497509550505050565b6000806000806000806080878903121561242157600080fd5b863561242c816122ab565b9550602087013561243c816122ab565b9450604087013567ffffffffffffffff8082111561245957600080fd5b6124658a838b016122dd565b9096509450606089013591508082111561247e57600080fd5b5061248b89828a016122dd565b979a9699509497509295939492505050565b600080602083850312156124b057600080fd5b823567ffffffffffffffff8111156124c757600080fd5b6124d3858286016122dd565b90969095509350505050565b6020808252825182820181905260009190848201906040850190845b818110156125205783516001600160a01b0316835292840192918401916001016124fb565b50909695505050505050565b6000806040838503121561253f57600080fd5b823561254a816122ab565b9150602083013561255a816122ab565b809150509250929050565b6000806000806040858703121561257b57600080fd5b843567ffffffffffffffff8082111561259357600080fd5b61259f888389016122dd565b909650945060208701359150808211156125b857600080fd5b506123fc878288016122dd565b634e487b7160e01b600052601160045260246000fd5b808201808211156107c0576107c06125c5565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b84815260606020808301829052908201849052600090859060808401835b8781101561266657833561264b816122ab565b6001600160a01b031682529282019290820190600101612638565b508481036040860152855180825290820192508186019060005b8181101561269c57825185529383019391830191600101612680565b50929998505050505050505050565b6000602082840312156126bd57600080fd5b5051919050565b60008235603e198336030181126126da57600080fd5b9190910192915050565b6000808335601e198436030181126126fb57600080fd5b83018035915067ffffffffffffffff82111561271657600080fd5b6020019150600581901b360382131561232257600080fd5b600060018201612740576127406125c5565b5060010190565b818103818111156107c0576107c06125c5565b60006020828403121561276c57600080fd5b81518015158114610fa157600080fd5b825160009082906020808701845b838110156127af5781516001600160a01b03168552938201939082019060010161278a565b5050855181870193925060005b818110156127de57845163ffffffff16845293820193928201926001016127bc565b5091979650505050505050565b63ffffffff818116838216019080821115612808576128086125c5565b509291505056fea164736f6c6343000812000a60a060405234801561001057600080fd5b503360805260805161027261004a60003960008181604b0152818160bc015281816101080152818161013c015261018601526102726000f3fe6080604052600436106100345760003560e01c80630e769b2b146100395780637c1f3ffe14610089578063ab0ebff41461009e575b600080fd5b34801561004557600080fd5b5061006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009c610097366004610214565b6100b1565b005b61009c6100ac36600461024c565b610131565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100f9576040516282b42960e81b815260040160405180910390fd5b61012d6001600160a01b0383167f0000000000000000000000000000000000000000000000000000000000000000836101af565b5050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610179576040516282b42960e81b815260040160405180910390fd5b6101ac6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016826101f8565b50565b81601a5280603a5269a9059cbb00000000000060005260206000604460166000875af13d1560016000511417166101ee576390b8ec186000526004601cfd5b6000603a52505050565b60008060008084865af161012d5763b12d13eb6000526004601cfd5b6000806040838503121561022757600080fd5b82356001600160a01b038116811461023e57600080fd5b946020939093013593505050565b60006020828403121561025e57600080fd5b503591905056fea164736f6c6343000812000a000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000e386b025180dc6c0459c7f74476150e8c93e9843
Deployed Bytecode
0x6080604052600436106101c65760003560e01c806389a30271116100f7578063c7de644011610095578063f04e283e11610064578063f04e283e14610540578063f2fde38b14610553578063f76decfe14610566578063fee81cf41461058657600080fd5b8063c7de6440146104c2578063d0e4b2f4146104e2578063d7533f0214610502578063e40dcfe31461052057600080fd5b80639ffab000116100d15780639ffab00014610435578063afaed66314610455578063c3a8962c14610482578063c458f5ed146104a257600080fd5b806389a30271146103c85780638da5cb5b146103fc57806394e6fd601461041557600080fd5b806354d1f13d116101645780638117abc11161013e5780638117abc1146103185780638119c0651461034c57806388c662aa1461036c57806389063570146103a857600080fd5b806354d1f13d146102e85780636e5f6919146102f0578063715018a61461031057600080fd5b806329701c3f116101a057806329701c3f146102455780633bb66a7b146102655780633f26479e146102855780634aa4a4fc1461029c57600080fd5b80631267c6da146101d25780631da0b8fc146101f4578063256929621461023d57600080fd5b366101cd57005b600080fd5b3480156101de57600080fd5b506101f26101ed3660046122c0565b6105b9565b005b34801561020057600080fd5b5061022a61020f3660046122c0565b6001600160a01b031660009081526003602052604090205490565b6040519081526020015b60405180910390f35b6101f2610652565b34801561025157600080fd5b506101f2610260366004612329565b6106a2565b34801561027157600080fd5b5061022a6102803660046122c0565b61076b565b34801561029157600080fd5b5061022a620f424081565b3480156102a857600080fd5b506102d07f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281565b6040516001600160a01b039091168152602001610234565b6101f26107c6565b3480156102fc57600080fd5b506101f261030b3660046123ac565b610802565b6101f261090d565b34801561032457600080fd5b506102d07f000000000000000000000000ac1365ac74c8f38d4a0184744da8cef18299602581565b34801561035857600080fd5b506000546102d0906001600160a01b031681565b34801561037857600080fd5b506102d06103873660046122c0565b6001600160a01b039081166000908152600360205260409020600101541690565b3480156103b457600080fd5b506101f26103c3366004612329565b610921565b3480156103d457600080fd5b506102d07f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4881565b34801561040857600080fd5b50638b78c6d819546102d0565b34801561042157600080fd5b506101f26104303660046122c0565b610a59565b34801561044157600080fd5b506101f2610450366004612408565b610a83565b34801561046157600080fd5b5061047561047036600461249d565b610de7565b60405161023491906124df565b34801561048e57600080fd5b5061022a61049d36600461252c565b610ee1565b3480156104ae57600080fd5b506101f26104bd366004612329565b610fa8565b3480156104ce57600080fd5b506101f26104dd3660046122c0565b6110f5565b3480156104ee57600080fd5b506101f26104fd36600461252c565b6111c0565b34801561050e57600080fd5b506040516202a3008152602001610234565b34801561052c57600080fd5b506102d061053b366004612565565b611290565b6101f261054e3660046122c0565b611402565b6101f26105613660046122c0565b611442565b34801561057257600080fd5b506101f2610581366004612408565b611469565b34801561059257600080fd5b5061022a6105a13660046122c0565b63389a75e1600c908152600091909152602090205490565b6001600160a01b0381811660009081526003602052604090206001015482911633146105ff576040516311ca4b2760e31b81523360048201526024015b60405180910390fd5b6001600160a01b03821660008181526003602052604080822060020180546001600160a01b0319169055517f6c2460a415b84be3720c209fe02f2cad7a6bcba21e8637afe8957b7ec4b6ef879190a25050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b6001600160a01b0385811660009081526003602052604090206001015486911633146106e3576040516311ca4b2760e31b81523360048201526024016105f6565b848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208088028281018201909352878252909350879250869182918501908490808284376000920191909152506107549250849150839050611597565b610761888888888861174c565b5050505050505050565b6001600160a01b038116600090815260036020526040812054810361079157600061079d565b816001600160a01b0316315b6001600160a01b0383166000908152600160205260409020546107c091906125db565b92915050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b60008167ffffffffffffffff81111561081d5761081d6125ee565b604051908082528060200260200182016040528015610846578160200160208202803683370190505b5090506000841561085d5761085a86611809565b90505b60005b838110156108bd576108988786868481811061087e5761087e612604565b905060200201602081019061089391906122c0565b61185c565b8382815181106108aa576108aa612604565b6020908102919091010152600101610860565b50856001600160a01b03167fa9e30bf144f83390a4fe47562a4e16892108102221c674ff538da0b72a83d174828686866040516108fd949392919061261a565b60405180910390a2505050505050565b6109156118ca565b61091f60006118e5565b565b6001600160a01b038581166000908152600360205260409020600101548691163314610962576040516311ca4b2760e31b81523360048201526024016105f6565b848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208088028281018201909352878252909350879250869182918501908490808284376000920191909152506109d39250849150839050611597565b6109e0888888888861174c565b610a4e8888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a91829185019084908082843760009201919091525061192392505050565b505050505050505050565b610a616118ca565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b83838080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808702828101820190935286825290935086925085918291850190849080828437600092019190915250610af49250849150839050611597565b610b628887878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a925089918291850190849080828437600092019190915250611e1592505050565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316876001600160a01b031603610c0f57610c0a888888888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a918291850190849080828437600092019190915250611e6592505050565b610761565b7f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b0316876001600160a01b031603610cbc57610cb68887878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a92508991829185019084908082843760009201919091525061192392505050565b50610761565b6040516370a0823160e01b81526001600160a01b038981166004830152600091908916906370a0823190602401602060405180830381865afa158015610d06573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d2a91906126ab565b604051633e0f9fff60e11b81526001600160a01b038a8116600483015260248201839052919250908a1690637c1f3ffe90604401600060405180830381600087803b158015610d7857600080fd5b505af1158015610d8c573d6000803e3d6000fd5b505050506001600160a01b0388811660009081526002602090815260408083208d85168452600383528184206001015490941683529290529081208054839290610dd79084906125db565b9091555050505050505050505050565b6060818067ffffffffffffffff811115610e0357610e036125ee565b604051908082528060200260200182016040528015610e2c578160200160208202803683370190505b50915060005b81811015610ed957610e9d858583818110610e4f57610e4f612604565b9050602002810190610e6191906126c4565b610e6b90806126e4565b878785818110610e7d57610e7d612604565b9050602002810190610e8f91906126c4565b61053b9060208101906126e4565b838281518110610eaf57610eaf612604565b6001600160a01b039092166020928302919091019091015280610ed18161272e565b915050610e32565b505092915050565b6001600160a01b0382166000908152600360205260408120548103610f07576000610f71565b6040516370a0823160e01b81526001600160a01b0384811660048301528316906370a0823190602401602060405180830381865afa158015610f4d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f7191906126ab565b6001600160a01b03808416600090815260026020908152604080832093881683529290522054610fa191906125db565b9392505050565b838380806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208087028281018201909352868252909350869250859182918501908490808284376000920191909152506110199250849150839050611597565b6110878787878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a925089918291850190849080828437600092019190915250611e1592505050565b6107618787878080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808b0282810182019093528a82529093508a92508991829185019084908082843760009201919091525061192392505050565b6001600160a01b038181166000908152600360205260409020600201548291163314611136576040516311ca4b2760e31b81523360048201526024016105f6565b6001600160a01b038083166000818152600360205260408082206002810180546001600160a01b031916905560010154905133949190911692917f943d69cf2bbe08a9d44b3c4ce6da17d939d758739370620871ce99a6437866d091a4506001600160a01b0316600090815260036020526040902060010180546001600160a01b03191633179055565b6001600160a01b038281166000908152600360205260409020600101548391163314611201576040516311ca4b2760e31b81523360048201526024016105f6565b816001600160a01b0381166112345760405163c369130760e01b81526001600160a01b03821660048201526024016105f6565b6001600160a01b0384811660008181526003602052604080822060020180546001600160a01b0319169488169485179055517f107cf6ea8668d533df1aab5bb8b6315bb0c25f0b6c955558d09368f290668fc79190a350505050565b6000848480806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250506040805160208088028281018201909352878252909350879250869182918501908490808284376000920191909152506113039250849150839050611597565b600061137288888080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808c0282810182019093528b82529093508b92508a91829185019084908082843760009201919091525061209c92505050565b905061139d7f000000000000000000000000ac1365ac74c8f38d4a0184744da8cef1829960256120cf565b6001600160a01b0381166000818152600360205260408082206001810180546001600160a01b031916331790558590555192965090917f8d5f9943c664a3edaf4d3eb18cc5e2c45a7d2dc5869be33d33bbc0fff9bc25909190a2505050949350505050565b61140a6118ca565b63389a75e1600c52806000526020600c20805442111561143257636f5e88186000526004601cfd5b6000905561143f816118e5565b50565b61144a6118ca565b8060601b61146057637448fbae6000526004601cfd5b61143f816118e5565b6001600160a01b0386811660009081526003602052604090206001015487911633146114aa576040516311ca4b2760e31b81523360048201526024016105f6565b8484808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080880282810182019093528782529093508792508691829185019084908082843760009201919091525061151b9250849150839050611597565b611528898888888861174c565b610a4e898989898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b918291850190849080828437600092019190915250611e6592505050565b6002825110156115bf578151604051630e8c626560e41b81526004016105f691815260200190565b80518251146115ee578151815160405163b34f351d60e01b8152600481019290925260248201526044016105f6565b620f42406115fb8261217e565b63ffffffff16146116315761160f8161217e565b60405163fcc487c160e01b815263ffffffff90911660048201526024016105f6565b81516000190160005b818110156116fd5783816001018151811061165757611657612604565b60200260200101516001600160a01b031684828151811061167a5761167a612604565b60200260200101516001600160a01b0316106116ac5760405163ac6bd23360e01b8152600481018290526024016105f6565b600063ffffffff168382815181106116c6576116c6612604565b602002602001015163ffffffff16036116f557604051630db7e4c760e01b8152600481018290526024016105f6565b60010161163a565b50600063ffffffff1682828151811061171857611718612604565b602002602001015163ffffffff160361174757604051630db7e4c760e01b8152600481018290526024016105f6565b505050565b60006117bb8585808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152505060408051602080890282810182019093528882529093508892508791829185019084908082843760009201919091525061209c92505050565b6001600160a01b0387166000818152600360205260408082208490555192935090917f45e1e99513dd915ac128b94953ca64c6375717ea1894b3114db08cdca51debd29190a2505050505050565b6001600160a01b038116600090815260016020819052604082205461182e9190612747565b6001600160a01b03831660008181526001602081905260409091205590915061185790826121c3565b919050565b6001600160a01b03808216600090815260026020908152604080832093861683529290529081205461189090600190612747565b6001600160a01b038084166000818152600260209081526040808320948916835293905291909120600190559091506107c09084836121e3565b638b78c6d81954331461091f576382b429006000526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2811660008181526002602090815260408083209488168084529482528083205460019092528083205490516370a0823160e01b815260048101959095529193849391929184916370a0823190602401602060405180830381865afa1580156119b8573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119dc91906126ab565b90506001600160a01b0388163181156119f6576001820391505b8315611a03576001840393505b8215611a10576001830392505b8383018201810194508115611aa257604051633e0f9fff60e11b81526001600160a01b037f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc281166004830152602482018490528a1690637c1f3ffe90604401600060405180830381600087803b158015611a8957600080fd5b505af1158015611a9d573d6000803e3d6000fd5b505050505b8015611b7757604051632ac3affd60e21b8152600481018290526001600160a01b038a169063ab0ebff490602401600060405180830381600087803b158015611aea57600080fd5b505af1158015611afe573d6000803e3d6000fd5b505050507f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015611b5d57600080fd5b505af1158015611b71573d6000803e3d6000fd5b50505050505b8215611bf2577f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc26001600160a01b031663d0e30db0846040518263ffffffff1660e01b81526004016000604051808303818588803b158015611bd857600080fd5b505af1158015611bec573d6000803e3d6000fd5b50505050505b60005460405163095ea7b360e01b81526001600160a01b039182166004820152602481018790527f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc29091169063095ea7b3906044016020604051808303816000875af1158015611c66573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c8a919061275a565b506000546040516322287e0b60e21b8152600481018790526001600160a01b03909116906388a1f82c906024016020604051808303816000875af1158015611cd6573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cfa91906126ab565b885190965060005b81811015611e07576000611d3a898b8481518110611d2257611d22612604565b602002602001015163ffffffff16620f424091020490565b9050611d807f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb488c8481518110611d7257611d72612604565b60200260200101518361222c565b611dfe576001600160a01b037f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb481660009081526002602052604081208c518392908e9086908110611dd357611dd3612604565b6020908102919091018101516001600160a01b03168252810191909152604001600020805490910190555b50600101611d02565b505050505050509392505050565b6000611e21838361209c565b6001600160a01b0385166000908152600360205260409020549091508114611e5f5760405163dd5ff45760e01b8152600481018290526024016105f6565b50505050565b6001600160a01b038381166000818152600260209081526040808320948916808452949091528082205490516370a0823160e01b815260048101949094529092909183916370a0823190602401602060405180830381865afa158015611ecf573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ef391906126ab565b90508015611f0057600019015b8115611f0d576001820391505b81810192508115611f42576001600160a01b038087166000908152600260209081526040808320938b16835292905220600190555b856001600160a01b0316876001600160a01b03167f5ce93041411cc768a3969c4b4575a472183e7487eb37987fef9f0044d9a95e2185604051611f8791815260200190565b60405180910390a38015611ff857604051633e0f9fff60e11b81526001600160a01b03878116600483015260248201839052881690637c1f3ffe90604401600060405180830381600087803b158015611fdf57600080fd5b505af1158015611ff3573d6000803e3d6000fd5b505050505b845160005b81811015610a4e57600061201d86888481518110611d2257611d22612604565b905061203589898481518110611d7257611d72612604565b612093576001600160a01b038916600090815260026020526040812089518392908b908690811061206857612068612604565b6020908102919091018101516001600160a01b03168252810191909152604001600020805490910190555b50600101611ffd565b600082826040516020016120b192919061277c565b60405160208183030381529060405280519060200120905092915050565b6000604051723d605d80600a3d3981f336603057343d52307f60681b81527f830d2d700a97af574b186c80d40429385d24241565b08a7c559ba283a964d9b160138201527260203da23d3df35b3d3d3d3d363d3d37363d7360681b60338201528260601b60468201526c5af43d3d93803e605b57fd5bf360981b605a8201526067816000f09150506001600160a01b03811661185757604051630985da9b60e41b815260040160405180910390fd5b8051600090815b818110156121bc5783818151811061219f5761219f612604565b6020026020010151836121b291906127eb565b9250600101612185565b5050919050565b60008060008084865af16121df5763b12d13eb6000526004601cfd5b5050565b81601a5280603a5269a9059cbb00000000000060005260206000604460166000875af13d156001600051141716612222576390b8ec186000526004601cfd5b6000603a52505050565b60405163a9059cbb60e01b81526001600160a01b038381166004830152602482018390526000919085169063a9059cbb906044016020604051808303816000875af115801561227f573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122a3919061275a565b949350505050565b6001600160a01b038116811461143f57600080fd5b6000602082840312156122d257600080fd5b8135610fa1816122ab565b60008083601f8401126122ef57600080fd5b50813567ffffffffffffffff81111561230757600080fd5b6020830191508360208260051b850101111561232257600080fd5b9250929050565b60008060008060006060868803121561234157600080fd5b853561234c816122ab565b9450602086013567ffffffffffffffff8082111561236957600080fd5b61237589838a016122dd565b9096509450604088013591508082111561238e57600080fd5b5061239b888289016122dd565b969995985093965092949392505050565b600080600080606085870312156123c257600080fd5b84356123cd816122ab565b935060208501359250604085013567ffffffffffffffff8111156123f057600080fd5b6123fc878288016122dd565b95989497509550505050565b6000806000806000806080878903121561242157600080fd5b863561242c816122ab565b9550602087013561243c816122ab565b9450604087013567ffffffffffffffff8082111561245957600080fd5b6124658a838b016122dd565b9096509450606089013591508082111561247e57600080fd5b5061248b89828a016122dd565b979a9699509497509295939492505050565b600080602083850312156124b057600080fd5b823567ffffffffffffffff8111156124c757600080fd5b6124d3858286016122dd565b90969095509350505050565b6020808252825182820181905260009190848201906040850190845b818110156125205783516001600160a01b0316835292840192918401916001016124fb565b50909695505050505050565b6000806040838503121561253f57600080fd5b823561254a816122ab565b9150602083013561255a816122ab565b809150509250929050565b6000806000806040858703121561257b57600080fd5b843567ffffffffffffffff8082111561259357600080fd5b61259f888389016122dd565b909650945060208701359150808211156125b857600080fd5b506123fc878288016122dd565b634e487b7160e01b600052601160045260246000fd5b808201808211156107c0576107c06125c5565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b84815260606020808301829052908201849052600090859060808401835b8781101561266657833561264b816122ab565b6001600160a01b031682529282019290820190600101612638565b508481036040860152855180825290820192508186019060005b8181101561269c57825185529383019391830191600101612680565b50929998505050505050505050565b6000602082840312156126bd57600080fd5b5051919050565b60008235603e198336030181126126da57600080fd5b9190910192915050565b6000808335601e198436030181126126fb57600080fd5b83018035915067ffffffffffffffff82111561271657600080fd5b6020019150600581901b360382131561232257600080fd5b600060018201612740576127406125c5565b5060010190565b818103818111156107c0576107c06125c5565b60006020828403121561276c57600080fd5b81518015158114610fa157600080fd5b825160009082906020808701845b838110156127af5781516001600160a01b03168552938201939082019060010161278a565b5050855181870193925060005b818110156127de57845163ffffffff16845293820193928201926001016127bc565b5091979650505050505050565b63ffffffff818116838216019080821115612808576128086125c5565b509291505056fea164736f6c6343000812000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000e386b025180dc6c0459c7f74476150e8c93e9843
-----Decoded View---------------
Arg [0] : _weth (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [1] : _usdc (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [2] : _swap (address): 0xE386B025180dc6c0459C7F74476150e8C93e9843
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [1] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [2] : 000000000000000000000000e386b025180dc6c0459c7f74476150e8c93e9843
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 30 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.