creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
      },
      "contracts/ArchetypePayouts.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// ArchetypePayouts v0.7.0\n//\n//        d8888                 888               888\n//       d88888                 888               888\n//      d88P888                 888               888\n//     d88P 888 888d888 .d8888b 88888b.   .d88b.  888888 888  888 88888b.   .d88b.\n//    d88P  888 888P\"  d88P\"    888 \"88b d8P  Y8b 888    888  888 888 \"88b d8P  Y8b\n//   d88P   888 888    888      888  888 88888888 888    888  888 888  888 88888888\n//  d8888888888 888    Y88b.    888  888 Y8b.     Y88b.  Y88b 888 888 d88P Y8b.\n// d88P     888 888     \"Y8888P 888  888  \"Y8888   \"Y888  \"Y88888 88888P\"   \"Y8888\n//                                                            888 888\n//                                                       Y8b d88P 888\n//\n\npragma solidity ^0.8.4;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\nerror InvalidLength();\nerror InvalidSplitShares();\nerror TransferFailed();\nerror BalanceEmpty();\nerror NotApprovedToWithdraw();\n\ncontract ArchetypePayouts {\n  event Withdrawal(address indexed src, address token, uint256 wad);\n  event FundsAdded(address indexed recipient, address token, uint256 amount);\n\n  mapping(address => mapping(address => uint256)) private _balance;\n  mapping(address => mapping(address => bool)) private _approvals;\n\n  function updateBalances(\n    uint256 totalAmount,\n    address token,\n    address[] calldata recipients,\n    uint16[] calldata splits\n  ) public payable {\n    if (recipients.length != splits.length) {\n      revert InvalidLength();\n    }\n\n    uint256 totalShares = 0;\n    for (uint256 i = 0; i < splits.length; i++) {\n      totalShares += splits[i];\n    }\n    if (totalShares != 10000) {\n      revert InvalidSplitShares();\n    }\n\n    if (token == address(0)) {\n      // ETH payments\n      uint256 totalReceived = msg.value;\n      for (uint256 i = 0; i < recipients.length; i++) {\n        if (splits[i] > 0) {\n          uint256 amountToAdd = (totalReceived * splits[i]) / 10000;\n          _balance[recipients[i]][token] += amountToAdd;\n          emit FundsAdded(recipients[i], token, amountToAdd);\n        }\n      }\n    } else {\n      // ERC20 payments\n      IERC20 paymentToken = IERC20(token);\n      bool success = paymentToken.transferFrom(msg.sender, address(this), totalAmount);\n      if (!success) {\n        revert TransferFailed();\n      }\n\n      for (uint256 i = 0; i < recipients.length; i++) {\n        if (splits[i] > 0) {\n          uint256 amountToAdd = (totalAmount * splits[i]) / 10000;\n          _balance[recipients[i]][token] += amountToAdd;\n          emit FundsAdded(recipients[i], token, amountToAdd);\n        }\n      }\n    }\n  }\n\n  function withdraw() external {\n    address msgSender = msg.sender;\n    _withdraw(msgSender, msgSender, address(0));\n  }\n\n  function withdrawTokens(address[] memory tokens) external {\n    address msgSender = msg.sender;\n\n    for (uint256 i = 0; i < tokens.length; i++) {\n      _withdraw(msgSender, msgSender, tokens[i]);\n    }\n  }\n\n  function withdrawFrom(address from, address to) public {\n    if (from != msg.sender && !_approvals[from][to]) {\n      revert NotApprovedToWithdraw();\n    }\n    _withdraw(from, to, address(0));\n  }\n\n  function withdrawTokensFrom(\n    address from,\n    address to,\n    address[] memory tokens\n  ) public {\n    if (from != msg.sender && !_approvals[from][to]) {\n      revert NotApprovedToWithdraw();\n    }\n    for (uint256 i = 0; i < tokens.length; i++) {\n      _withdraw(from, to, tokens[i]);\n    }\n  }\n\n  function _withdraw(\n    address from,\n    address to,\n    address token\n  ) internal {\n    uint256 wad;\n\n    wad = _balance[from][token];\n    _balance[from][token] = 0;\n\n    if (wad == 0) {\n      revert BalanceEmpty();\n    }\n\n    if (token == address(0)) {\n      bool success = false;\n      (success, ) = to.call{ value: wad }(\"\");\n      if (!success) {\n        revert TransferFailed();\n      }\n    } else {\n      IERC20 erc20Token = IERC20(token);\n      bool success = erc20Token.transfer(to, wad);\n      if (!success) {\n        revert TransferFailed();\n      }\n    }\n    emit Withdrawal(from, token, wad);\n  }\n\n  function approveWithdrawal(address delegate, bool approved) external {\n    _approvals[msg.sender][delegate] = approved;\n  }\n\n  function isApproved(address from, address delegate) external view returns (bool) {\n    return _approvals[from][delegate];\n  }\n\n  function balance(address recipient) external view returns (uint256) {\n    return _balance[recipient][address(0)];\n  }\n\n  function balanceToken(address recipient, address token) external view returns (uint256) {\n    return _balance[recipient][token];\n  }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}