/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/interfaces/IERC1967.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC1967.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.0;
  5 |     | 
  6 |     | /**
  7 |     |  * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC.
  8 |     |  *
  9 |     |  * _Available since v4.8.3._
 10 |     |  */
 11 |     | interface IERC1967 {
 12 |     |     /**
 13 |     |      * @dev Emitted when the implementation is upgraded.
 14 |     |      */
 15 |     |     event Upgraded(address indexed implementation);
 16 |     | 
 17 |     |     /**
 18 |     |      * @dev Emitted when the admin account has changed.
 19 |     |      */
 20 |     |     event AdminChanged(address previousAdmin, address newAdmin);
 21 |     | 
 22 |     |     /**
 23 |     |      * @dev Emitted when the beacon is changed.
 24 |     |      */
 25 |     |     event BeaconUpgraded(address indexed beacon);
 26 |     | }
 27 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/interfaces/draft-IERC1822.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.0;
  5 |     | 
  6 |     | /**
  7 |     |  * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
  8 |     |  * proxy whose upgrades are fully controlled by the current implementation.
  9 |     |  */
 10 |     | interface IERC1822Proxiable {
 11 |     |     /**
 12 |     |      * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
 13 |     |      * address.
 14 |     |      *
 15 |     |      * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
 16 |     |      * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
 17 |     |      * function revert if invoked through a proxy.
 18 |     |      */
 19 |     |     function proxiableUUID() external view returns (bytes32);
 20 |     | }
 21 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/metatx/ERC2771Context.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts (last updated v4.7.0) (metatx/ERC2771Context.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.9;
  5 |     | 
  6 |     | import "../utils/Context.sol";
  7 |     | 
  8 |     | /**
  9 |     |  * @dev Context variant with ERC2771 support.
 10 |     |  */
 11 |     | abstract contract ERC2771Context is Context {
 12 |     |     /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
 13 |     |     address private immutable _trustedForwarder;
 14 |     | 
 15 |     |     /// @custom:oz-upgrades-unsafe-allow constructor
 16 | *   |     constructor(address trustedForwarder) {
 17 | *   |         _trustedForwarder = trustedForwarder;
 18 |     |     }
 19 |     | 
 20 | *   |     function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
 21 | *   |         return forwarder == _trustedForwarder;
 22 |     |     }
 23 |     | 
 24 | *   |     function _msgSender() internal view virtual override returns (address sender) {
 25 | *   |         if (isTrustedForwarder(msg.sender)) {
 26 |     |             // The assembly code is more direct than the Solidity version using `abi.decode`.
 27 |     |             /// @solidity memory-safe-assembly
 28 |     |             assembly {
 29 |     |                 sender := shr(96, calldataload(sub(calldatasize(), 20)))
 30 |     |             }
 31 |     |         } else {
 32 | *   |             return super._msgSender();
 33 |     |         }
 34 |     |     }
 35 |     | 
 36 |     |     function _msgData() internal view virtual override returns (bytes calldata) {
 37 |     |         if (isTrustedForwarder(msg.sender)) {
 38 |     |             return msg.data[:msg.data.length - 20];
 39 |     |         } else {
 40 |     |             return super._msgData();
 41 |     |         }
 42 |     |     }
 43 |     | }
 44 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts (last updated v4.7.0) (proxy/ERC1967/ERC1967Proxy.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.0;
  5 |     | 
  6 |     | import "../Proxy.sol";
  7 |     | import "./ERC1967Upgrade.sol";
  8 |     | 
  9 |     | /**
 10 |     |  * @dev This contract implements an upgradeable proxy. It is upgradeable because calls are delegated to an
 11 |     |  * implementation address that can be changed. This address is stored in storage in the location specified by
 12 |     |  * https://eips.ethereum.org/EIPS/eip-1967[EIP1967], so that it doesn't conflict with the storage layout of the
 13 |     |  * implementation behind the proxy.
 14 |     |  */
 15 |     | contract ERC1967Proxy is Proxy, ERC1967Upgrade {
 16 |     |     /**
 17 |     |      * @dev Initializes the upgradeable proxy with an initial implementation specified by `_logic`.
 18 |     |      *
 19 |     |      * If `_data` is nonempty, it's used as data in a delegate call to `_logic`. This will typically be an encoded
 20 |     |      * function call, and allows initializing the storage of the proxy like a Solidity constructor.
 21 |     |      */
 22 |     |     constructor(address _logic, bytes memory _data) payable {
 23 |     |         _upgradeToAndCall(_logic, _data, false);
 24 |     |     }
 25 |     | 
 26 |     |     /**
 27 |     |      * @dev Returns the current implementation address.
 28 |     |      */
 29 |     |     function _implementation() internal view virtual override returns (address impl) {
 30 |     |         return ERC1967Upgrade._getImplementation();
 31 |     |     }
 32 |     | }
 33 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Upgrade.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (proxy/ERC1967/ERC1967Upgrade.sol)
   3 |     | 
   4 |     | pragma solidity ^0.8.2;
   5 |     | 
   6 |     | import "../beacon/IBeacon.sol";
   7 |     | import "../../interfaces/IERC1967.sol";
   8 |     | import "../../interfaces/draft-IERC1822.sol";
   9 |     | import "../../utils/Address.sol";
  10 |     | import "../../utils/StorageSlot.sol";
  11 |     | 
  12 |     | /**
  13 |     |  * @dev This abstract contract provides getters and event emitting update functions for
  14 |     |  * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
  15 |     |  *
  16 |     |  * _Available since v4.1._
  17 |     |  */
  18 |     | abstract contract ERC1967Upgrade is IERC1967 {
  19 |     |     // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
  20 |     |     bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
  21 |     | 
  22 |     |     /**
  23 |     |      * @dev Storage slot with the address of the current implementation.
  24 |     |      * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
  25 |     |      * validated in the constructor.
  26 |     |      */
  27 |     |     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
  28 |     | 
  29 |     |     /**
  30 |     |      * @dev Returns the current implementation address.
  31 |     |      */
  32 |     |     function _getImplementation() internal view returns (address) {
  33 |     |         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
  34 |     |     }
  35 |     | 
  36 |     |     /**
  37 |     |      * @dev Stores a new address in the EIP1967 implementation slot.
  38 |     |      */
  39 |     |     function _setImplementation(address newImplementation) private {
  40 |     |         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
  41 |     |         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
  42 |     |     }
  43 |     | 
  44 |     |     /**
  45 |     |      * @dev Perform implementation upgrade
  46 |     |      *
  47 |     |      * Emits an {Upgraded} event.
  48 |     |      */
  49 |     |     function _upgradeTo(address newImplementation) internal {
  50 |     |         _setImplementation(newImplementation);
  51 |     |         emit Upgraded(newImplementation);
  52 |     |     }
  53 |     | 
  54 |     |     /**
  55 |     |      * @dev Perform implementation upgrade with additional setup call.
  56 |     |      *
  57 |     |      * Emits an {Upgraded} event.
  58 |     |      */
  59 |     |     function _upgradeToAndCall(address newImplementation, bytes memory data, bool forceCall) internal {
  60 |     |         _upgradeTo(newImplementation);
  61 |     |         if (data.length > 0 || forceCall) {
  62 |     |             Address.functionDelegateCall(newImplementation, data);
  63 |     |         }
  64 |     |     }
  65 |     | 
  66 |     |     /**
  67 |     |      * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
  68 |     |      *
  69 |     |      * Emits an {Upgraded} event.
  70 |     |      */
  71 |     |     function _upgradeToAndCallUUPS(address newImplementation, bytes memory data, bool forceCall) internal {
  72 |     |         // Upgrades from old implementations will perform a rollback test. This test requires the new
  73 |     |         // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
  74 |     |         // this special case will break upgrade paths from old UUPS implementation to new ones.
  75 |     |         if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
  76 |     |             _setImplementation(newImplementation);
  77 |     |         } else {
  78 |     |             try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
  79 |     |                 require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
  80 |     |             } catch {
  81 |     |                 revert("ERC1967Upgrade: new implementation is not UUPS");
  82 |     |             }
  83 |     |             _upgradeToAndCall(newImplementation, data, forceCall);
  84 |     |         }
  85 |     |     }
  86 |     | 
  87 |     |     /**
  88 |     |      * @dev Storage slot with the admin of the contract.
  89 |     |      * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
  90 |     |      * validated in the constructor.
  91 |     |      */
  92 |     |     bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
  93 |     | 
  94 |     |     /**
  95 |     |      * @dev Returns the current admin.
  96 |     |      */
  97 |     |     function _getAdmin() internal view returns (address) {
  98 |     |         return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
  99 |     |     }
 100 |     | 
 101 |     |     /**
 102 |     |      * @dev Stores a new address in the EIP1967 admin slot.
 103 |     |      */
 104 |     |     function _setAdmin(address newAdmin) private {
 105 |     |         require(newAdmin != address(0), "ERC1967: new admin is the zero address");
 106 |     |         StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
 107 |     |     }
 108 |     | 
 109 |     |     /**
 110 |     |      * @dev Changes the admin of the proxy.
 111 |     |      *
 112 |     |      * Emits an {AdminChanged} event.
 113 |     |      */
 114 |     |     function _changeAdmin(address newAdmin) internal {
 115 |     |         emit AdminChanged(_getAdmin(), newAdmin);
 116 |     |         _setAdmin(newAdmin);
 117 |     |     }
 118 |     | 
 119 |     |     /**
 120 |     |      * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
 121 |     |      * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
 122 |     |      */
 123 |     |     bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
 124 |     | 
 125 |     |     /**
 126 |     |      * @dev Returns the current beacon.
 127 |     |      */
 128 |     |     function _getBeacon() internal view returns (address) {
 129 |     |         return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
 130 |     |     }
 131 |     | 
 132 |     |     /**
 133 |     |      * @dev Stores a new beacon in the EIP1967 beacon slot.
 134 |     |      */
 135 |     |     function _setBeacon(address newBeacon) private {
 136 |     |         require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
 137 |     |         require(
 138 |     |             Address.isContract(IBeacon(newBeacon).implementation()),
 139 |     |             "ERC1967: beacon implementation is not a contract"
 140 |     |         );
 141 |     |         StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
 142 |     |     }
 143 |     | 
 144 |     |     /**
 145 |     |      * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
 146 |     |      * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
 147 |     |      *
 148 |     |      * Emits a {BeaconUpgraded} event.
 149 |     |      */
 150 |     |     function _upgradeBeaconToAndCall(address newBeacon, bytes memory data, bool forceCall) internal {
 151 |     |         _setBeacon(newBeacon);
 152 |     |         emit BeaconUpgraded(newBeacon);
 153 |     |         if (data.length > 0 || forceCall) {
 154 |     |             Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
 155 |     |         }
 156 |     |     }
 157 |     | }
 158 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/proxy/Proxy.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts (last updated v4.6.0) (proxy/Proxy.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.0;
  5 |     | 
  6 |     | /**
  7 |     |  * @dev This abstract contract provides a fallback function that delegates all calls to another contract using the EVM
  8 |     |  * instruction `delegatecall`. We refer to the second contract as the _implementation_ behind the proxy, and it has to
  9 |     |  * be specified by overriding the virtual {_implementation} function.
 10 |     |  *
 11 |     |  * Additionally, delegation to the implementation can be triggered manually through the {_fallback} function, or to a
 12 |     |  * different contract through the {_delegate} function.
 13 |     |  *
 14 |     |  * The success and return data of the delegated call will be returned back to the caller of the proxy.
 15 |     |  */
 16 |     | abstract contract Proxy {
 17 |     |     /**
 18 |     |      * @dev Delegates the current call to `implementation`.
 19 |     |      *
 20 |     |      * This function does not return to its internal call site, it will return directly to the external caller.
 21 |     |      */
 22 |     |     function _delegate(address implementation) internal virtual {
 23 |     |         assembly {
 24 |     |             // Copy msg.data. We take full control of memory in this inline assembly
 25 |     |             // block because it will not return to Solidity code. We overwrite the
 26 |     |             // Solidity scratch pad at memory position 0.
 27 |     |             calldatacopy(0, 0, calldatasize())
 28 |     | 
 29 |     |             // Call the implementation.
 30 |     |             // out and outsize are 0 because we don't know the size yet.
 31 |     |             let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
 32 |     | 
 33 |     |             // Copy the returned data.
 34 |     |             returndatacopy(0, 0, returndatasize())
 35 |     | 
 36 |     |             switch result
 37 |     |             // delegatecall returns 0 on error.
 38 |     |             case 0 {
 39 |     |                 revert(0, returndatasize())
 40 |     |             }
 41 |     |             default {
 42 |     |                 return(0, returndatasize())
 43 |     |             }
 44 |     |         }
 45 |     |     }
 46 |     | 
 47 |     |     /**
 48 |     |      * @dev This is a virtual function that should be overridden so it returns the address to which the fallback function
 49 |     |      * and {_fallback} should delegate.
 50 |     |      */
 51 |     |     function _implementation() internal view virtual returns (address);
 52 |     | 
 53 |     |     /**
 54 |     |      * @dev Delegates the current call to the address returned by `_implementation()`.
 55 |     |      *
 56 |     |      * This function does not return to its internal call site, it will return directly to the external caller.
 57 |     |      */
 58 |     |     function _fallback() internal virtual {
 59 |     |         _beforeFallback();
 60 |     |         _delegate(_implementation());
 61 |     |     }
 62 |     | 
 63 |     |     /**
 64 |     |      * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if no other
 65 |     |      * function in the contract matches the call data.
 66 |     |      */
 67 |     |     fallback() external payable virtual {
 68 |     |         _fallback();
 69 |     |     }
 70 |     | 
 71 |     |     /**
 72 |     |      * @dev Fallback function that delegates calls to the address returned by `_implementation()`. Will run if call data
 73 |     |      * is empty.
 74 |     |      */
 75 |     |     receive() external payable virtual {
 76 |     |         _fallback();
 77 |     |     }
 78 |     | 
 79 |     |     /**
 80 |     |      * @dev Hook that is called before falling back to the implementation. Can happen as part of a manual `_fallback`
 81 |     |      * call, or as part of the Solidity `fallback` or `receive` functions.
 82 |     |      *
 83 |     |      * If overridden should call `super._beforeFallback()`.
 84 |     |      */
 85 |     |     function _beforeFallback() internal virtual {}
 86 |     | }
 87 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/proxy/beacon/IBeacon.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.0;
  5 |     | 
  6 |     | /**
  7 |     |  * @dev This is the interface that {BeaconProxy} expects of its beacon.
  8 |     |  */
  9 |     | interface IBeacon {
 10 |     |     /**
 11 |     |      * @dev Must return an address that can be used as a delegate call target.
 12 |     |      *
 13 |     |      * {BeaconProxy} will check that this address is a contract.
 14 |     |      */
 15 |     |     function implementation() external view returns (address);
 16 |     | }
 17 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/proxy/utils/UUPSUpgradeable.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (proxy/utils/UUPSUpgradeable.sol)
   3 |     | 
   4 |     | pragma solidity ^0.8.0;
   5 |     | 
   6 |     | import "../../interfaces/draft-IERC1822.sol";
   7 |     | import "../ERC1967/ERC1967Upgrade.sol";
   8 |     | 
   9 |     | /**
  10 |     |  * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an
  11 |     |  * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy.
  12 |     |  *
  13 |     |  * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is
  14 |     |  * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing
  15 |     |  * `UUPSUpgradeable` with a custom implementation of upgrades.
  16 |     |  *
  17 |     |  * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism.
  18 |     |  *
  19 |     |  * _Available since v4.1._
  20 |     |  */
  21 |     | abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade {
  22 |     |     /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment
  23 | *   |     address private immutable __self = address(this);
  24 |     | 
  25 |     |     /**
  26 |     |      * @dev Check that the execution is being performed through a delegatecall call and that the execution context is
  27 |     |      * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case
  28 |     |      * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a
  29 |     |      * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to
  30 |     |      * fail.
  31 |     |      */
  32 |     |     modifier onlyProxy() {
  33 |     |         require(address(this) != __self, "Function must be called through delegatecall");
  34 |     |         require(_getImplementation() == __self, "Function must be called through active proxy");
  35 |     |         _;
  36 |     |     }
  37 |     | 
  38 |     |     /**
  39 |     |      * @dev Check that the execution is not being performed through a delegate call. This allows a function to be
  40 |     |      * callable on the implementing contract but not through proxies.
  41 |     |      */
  42 |     |     modifier notDelegated() {
  43 |     |         require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall");
  44 |     |         _;
  45 |     |     }
  46 |     | 
  47 |     |     /**
  48 |     |      * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the
  49 |     |      * implementation. It is used to validate the implementation's compatibility when performing an upgrade.
  50 |     |      *
  51 |     |      * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
  52 |     |      * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
  53 |     |      * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier.
  54 |     |      */
  55 |     |     function proxiableUUID() external view virtual override notDelegated returns (bytes32) {
  56 |     |         return _IMPLEMENTATION_SLOT;
  57 |     |     }
  58 |     | 
  59 |     |     /**
  60 |     |      * @dev Upgrade the implementation of the proxy to `newImplementation`.
  61 |     |      *
  62 |     |      * Calls {_authorizeUpgrade}.
  63 |     |      *
  64 |     |      * Emits an {Upgraded} event.
  65 |     |      *
  66 |     |      * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
  67 |     |      */
  68 |     |     function upgradeTo(address newImplementation) public virtual onlyProxy {
  69 |     |         _authorizeUpgrade(newImplementation);
  70 |     |         _upgradeToAndCallUUPS(newImplementation, new bytes(0), false);
  71 |     |     }
  72 |     | 
  73 |     |     /**
  74 |     |      * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call
  75 |     |      * encoded in `data`.
  76 |     |      *
  77 |     |      * Calls {_authorizeUpgrade}.
  78 |     |      *
  79 |     |      * Emits an {Upgraded} event.
  80 |     |      *
  81 |     |      * @custom:oz-upgrades-unsafe-allow-reachable delegatecall
  82 |     |      */
  83 |     |     function upgradeToAndCall(address newImplementation, bytes memory data) public payable virtual onlyProxy {
  84 |     |         _authorizeUpgrade(newImplementation);
  85 |     |         _upgradeToAndCallUUPS(newImplementation, data, true);
  86 |     |     }
  87 |     | 
  88 |     |     /**
  89 |     |      * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by
  90 |     |      * {upgradeTo} and {upgradeToAndCall}.
  91 |     |      *
  92 |     |      * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}.
  93 |     |      *
  94 |     |      * ```solidity
  95 |     |      * function _authorizeUpgrade(address) internal override onlyOwner {}
  96 |     |      * ```
  97 |     |      */
  98 |     |     function _authorizeUpgrade(address newImplementation) internal virtual;
  99 |     | }
 100 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/token/ERC20/ERC20.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
   3 |     | 
   4 |     | pragma solidity ^0.8.0;
   5 |     | 
   6 |     | import "./IERC20.sol";
   7 |     | import "./extensions/IERC20Metadata.sol";
   8 |     | import "../../utils/Context.sol";
   9 |     | 
  10 |     | /**
  11 |     |  * @dev Implementation of the {IERC20} interface.
  12 |     |  *
  13 |     |  * This implementation is agnostic to the way tokens are created. This means
  14 |     |  * that a supply mechanism has to be added in a derived contract using {_mint}.
  15 |     |  * For a generic mechanism see {ERC20PresetMinterPauser}.
  16 |     |  *
  17 |     |  * TIP: For a detailed writeup see our guide
  18 |     |  * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
  19 |     |  * to implement supply mechanisms].
  20 |     |  *
  21 |     |  * The default value of {decimals} is 18. To change this, you should override
  22 |     |  * this function so it returns a different value.
  23 |     |  *
  24 |     |  * We have followed general OpenZeppelin Contracts guidelines: functions revert
  25 |     |  * instead returning `false` on failure. This behavior is nonetheless
  26 |     |  * conventional and does not conflict with the expectations of ERC20
  27 |     |  * applications.
  28 |     |  *
  29 |     |  * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
  30 |     |  * This allows applications to reconstruct the allowance for all accounts just
  31 |     |  * by listening to said events. Other implementations of the EIP may not emit
  32 |     |  * these events, as it isn't required by the specification.
  33 |     |  *
  34 |     |  * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
  35 |     |  * functions have been added to mitigate the well-known issues around setting
  36 |     |  * allowances. See {IERC20-approve}.
  37 |     |  */
  38 |     | contract ERC20 is Context, IERC20, IERC20Metadata {
  39 |     |     mapping(address => uint256) private _balances;
  40 |     | 
  41 |     |     mapping(address => mapping(address => uint256)) private _allowances;
  42 |     | 
  43 |     |     uint256 private _totalSupply;
  44 |     | 
  45 |     |     string private _name;
  46 |     |     string private _symbol;
  47 |     | 
  48 |     |     /**
  49 |     |      * @dev Sets the values for {name} and {symbol}.
  50 |     |      *
  51 |     |      * All two of these values are immutable: they can only be set once during
  52 |     |      * construction.
  53 |     |      */
  54 | *   |     constructor(string memory name_, string memory symbol_) {
  55 | *   |         _name = name_;
  56 | *   |         _symbol = symbol_;
  57 |     |     }
  58 |     | 
  59 |     |     /**
  60 |     |      * @dev Returns the name of the token.
  61 |     |      */
  62 |     |     function name() public view virtual override returns (string memory) {
  63 |     |         return _name;
  64 |     |     }
  65 |     | 
  66 |     |     /**
  67 |     |      * @dev Returns the symbol of the token, usually a shorter version of the
  68 |     |      * name.
  69 |     |      */
  70 |     |     function symbol() public view virtual override returns (string memory) {
  71 |     |         return _symbol;
  72 |     |     }
  73 |     | 
  74 |     |     /**
  75 |     |      * @dev Returns the number of decimals used to get its user representation.
  76 |     |      * For example, if `decimals` equals `2`, a balance of `505` tokens should
  77 |     |      * be displayed to a user as `5.05` (`505 / 10 ** 2`).
  78 |     |      *
  79 |     |      * Tokens usually opt for a value of 18, imitating the relationship between
  80 |     |      * Ether and Wei. This is the default value returned by this function, unless
  81 |     |      * it's overridden.
  82 |     |      *
  83 |     |      * NOTE: This information is only used for _display_ purposes: it in
  84 |     |      * no way affects any of the arithmetic of the contract, including
  85 |     |      * {IERC20-balanceOf} and {IERC20-transfer}.
  86 |     |      */
  87 |     |     function decimals() public view virtual override returns (uint8) {
  88 |     |         return 18;
  89 |     |     }
  90 |     | 
  91 |     |     /**
  92 |     |      * @dev See {IERC20-totalSupply}.
  93 |     |      */
  94 |     |     function totalSupply() public view virtual override returns (uint256) {
  95 |     |         return _totalSupply;
  96 |     |     }
  97 |     | 
  98 |     |     /**
  99 |     |      * @dev See {IERC20-balanceOf}.
 100 |     |      */
 101 | *   |     function balanceOf(address account) public view virtual override returns (uint256) {
 102 | *   |         return _balances[account];
 103 |     |     }
 104 |     | 
 105 |     |     /**
 106 |     |      * @dev See {IERC20-transfer}.
 107 |     |      *
 108 |     |      * Requirements:
 109 |     |      *
 110 |     |      * - `to` cannot be the zero address.
 111 |     |      * - the caller must have a balance of at least `amount`.
 112 |     |      */
 113 | *   |     function transfer(address to, uint256 amount) public virtual override returns (bool) {
 114 | *   |         address owner = _msgSender();
 115 | *   |         _transfer(owner, to, amount);
 116 | *   |         return true;
 117 |     |     }
 118 |     | 
 119 |     |     /**
 120 |     |      * @dev See {IERC20-allowance}.
 121 |     |      */
 122 | *   |     function allowance(address owner, address spender) public view virtual override returns (uint256) {
 123 | *   |         return _allowances[owner][spender];
 124 |     |     }
 125 |     | 
 126 |     |     /**
 127 |     |      * @dev See {IERC20-approve}.
 128 |     |      *
 129 |     |      * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
 130 |     |      * `transferFrom`. This is semantically equivalent to an infinite approval.
 131 |     |      *
 132 |     |      * Requirements:
 133 |     |      *
 134 |     |      * - `spender` cannot be the zero address.
 135 |     |      */
 136 | *   |     function approve(address spender, uint256 amount) public virtual override returns (bool) {
 137 | *   |         address owner = _msgSender();
 138 | *   |         _approve(owner, spender, amount);
 139 | *   |         return true;
 140 |     |     }
 141 |     | 
 142 |     |     /**
 143 |     |      * @dev See {IERC20-transferFrom}.
 144 |     |      *
 145 |     |      * Emits an {Approval} event indicating the updated allowance. This is not
 146 |     |      * required by the EIP. See the note at the beginning of {ERC20}.
 147 |     |      *
 148 |     |      * NOTE: Does not update the allowance if the current allowance
 149 |     |      * is the maximum `uint256`.
 150 |     |      *
 151 |     |      * Requirements:
 152 |     |      *
 153 |     |      * - `from` and `to` cannot be the zero address.
 154 |     |      * - `from` must have a balance of at least `amount`.
 155 |     |      * - the caller must have allowance for ``from``'s tokens of at least
 156 |     |      * `amount`.
 157 |     |      */
 158 | *   |     function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
 159 | *   |         address spender = _msgSender();
 160 | *   |         _spendAllowance(from, spender, amount);
 161 | *   |         _transfer(from, to, amount);
 162 | *   |         return true;
 163 |     |     }
 164 |     | 
 165 |     |     /**
 166 |     |      * @dev Atomically increases the allowance granted to `spender` by the caller.
 167 |     |      *
 168 |     |      * This is an alternative to {approve} that can be used as a mitigation for
 169 |     |      * problems described in {IERC20-approve}.
 170 |     |      *
 171 |     |      * Emits an {Approval} event indicating the updated allowance.
 172 |     |      *
 173 |     |      * Requirements:
 174 |     |      *
 175 |     |      * - `spender` cannot be the zero address.
 176 |     |      */
 177 |     |     function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
 178 |     |         address owner = _msgSender();
 179 |     |         _approve(owner, spender, allowance(owner, spender) + addedValue);
 180 |     |         return true;
 181 |     |     }
 182 |     | 
 183 |     |     /**
 184 |     |      * @dev Atomically decreases the allowance granted to `spender` by the caller.
 185 |     |      *
 186 |     |      * This is an alternative to {approve} that can be used as a mitigation for
 187 |     |      * problems described in {IERC20-approve}.
 188 |     |      *
 189 |     |      * Emits an {Approval} event indicating the updated allowance.
 190 |     |      *
 191 |     |      * Requirements:
 192 |     |      *
 193 |     |      * - `spender` cannot be the zero address.
 194 |     |      * - `spender` must have allowance for the caller of at least
 195 |     |      * `subtractedValue`.
 196 |     |      */
 197 |     |     function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
 198 |     |         address owner = _msgSender();
 199 |     |         uint256 currentAllowance = allowance(owner, spender);
 200 |     |         require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
 201 |     |         unchecked {
 202 |     |             _approve(owner, spender, currentAllowance - subtractedValue);
 203 |     |         }
 204 |     | 
 205 |     |         return true;
 206 |     |     }
 207 |     | 
 208 |     |     /**
 209 |     |      * @dev Moves `amount` of tokens from `from` to `to`.
 210 |     |      *
 211 |     |      * This internal function is equivalent to {transfer}, and can be used to
 212 |     |      * e.g. implement automatic token fees, slashing mechanisms, etc.
 213 |     |      *
 214 |     |      * Emits a {Transfer} event.
 215 |     |      *
 216 |     |      * Requirements:
 217 |     |      *
 218 |     |      * - `from` cannot be the zero address.
 219 |     |      * - `to` cannot be the zero address.
 220 |     |      * - `from` must have a balance of at least `amount`.
 221 |     |      */
 222 | *   |     function _transfer(address from, address to, uint256 amount) internal virtual {
 223 | *   |         require(from != address(0), "ERC20: transfer from the zero address");
 224 | *   |         require(to != address(0), "ERC20: transfer to the zero address");
 225 |     | 
 226 | *   |         _beforeTokenTransfer(from, to, amount);
 227 |     | 
 228 | *   |         uint256 fromBalance = _balances[from];
 229 | *   |         require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
 230 |     |         unchecked {
 231 | *   |             _balances[from] = fromBalance - amount;
 232 |     |             // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
 233 |     |             // decrementing then incrementing.
 234 | *   |             _balances[to] += amount;
 235 |     |         }
 236 |     | 
 237 | *   |         emit Transfer(from, to, amount);
 238 |     | 
 239 | *   |         _afterTokenTransfer(from, to, amount);
 240 |     |     }
 241 |     | 
 242 |     |     /** @dev Creates `amount` tokens and assigns them to `account`, increasing
 243 |     |      * the total supply.
 244 |     |      *
 245 |     |      * Emits a {Transfer} event with `from` set to the zero address.
 246 |     |      *
 247 |     |      * Requirements:
 248 |     |      *
 249 |     |      * - `account` cannot be the zero address.
 250 |     |      */
 251 | *   |     function _mint(address account, uint256 amount) internal virtual {
 252 | *   |         require(account != address(0), "ERC20: mint to the zero address");
 253 |     | 
 254 | *   |         _beforeTokenTransfer(address(0), account, amount);
 255 |     | 
 256 | *   |         _totalSupply += amount;
 257 |     |         unchecked {
 258 |     |             // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
 259 | *   |             _balances[account] += amount;
 260 |     |         }
 261 | *   |         emit Transfer(address(0), account, amount);
 262 |     | 
 263 | *   |         _afterTokenTransfer(address(0), account, amount);
 264 |     |     }
 265 |     | 
 266 |     |     /**
 267 |     |      * @dev Destroys `amount` tokens from `account`, reducing the
 268 |     |      * total supply.
 269 |     |      *
 270 |     |      * Emits a {Transfer} event with `to` set to the zero address.
 271 |     |      *
 272 |     |      * Requirements:
 273 |     |      *
 274 |     |      * - `account` cannot be the zero address.
 275 |     |      * - `account` must have at least `amount` tokens.
 276 |     |      */
 277 |     |     function _burn(address account, uint256 amount) internal virtual {
 278 |     |         require(account != address(0), "ERC20: burn from the zero address");
 279 |     | 
 280 |     |         _beforeTokenTransfer(account, address(0), amount);
 281 |     | 
 282 |     |         uint256 accountBalance = _balances[account];
 283 |     |         require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
 284 |     |         unchecked {
 285 |     |             _balances[account] = accountBalance - amount;
 286 |     |             // Overflow not possible: amount <= accountBalance <= totalSupply.
 287 |     |             _totalSupply -= amount;
 288 |     |         }
 289 |     | 
 290 |     |         emit Transfer(account, address(0), amount);
 291 |     | 
 292 |     |         _afterTokenTransfer(account, address(0), amount);
 293 |     |     }
 294 |     | 
 295 |     |     /**
 296 |     |      * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
 297 |     |      *
 298 |     |      * This internal function is equivalent to `approve`, and can be used to
 299 |     |      * e.g. set automatic allowances for certain subsystems, etc.
 300 |     |      *
 301 |     |      * Emits an {Approval} event.
 302 |     |      *
 303 |     |      * Requirements:
 304 |     |      *
 305 |     |      * - `owner` cannot be the zero address.
 306 |     |      * - `spender` cannot be the zero address.
 307 |     |      */
 308 | *   |     function _approve(address owner, address spender, uint256 amount) internal virtual {
 309 | *   |         require(owner != address(0), "ERC20: approve from the zero address");
 310 | *   |         require(spender != address(0), "ERC20: approve to the zero address");
 311 |     | 
 312 | *   |         _allowances[owner][spender] = amount;
 313 | *   |         emit Approval(owner, spender, amount);
 314 |     |     }
 315 |     | 
 316 |     |     /**
 317 |     |      * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
 318 |     |      *
 319 |     |      * Does not update the allowance amount in case of infinite allowance.
 320 |     |      * Revert if not enough allowance is available.
 321 |     |      *
 322 |     |      * Might emit an {Approval} event.
 323 |     |      */
 324 | *   |     function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
 325 | *   |         uint256 currentAllowance = allowance(owner, spender);
 326 | *   |         if (currentAllowance != type(uint256).max) {
 327 |     |             require(currentAllowance >= amount, "ERC20: insufficient allowance");
 328 |     |             unchecked {
 329 |     |                 _approve(owner, spender, currentAllowance - amount);
 330 |     |             }
 331 |     |         }
 332 |     |     }
 333 |     | 
 334 |     |     /**
 335 |     |      * @dev Hook that is called before any transfer of tokens. This includes
 336 |     |      * minting and burning.
 337 |     |      *
 338 |     |      * Calling conditions:
 339 |     |      *
 340 |     |      * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
 341 |     |      * will be transferred to `to`.
 342 |     |      * - when `from` is zero, `amount` tokens will be minted for `to`.
 343 |     |      * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
 344 |     |      * - `from` and `to` are never both zero.
 345 |     |      *
 346 |     |      * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
 347 |     |      */
 348 | *   |     function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
 349 |     | 
 350 |     |     /**
 351 |     |      * @dev Hook that is called after any transfer of tokens. This includes
 352 |     |      * minting and burning.
 353 |     |      *
 354 |     |      * Calling conditions:
 355 |     |      *
 356 |     |      * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
 357 |     |      * has been transferred to `to`.
 358 |     |      * - when `from` is zero, `amount` tokens have been minted for `to`.
 359 |     |      * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
 360 |     |      * - `from` and `to` are never both zero.
 361 |     |      *
 362 |     |      * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
 363 |     |      */
 364 | *   |     function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
 365 |     | }
 366 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/token/ERC20/IERC20.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.0;
  5 |     | 
  6 |     | /**
  7 |     |  * @dev Interface of the ERC20 standard as defined in the EIP.
  8 |     |  */
  9 |     | interface IERC20 {
 10 |     |     /**
 11 |     |      * @dev Emitted when `value` tokens are moved from one account (`from`) to
 12 |     |      * another (`to`).
 13 |     |      *
 14 |     |      * Note that `value` may be zero.
 15 |     |      */
 16 |     |     event Transfer(address indexed from, address indexed to, uint256 value);
 17 |     | 
 18 |     |     /**
 19 |     |      * @dev Emitted when the allowance of a `spender` for an `owner` is set by
 20 |     |      * a call to {approve}. `value` is the new allowance.
 21 |     |      */
 22 |     |     event Approval(address indexed owner, address indexed spender, uint256 value);
 23 |     | 
 24 |     |     /**
 25 |     |      * @dev Returns the amount of tokens in existence.
 26 |     |      */
 27 |     |     function totalSupply() external view returns (uint256);
 28 |     | 
 29 |     |     /**
 30 |     |      * @dev Returns the amount of tokens owned by `account`.
 31 |     |      */
 32 |     |     function balanceOf(address account) external view returns (uint256);
 33 |     | 
 34 |     |     /**
 35 |     |      * @dev Moves `amount` tokens from the caller's account to `to`.
 36 |     |      *
 37 |     |      * Returns a boolean value indicating whether the operation succeeded.
 38 |     |      *
 39 |     |      * Emits a {Transfer} event.
 40 |     |      */
 41 |     |     function transfer(address to, uint256 amount) external returns (bool);
 42 |     | 
 43 |     |     /**
 44 |     |      * @dev Returns the remaining number of tokens that `spender` will be
 45 |     |      * allowed to spend on behalf of `owner` through {transferFrom}. This is
 46 |     |      * zero by default.
 47 |     |      *
 48 |     |      * This value changes when {approve} or {transferFrom} are called.
 49 |     |      */
 50 |     |     function allowance(address owner, address spender) external view returns (uint256);
 51 |     | 
 52 |     |     /**
 53 |     |      * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
 54 |     |      *
 55 |     |      * Returns a boolean value indicating whether the operation succeeded.
 56 |     |      *
 57 |     |      * IMPORTANT: Beware that changing an allowance with this method brings the risk
 58 |     |      * that someone may use both the old and the new allowance by unfortunate
 59 |     |      * transaction ordering. One possible solution to mitigate this race
 60 |     |      * condition is to first reduce the spender's allowance to 0 and set the
 61 |     |      * desired value afterwards:
 62 |     |      * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
 63 |     |      *
 64 |     |      * Emits an {Approval} event.
 65 |     |      */
 66 |     |     function approve(address spender, uint256 amount) external returns (bool);
 67 |     | 
 68 |     |     /**
 69 |     |      * @dev Moves `amount` tokens from `from` to `to` using the
 70 |     |      * allowance mechanism. `amount` is then deducted from the caller's
 71 |     |      * allowance.
 72 |     |      *
 73 |     |      * Returns a boolean value indicating whether the operation succeeded.
 74 |     |      *
 75 |     |      * Emits a {Transfer} event.
 76 |     |      */
 77 |     |     function transferFrom(address from, address to, uint256 amount) external returns (bool);
 78 |     | }
 79 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.0;
  5 |     | 
  6 |     | import "../ERC20.sol";
  7 |     | import "../../../utils/Context.sol";
  8 |     | 
  9 |     | /**
 10 |     |  * @dev Extension of {ERC20} that allows token holders to destroy both their own
 11 |     |  * tokens and those that they have an allowance for, in a way that can be
 12 |     |  * recognized off-chain (via event analysis).
 13 |     |  */
 14 |     | abstract contract ERC20Burnable is Context, ERC20 {
 15 |     |     /**
 16 |     |      * @dev Destroys `amount` tokens from the caller.
 17 |     |      *
 18 |     |      * See {ERC20-_burn}.
 19 |     |      */
 20 |     |     function burn(uint256 amount) public virtual {
 21 |     |         _burn(_msgSender(), amount);
 22 |     |     }
 23 |     | 
 24 |     |     /**
 25 |     |      * @dev Destroys `amount` tokens from `account`, deducting from the caller's
 26 |     |      * allowance.
 27 |     |      *
 28 |     |      * See {ERC20-_burn} and {ERC20-allowance}.
 29 |     |      *
 30 |     |      * Requirements:
 31 |     |      *
 32 |     |      * - the caller must have allowance for ``accounts``'s tokens of at least
 33 |     |      * `amount`.
 34 |     |      */
 35 |     |     function burnFrom(address account, uint256 amount) public virtual {
 36 |     |         _spendAllowance(account, _msgSender(), amount);
 37 |     |         _burn(account, amount);
 38 |     |     }
 39 |     | }
 40 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.0;
  5 |     | 
  6 |     | import "../IERC20.sol";
  7 |     | 
  8 |     | /**
  9 |     |  * @dev Interface for the optional metadata functions from the ERC20 standard.
 10 |     |  *
 11 |     |  * _Available since v4.1._
 12 |     |  */
 13 |     | interface IERC20Metadata is IERC20 {
 14 |     |     /**
 15 |     |      * @dev Returns the name of the token.
 16 |     |      */
 17 |     |     function name() external view returns (string memory);
 18 |     | 
 19 |     |     /**
 20 |     |      * @dev Returns the symbol of the token.
 21 |     |      */
 22 |     |     function symbol() external view returns (string memory);
 23 |     | 
 24 |     |     /**
 25 |     |      * @dev Returns the decimals places of the token.
 26 |     |      */
 27 |     |     function decimals() external view returns (uint8);
 28 |     | }
 29 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Permit.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.0;
  5 |     | 
  6 |     | /**
  7 |     |  * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
  8 |     |  * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
  9 |     |  *
 10 |     |  * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 11 |     |  * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 12 |     |  * need to send a transaction, and thus is not required to hold Ether at all.
 13 |     |  */
 14 |     | interface IERC20Permit {
 15 |     |     /**
 16 |     |      * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
 17 |     |      * given ``owner``'s signed approval.
 18 |     |      *
 19 |     |      * IMPORTANT: The same issues {IERC20-approve} has related to transaction
 20 |     |      * ordering also apply here.
 21 |     |      *
 22 |     |      * Emits an {Approval} event.
 23 |     |      *
 24 |     |      * Requirements:
 25 |     |      *
 26 |     |      * - `spender` cannot be the zero address.
 27 |     |      * - `deadline` must be a timestamp in the future.
 28 |     |      * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
 29 |     |      * over the EIP712-formatted function arguments.
 30 |     |      * - the signature must use ``owner``'s current nonce (see {nonces}).
 31 |     |      *
 32 |     |      * For more information on the signature format, see the
 33 |     |      * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
 34 |     |      * section].
 35 |     |      */
 36 |     |     function permit(
 37 |     |         address owner,
 38 |     |         address spender,
 39 |     |         uint256 value,
 40 |     |         uint256 deadline,
 41 |     |         uint8 v,
 42 |     |         bytes32 r,
 43 |     |         bytes32 s
 44 |     |     ) external;
 45 |     | 
 46 |     |     /**
 47 |     |      * @dev Returns the current nonce for `owner`. This value must be
 48 |     |      * included whenever a signature is generated for {permit}.
 49 |     |      *
 50 |     |      * Every successful call to {permit} increases ``owner``'s nonce by one. This
 51 |     |      * prevents a signature from being used multiple times.
 52 |     |      */
 53 |     |     function nonces(address owner) external view returns (uint256);
 54 |     | 
 55 |     |     /**
 56 |     |      * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
 57 |     |      */
 58 |     |     // solhint-disable-next-line func-name-mixedcase
 59 |     |     function DOMAIN_SEPARATOR() external view returns (bytes32);
 60 |     | }
 61 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/presets/ERC20PresetFixedSupply.sol)
  3 |     | pragma solidity ^0.8.0;
  4 |     | 
  5 |     | import "../extensions/ERC20Burnable.sol";
  6 |     | 
  7 |     | /**
  8 |     |  * @dev {ERC20} token, including:
  9 |     |  *
 10 |     |  *  - Preminted initial supply
 11 |     |  *  - Ability for holders to burn (destroy) their tokens
 12 |     |  *  - No access control mechanism (for minting/pausing) and hence no governance
 13 |     |  *
 14 |     |  * This contract uses {ERC20Burnable} to include burn capabilities - head to
 15 |     |  * its documentation for details.
 16 |     |  *
 17 |     |  * _Available since v3.4._
 18 |     |  *
 19 |     |  * _Deprecated in favor of https://wizard.openzeppelin.com/[Contracts Wizard]._
 20 |     |  */
 21 | *   | contract ERC20PresetFixedSupply is ERC20Burnable {
 22 |     |     /**
 23 |     |      * @dev Mints `initialSupply` amount of token and transfers them to `owner`.
 24 |     |      *
 25 |     |      * See {ERC20-constructor}.
 26 |     |      */
 27 | *   |     constructor(string memory name, string memory symbol, uint256 initialSupply, address owner) ERC20(name, symbol) {
 28 | *   |         _mint(owner, initialSupply);
 29 |     |     }
 30 |     | }
 31 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
   3 |     | 
   4 |     | pragma solidity ^0.8.0;
   5 |     | 
   6 |     | import "../IERC20.sol";
   7 |     | import "../extensions/IERC20Permit.sol";
   8 |     | import "../../../utils/Address.sol";
   9 |     | 
  10 |     | /**
  11 |     |  * @title SafeERC20
  12 |     |  * @dev Wrappers around ERC20 operations that throw on failure (when the token
  13 |     |  * contract returns false). Tokens that return no value (and instead revert or
  14 |     |  * throw on failure) are also supported, non-reverting calls are assumed to be
  15 |     |  * successful.
  16 |     |  * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
  17 |     |  * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
  18 |     |  */
  19 |     | library SafeERC20 {
  20 |     |     using Address for address;
  21 |     | 
  22 |     |     /**
  23 |     |      * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
  24 |     |      * non-reverting calls are assumed to be successful.
  25 |     |      */
  26 | *   |     function safeTransfer(IERC20 token, address to, uint256 value) internal {
  27 | *   |         _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
  28 |     |     }
  29 |     | 
  30 |     |     /**
  31 |     |      * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
  32 |     |      * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
  33 |     |      */
  34 | *   |     function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
  35 | *   |         _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
  36 |     |     }
  37 |     | 
  38 |     |     /**
  39 |     |      * @dev Deprecated. This function has issues similar to the ones found in
  40 |     |      * {IERC20-approve}, and its usage is discouraged.
  41 |     |      *
  42 |     |      * Whenever possible, use {safeIncreaseAllowance} and
  43 |     |      * {safeDecreaseAllowance} instead.
  44 |     |      */
  45 |     |     function safeApprove(IERC20 token, address spender, uint256 value) internal {
  46 |     |         // safeApprove should only be called when setting an initial allowance,
  47 |     |         // or when resetting it to zero. To increase and decrease it, use
  48 |     |         // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
  49 |     |         require(
  50 |     |             (value == 0) || (token.allowance(address(this), spender) == 0),
  51 |     |             "SafeERC20: approve from non-zero to non-zero allowance"
  52 |     |         );
  53 |     |         _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
  54 |     |     }
  55 |     | 
  56 |     |     /**
  57 |     |      * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
  58 |     |      * non-reverting calls are assumed to be successful.
  59 |     |      */
  60 |     |     function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
  61 |     |         uint256 oldAllowance = token.allowance(address(this), spender);
  62 |     |         _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
  63 |     |     }
  64 |     | 
  65 |     |     /**
  66 |     |      * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
  67 |     |      * non-reverting calls are assumed to be successful.
  68 |     |      */
  69 |     |     function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
  70 |     |         unchecked {
  71 |     |             uint256 oldAllowance = token.allowance(address(this), spender);
  72 |     |             require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
  73 |     |             _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
  74 |     |         }
  75 |     |     }
  76 |     | 
  77 |     |     /**
  78 |     |      * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
  79 |     |      * non-reverting calls are assumed to be successful. Compatible with tokens that require the approval to be set to
  80 |     |      * 0 before setting it to a non-zero value.
  81 |     |      */
  82 |     |     function forceApprove(IERC20 token, address spender, uint256 value) internal {
  83 |     |         bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);
  84 |     | 
  85 |     |         if (!_callOptionalReturnBool(token, approvalCall)) {
  86 |     |             _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
  87 |     |             _callOptionalReturn(token, approvalCall);
  88 |     |         }
  89 |     |     }
  90 |     | 
  91 |     |     /**
  92 |     |      * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
  93 |     |      * Revert on invalid signature.
  94 |     |      */
  95 |     |     function safePermit(
  96 |     |         IERC20Permit token,
  97 |     |         address owner,
  98 |     |         address spender,
  99 |     |         uint256 value,
 100 |     |         uint256 deadline,
 101 |     |         uint8 v,
 102 |     |         bytes32 r,
 103 |     |         bytes32 s
 104 |     |     ) internal {
 105 |     |         uint256 nonceBefore = token.nonces(owner);
 106 |     |         token.permit(owner, spender, value, deadline, v, r, s);
 107 |     |         uint256 nonceAfter = token.nonces(owner);
 108 |     |         require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
 109 |     |     }
 110 |     | 
 111 |     |     /**
 112 |     |      * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
 113 |     |      * on the return value: the return value is optional (but if data is returned, it must not be false).
 114 |     |      * @param token The token targeted by the call.
 115 |     |      * @param data The call data (encoded using abi.encode or one of its variants).
 116 |     |      */
 117 | *   |     function _callOptionalReturn(IERC20 token, bytes memory data) private {
 118 |     |         // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
 119 |     |         // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
 120 |     |         // the target address contains contract code and also asserts for success in the low-level call.
 121 |     | 
 122 | *   |         bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
 123 | *   |         require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
 124 |     |     }
 125 |     | 
 126 |     |     /**
 127 |     |      * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
 128 |     |      * on the return value: the return value is optional (but if data is returned, it must not be false).
 129 |     |      * @param token The token targeted by the call.
 130 |     |      * @param data The call data (encoded using abi.encode or one of its variants).
 131 |     |      *
 132 |     |      * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
 133 |     |      */
 134 |     |     function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
 135 |     |         // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
 136 |     |         // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
 137 |     |         // and not revert is the subcall reverts.
 138 |     | 
 139 |     |         (bool success, bytes memory returndata) = address(token).call(data);
 140 |     |         return
 141 |     |             success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
 142 |     |     }
 143 |     | }
 144 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/utils/Address.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)
   3 |     | 
   4 |     | pragma solidity ^0.8.1;
   5 |     | 
   6 |     | /**
   7 |     |  * @dev Collection of functions related to the address type
   8 |     |  */
   9 |     | library Address {
  10 |     |     /**
  11 |     |      * @dev Returns true if `account` is a contract.
  12 |     |      *
  13 |     |      * [IMPORTANT]
  14 |     |      * ====
  15 |     |      * It is unsafe to assume that an address for which this function returns
  16 |     |      * false is an externally-owned account (EOA) and not a contract.
  17 |     |      *
  18 |     |      * Among others, `isContract` will return false for the following
  19 |     |      * types of addresses:
  20 |     |      *
  21 |     |      *  - an externally-owned account
  22 |     |      *  - a contract in construction
  23 |     |      *  - an address where a contract will be created
  24 |     |      *  - an address where a contract lived, but was destroyed
  25 |     |      *
  26 |     |      * Furthermore, `isContract` will also return true if the target contract within
  27 |     |      * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
  28 |     |      * which only has an effect at the end of a transaction.
  29 |     |      * ====
  30 |     |      *
  31 |     |      * [IMPORTANT]
  32 |     |      * ====
  33 |     |      * You shouldn't rely on `isContract` to protect against flash loan attacks!
  34 |     |      *
  35 |     |      * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
  36 |     |      * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
  37 |     |      * constructor.
  38 |     |      * ====
  39 |     |      */
  40 |     |     function isContract(address account) internal view returns (bool) {
  41 |     |         // This method relies on extcodesize/address.code.length, which returns 0
  42 |     |         // for contracts in construction, since the code is only stored at the end
  43 |     |         // of the constructor execution.
  44 |     | 
  45 |     |         return account.code.length > 0;
  46 |     |     }
  47 |     | 
  48 |     |     /**
  49 |     |      * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
  50 |     |      * `recipient`, forwarding all available gas and reverting on errors.
  51 |     |      *
  52 |     |      * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
  53 |     |      * of certain opcodes, possibly making contracts go over the 2300 gas limit
  54 |     |      * imposed by `transfer`, making them unable to receive funds via
  55 |     |      * `transfer`. {sendValue} removes this limitation.
  56 |     |      *
  57 |     |      * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
  58 |     |      *
  59 |     |      * IMPORTANT: because control is transferred to `recipient`, care must be
  60 |     |      * taken to not create reentrancy vulnerabilities. Consider using
  61 |     |      * {ReentrancyGuard} or the
  62 |     |      * https://solidity.readthedocs.io/en/v0.8.0/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
  63 |     |      */
  64 |     |     function sendValue(address payable recipient, uint256 amount) internal {
  65 |     |         require(address(this).balance >= amount, "Address: insufficient balance");
  66 |     | 
  67 |     |         (bool success, ) = recipient.call{value: amount}("");
  68 |     |         require(success, "Address: unable to send value, recipient may have reverted");
  69 |     |     }
  70 |     | 
  71 |     |     /**
  72 |     |      * @dev Performs a Solidity function call using a low level `call`. A
  73 |     |      * plain `call` is an unsafe replacement for a function call: use this
  74 |     |      * function instead.
  75 |     |      *
  76 |     |      * If `target` reverts with a revert reason, it is bubbled up by this
  77 |     |      * function (like regular Solidity function calls).
  78 |     |      *
  79 |     |      * Returns the raw returned data. To convert to the expected return value,
  80 |     |      * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
  81 |     |      *
  82 |     |      * Requirements:
  83 |     |      *
  84 |     |      * - `target` must be a contract.
  85 |     |      * - calling `target` with `data` must not revert.
  86 |     |      *
  87 |     |      * _Available since v3.1._
  88 |     |      */
  89 |     |     function functionCall(address target, bytes memory data) internal returns (bytes memory) {
  90 |     |         return functionCallWithValue(target, data, 0, "Address: low-level call failed");
  91 |     |     }
  92 |     | 
  93 |     |     /**
  94 |     |      * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
  95 |     |      * `errorMessage` as a fallback revert reason when `target` reverts.
  96 |     |      *
  97 |     |      * _Available since v3.1._
  98 |     |      */
  99 | *   |     function functionCall(
 100 |     |         address target,
 101 |     |         bytes memory data,
 102 |     |         string memory errorMessage
 103 | *   |     ) internal returns (bytes memory) {
 104 | *   |         return functionCallWithValue(target, data, 0, errorMessage);
 105 |     |     }
 106 |     | 
 107 |     |     /**
 108 |     |      * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
 109 |     |      * but also transferring `value` wei to `target`.
 110 |     |      *
 111 |     |      * Requirements:
 112 |     |      *
 113 |     |      * - the calling contract must have an ETH balance of at least `value`.
 114 |     |      * - the called Solidity function must be `payable`.
 115 |     |      *
 116 |     |      * _Available since v3.1._
 117 |     |      */
 118 |     |     function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
 119 |     |         return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
 120 |     |     }
 121 |     | 
 122 |     |     /**
 123 |     |      * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
 124 |     |      * with `errorMessage` as a fallback revert reason when `target` reverts.
 125 |     |      *
 126 |     |      * _Available since v3.1._
 127 |     |      */
 128 | *   |     function functionCallWithValue(
 129 |     |         address target,
 130 |     |         bytes memory data,
 131 |     |         uint256 value,
 132 |     |         string memory errorMessage
 133 | *   |     ) internal returns (bytes memory) {
 134 | *   |         require(address(this).balance >= value, "Address: insufficient balance for call");
 135 | *   |         (bool success, bytes memory returndata) = target.call{value: value}(data);
 136 | *   |         return verifyCallResultFromTarget(target, success, returndata, errorMessage);
 137 |     |     }
 138 |     | 
 139 |     |     /**
 140 |     |      * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
 141 |     |      * but performing a static call.
 142 |     |      *
 143 |     |      * _Available since v3.3._
 144 |     |      */
 145 |     |     function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
 146 |     |         return functionStaticCall(target, data, "Address: low-level static call failed");
 147 |     |     }
 148 |     | 
 149 |     |     /**
 150 |     |      * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
 151 |     |      * but performing a static call.
 152 |     |      *
 153 |     |      * _Available since v3.3._
 154 |     |      */
 155 |     |     function functionStaticCall(
 156 |     |         address target,
 157 |     |         bytes memory data,
 158 |     |         string memory errorMessage
 159 |     |     ) internal view returns (bytes memory) {
 160 |     |         (bool success, bytes memory returndata) = target.staticcall(data);
 161 |     |         return verifyCallResultFromTarget(target, success, returndata, errorMessage);
 162 |     |     }
 163 |     | 
 164 |     |     /**
 165 |     |      * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
 166 |     |      * but performing a delegate call.
 167 |     |      *
 168 |     |      * _Available since v3.4._
 169 |     |      */
 170 |     |     function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
 171 |     |         return functionDelegateCall(target, data, "Address: low-level delegate call failed");
 172 |     |     }
 173 |     | 
 174 |     |     /**
 175 |     |      * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
 176 |     |      * but performing a delegate call.
 177 |     |      *
 178 |     |      * _Available since v3.4._
 179 |     |      */
 180 |     |     function functionDelegateCall(
 181 |     |         address target,
 182 |     |         bytes memory data,
 183 |     |         string memory errorMessage
 184 |     |     ) internal returns (bytes memory) {
 185 |     |         (bool success, bytes memory returndata) = target.delegatecall(data);
 186 |     |         return verifyCallResultFromTarget(target, success, returndata, errorMessage);
 187 |     |     }
 188 |     | 
 189 |     |     /**
 190 |     |      * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
 191 |     |      * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
 192 |     |      *
 193 |     |      * _Available since v4.8._
 194 |     |      */
 195 | *   |     function verifyCallResultFromTarget(
 196 |     |         address target,
 197 |     |         bool success,
 198 |     |         bytes memory returndata,
 199 |     |         string memory errorMessage
 200 | *   |     ) internal view returns (bytes memory) {
 201 | *   |         if (success) {
 202 | *   |             if (returndata.length == 0) {
 203 |     |                 // only check isContract if the call was successful and the return data is empty
 204 |     |                 // otherwise we already know that it was a contract
 205 |     |                 require(isContract(target), "Address: call to non-contract");
 206 |     |             }
 207 | *   |             return returndata;
 208 |     |         } else {
 209 | *   |             _revert(returndata, errorMessage);
 210 |     |         }
 211 |     |     }
 212 |     | 
 213 |     |     /**
 214 |     |      * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
 215 |     |      * revert reason or using the provided one.
 216 |     |      *
 217 |     |      * _Available since v4.3._
 218 |     |      */
 219 |     |     function verifyCallResult(
 220 |     |         bool success,
 221 |     |         bytes memory returndata,
 222 |     |         string memory errorMessage
 223 |     |     ) internal pure returns (bytes memory) {
 224 |     |         if (success) {
 225 |     |             return returndata;
 226 |     |         } else {
 227 |     |             _revert(returndata, errorMessage);
 228 |     |         }
 229 |     |     }
 230 |     | 
 231 | *   |     function _revert(bytes memory returndata, string memory errorMessage) private pure {
 232 |     |         // Look for revert reason and bubble it up if present
 233 | *   |         if (returndata.length > 0) {
 234 |     |             // The easiest way to bubble the revert reason is using memory via assembly
 235 |     |             /// @solidity memory-safe-assembly
 236 |     |             assembly {
 237 | *   |                 let returndata_size := mload(returndata)
 238 | *   |                 revert(add(32, returndata), returndata_size)
 239 |     |             }
 240 |     |         } else {
 241 |     |             revert(errorMessage);
 242 |     |         }
 243 |     |     }
 244 |     | }
 245 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/utils/Context.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
  3 |     | 
  4 |     | pragma solidity ^0.8.0;
  5 |     | 
  6 |     | /**
  7 |     |  * @dev Provides information about the current execution context, including the
  8 |     |  * sender of the transaction and its data. While these are generally available
  9 |     |  * via msg.sender and msg.data, they should not be accessed in such a direct
 10 |     |  * manner, since when dealing with meta-transactions the account sending and
 11 |     |  * paying for execution may not be the actual sender (as far as an application
 12 |     |  * is concerned).
 13 |     |  *
 14 |     |  * This contract is only required for intermediate, library-like contracts.
 15 |     |  */
 16 |     | abstract contract Context {
 17 | *   |     function _msgSender() internal view virtual returns (address) {
 18 | *   |         return msg.sender;
 19 |     |     }
 20 |     | 
 21 |     |     function _msgData() internal view virtual returns (bytes calldata) {
 22 |     |         return msg.data;
 23 |     |     }
 24 |     | }
 25 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/utils/StorageSlot.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
   3 |     | // This file was procedurally generated from scripts/generate/templates/StorageSlot.js.
   4 |     | 
   5 |     | pragma solidity ^0.8.0;
   6 |     | 
   7 |     | /**
   8 |     |  * @dev Library for reading and writing primitive types to specific storage slots.
   9 |     |  *
  10 |     |  * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
  11 |     |  * This library helps with reading and writing to such slots without the need for inline assembly.
  12 |     |  *
  13 |     |  * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
  14 |     |  *
  15 |     |  * Example usage to set ERC1967 implementation slot:
  16 |     |  * ```solidity
  17 |     |  * contract ERC1967 {
  18 |     |  *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
  19 |     |  *
  20 |     |  *     function _getImplementation() internal view returns (address) {
  21 |     |  *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
  22 |     |  *     }
  23 |     |  *
  24 |     |  *     function _setImplementation(address newImplementation) internal {
  25 |     |  *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
  26 |     |  *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
  27 |     |  *     }
  28 |     |  * }
  29 |     |  * ```
  30 |     |  *
  31 |     |  * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
  32 |     |  * _Available since v4.9 for `string`, `bytes`._
  33 |     |  */
  34 |     | library StorageSlot {
  35 |     |     struct AddressSlot {
  36 |     |         address value;
  37 |     |     }
  38 |     | 
  39 |     |     struct BooleanSlot {
  40 |     |         bool value;
  41 |     |     }
  42 |     | 
  43 |     |     struct Bytes32Slot {
  44 |     |         bytes32 value;
  45 |     |     }
  46 |     | 
  47 |     |     struct Uint256Slot {
  48 |     |         uint256 value;
  49 |     |     }
  50 |     | 
  51 |     |     struct StringSlot {
  52 |     |         string value;
  53 |     |     }
  54 |     | 
  55 |     |     struct BytesSlot {
  56 |     |         bytes value;
  57 |     |     }
  58 |     | 
  59 |     |     /**
  60 |     |      * @dev Returns an `AddressSlot` with member `value` located at `slot`.
  61 |     |      */
  62 |     |     function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
  63 |     |         /// @solidity memory-safe-assembly
  64 |     |         assembly {
  65 |     |             r.slot := slot
  66 |     |         }
  67 |     |     }
  68 |     | 
  69 |     |     /**
  70 |     |      * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
  71 |     |      */
  72 |     |     function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
  73 |     |         /// @solidity memory-safe-assembly
  74 |     |         assembly {
  75 |     |             r.slot := slot
  76 |     |         }
  77 |     |     }
  78 |     | 
  79 |     |     /**
  80 |     |      * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
  81 |     |      */
  82 |     |     function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
  83 |     |         /// @solidity memory-safe-assembly
  84 |     |         assembly {
  85 |     |             r.slot := slot
  86 |     |         }
  87 |     |     }
  88 |     | 
  89 |     |     /**
  90 |     |      * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
  91 |     |      */
  92 |     |     function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
  93 |     |         /// @solidity memory-safe-assembly
  94 |     |         assembly {
  95 |     |             r.slot := slot
  96 |     |         }
  97 |     |     }
  98 |     | 
  99 |     |     /**
 100 |     |      * @dev Returns an `StringSlot` with member `value` located at `slot`.
 101 |     |      */
 102 |     |     function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
 103 |     |         /// @solidity memory-safe-assembly
 104 |     |         assembly {
 105 |     |             r.slot := slot
 106 |     |         }
 107 |     |     }
 108 |     | 
 109 |     |     /**
 110 |     |      * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
 111 |     |      */
 112 |     |     function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
 113 |     |         /// @solidity memory-safe-assembly
 114 |     |         assembly {
 115 |     |             r.slot := store.slot
 116 |     |         }
 117 |     |     }
 118 |     | 
 119 |     |     /**
 120 |     |      * @dev Returns an `BytesSlot` with member `value` located at `slot`.
 121 |     |      */
 122 |     |     function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
 123 |     |         /// @solidity memory-safe-assembly
 124 |     |         assembly {
 125 |     |             r.slot := slot
 126 |     |         }
 127 |     |     }
 128 |     | 
 129 |     |     /**
 130 |     |      * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
 131 |     |      */
 132 |     |     function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
 133 |     |         /// @solidity memory-safe-assembly
 134 |     |         assembly {
 135 |     |             r.slot := store.slot
 136 |     |         }
 137 |     |     }
 138 |     | }
 139 |     | 

/opt/scfuzzbench/work/target/lib/openzeppelin-contracts/contracts/utils/structs/EnumerableSet.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | // OpenZeppelin Contracts (last updated v4.9.0) (utils/structs/EnumerableSet.sol)
   3 |     | // This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
   4 |     | 
   5 |     | pragma solidity ^0.8.0;
   6 |     | 
   7 |     | /**
   8 |     |  * @dev Library for managing
   9 |     |  * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
  10 |     |  * types.
  11 |     |  *
  12 |     |  * Sets have the following properties:
  13 |     |  *
  14 |     |  * - Elements are added, removed, and checked for existence in constant time
  15 |     |  * (O(1)).
  16 |     |  * - Elements are enumerated in O(n). No guarantees are made on the ordering.
  17 |     |  *
  18 |     |  * ```solidity
  19 |     |  * contract Example {
  20 |     |  *     // Add the library methods
  21 |     |  *     using EnumerableSet for EnumerableSet.AddressSet;
  22 |     |  *
  23 |     |  *     // Declare a set state variable
  24 |     |  *     EnumerableSet.AddressSet private mySet;
  25 |     |  * }
  26 |     |  * ```
  27 |     |  *
  28 |     |  * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
  29 |     |  * and `uint256` (`UintSet`) are supported.
  30 |     |  *
  31 |     |  * [WARNING]
  32 |     |  * ====
  33 |     |  * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
  34 |     |  * unusable.
  35 |     |  * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
  36 |     |  *
  37 |     |  * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
  38 |     |  * array of EnumerableSet.
  39 |     |  * ====
  40 |     |  */
  41 |     | library EnumerableSet {
  42 |     |     // To implement this library for multiple types with as little code
  43 |     |     // repetition as possible, we write it in terms of a generic Set type with
  44 |     |     // bytes32 values.
  45 |     |     // The Set implementation uses private functions, and user-facing
  46 |     |     // implementations (such as AddressSet) are just wrappers around the
  47 |     |     // underlying Set.
  48 |     |     // This means that we can only create new EnumerableSets for types that fit
  49 |     |     // in bytes32.
  50 |     | 
  51 |     |     struct Set {
  52 |     |         // Storage of set values
  53 |     |         bytes32[] _values;
  54 |     |         // Position of the value in the `values` array, plus 1 because index 0
  55 |     |         // means a value is not in the set.
  56 |     |         mapping(bytes32 => uint256) _indexes;
  57 |     |     }
  58 |     | 
  59 |     |     /**
  60 |     |      * @dev Add a value to a set. O(1).
  61 |     |      *
  62 |     |      * Returns true if the value was added to the set, that is if it was not
  63 |     |      * already present.
  64 |     |      */
  65 |     |     function _add(Set storage set, bytes32 value) private returns (bool) {
  66 |     |         if (!_contains(set, value)) {
  67 |     |             set._values.push(value);
  68 |     |             // The value is stored at length-1, but we add 1 to all indexes
  69 |     |             // and use 0 as a sentinel value
  70 |     |             set._indexes[value] = set._values.length;
  71 |     |             return true;
  72 |     |         } else {
  73 |     |             return false;
  74 |     |         }
  75 |     |     }
  76 |     | 
  77 |     |     /**
  78 |     |      * @dev Removes a value from a set. O(1).
  79 |     |      *
  80 |     |      * Returns true if the value was removed from the set, that is if it was
  81 |     |      * present.
  82 |     |      */
  83 |     |     function _remove(Set storage set, bytes32 value) private returns (bool) {
  84 |     |         // We read and store the value's index to prevent multiple reads from the same storage slot
  85 |     |         uint256 valueIndex = set._indexes[value];
  86 |     | 
  87 |     |         if (valueIndex != 0) {
  88 |     |             // Equivalent to contains(set, value)
  89 |     |             // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
  90 |     |             // the array, and then remove the last element (sometimes called as 'swap and pop').
  91 |     |             // This modifies the order of the array, as noted in {at}.
  92 |     | 
  93 |     |             uint256 toDeleteIndex = valueIndex - 1;
  94 |     |             uint256 lastIndex = set._values.length - 1;
  95 |     | 
  96 |     |             if (lastIndex != toDeleteIndex) {
  97 |     |                 bytes32 lastValue = set._values[lastIndex];
  98 |     | 
  99 |     |                 // Move the last value to the index where the value to delete is
 100 |     |                 set._values[toDeleteIndex] = lastValue;
 101 |     |                 // Update the index for the moved value
 102 |     |                 set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
 103 |     |             }
 104 |     | 
 105 |     |             // Delete the slot where the moved value was stored
 106 |     |             set._values.pop();
 107 |     | 
 108 |     |             // Delete the index for the deleted slot
 109 |     |             delete set._indexes[value];
 110 |     | 
 111 |     |             return true;
 112 |     |         } else {
 113 |     |             return false;
 114 |     |         }
 115 |     |     }
 116 |     | 
 117 |     |     /**
 118 |     |      * @dev Returns true if the value is in the set. O(1).
 119 |     |      */
 120 |     |     function _contains(Set storage set, bytes32 value) private view returns (bool) {
 121 |     |         return set._indexes[value] != 0;
 122 |     |     }
 123 |     | 
 124 |     |     /**
 125 |     |      * @dev Returns the number of values on the set. O(1).
 126 |     |      */
 127 |     |     function _length(Set storage set) private view returns (uint256) {
 128 |     |         return set._values.length;
 129 |     |     }
 130 |     | 
 131 |     |     /**
 132 |     |      * @dev Returns the value stored at position `index` in the set. O(1).
 133 |     |      *
 134 |     |      * Note that there are no guarantees on the ordering of values inside the
 135 |     |      * array, and it may change when more values are added or removed.
 136 |     |      *
 137 |     |      * Requirements:
 138 |     |      *
 139 |     |      * - `index` must be strictly less than {length}.
 140 |     |      */
 141 |     |     function _at(Set storage set, uint256 index) private view returns (bytes32) {
 142 |     |         return set._values[index];
 143 |     |     }
 144 |     | 
 145 |     |     /**
 146 |     |      * @dev Return the entire set in an array
 147 |     |      *
 148 |     |      * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
 149 |     |      * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
 150 |     |      * this function has an unbounded cost, and using it as part of a state-changing function may render the function
 151 |     |      * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
 152 |     |      */
 153 |     |     function _values(Set storage set) private view returns (bytes32[] memory) {
 154 |     |         return set._values;
 155 |     |     }
 156 |     | 
 157 |     |     // Bytes32Set
 158 |     | 
 159 |     |     struct Bytes32Set {
 160 |     |         Set _inner;
 161 |     |     }
 162 |     | 
 163 |     |     /**
 164 |     |      * @dev Add a value to a set. O(1).
 165 |     |      *
 166 |     |      * Returns true if the value was added to the set, that is if it was not
 167 |     |      * already present.
 168 |     |      */
 169 |     |     function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
 170 |     |         return _add(set._inner, value);
 171 |     |     }
 172 |     | 
 173 |     |     /**
 174 |     |      * @dev Removes a value from a set. O(1).
 175 |     |      *
 176 |     |      * Returns true if the value was removed from the set, that is if it was
 177 |     |      * present.
 178 |     |      */
 179 |     |     function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
 180 |     |         return _remove(set._inner, value);
 181 |     |     }
 182 |     | 
 183 |     |     /**
 184 |     |      * @dev Returns true if the value is in the set. O(1).
 185 |     |      */
 186 |     |     function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
 187 |     |         return _contains(set._inner, value);
 188 |     |     }
 189 |     | 
 190 |     |     /**
 191 |     |      * @dev Returns the number of values in the set. O(1).
 192 |     |      */
 193 |     |     function length(Bytes32Set storage set) internal view returns (uint256) {
 194 |     |         return _length(set._inner);
 195 |     |     }
 196 |     | 
 197 |     |     /**
 198 |     |      * @dev Returns the value stored at position `index` in the set. O(1).
 199 |     |      *
 200 |     |      * Note that there are no guarantees on the ordering of values inside the
 201 |     |      * array, and it may change when more values are added or removed.
 202 |     |      *
 203 |     |      * Requirements:
 204 |     |      *
 205 |     |      * - `index` must be strictly less than {length}.
 206 |     |      */
 207 |     |     function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
 208 |     |         return _at(set._inner, index);
 209 |     |     }
 210 |     | 
 211 |     |     /**
 212 |     |      * @dev Return the entire set in an array
 213 |     |      *
 214 |     |      * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
 215 |     |      * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
 216 |     |      * this function has an unbounded cost, and using it as part of a state-changing function may render the function
 217 |     |      * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
 218 |     |      */
 219 |     |     function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
 220 |     |         bytes32[] memory store = _values(set._inner);
 221 |     |         bytes32[] memory result;
 222 |     | 
 223 |     |         /// @solidity memory-safe-assembly
 224 |     |         assembly {
 225 |     |             result := store
 226 |     |         }
 227 |     | 
 228 |     |         return result;
 229 |     |     }
 230 |     | 
 231 |     |     // AddressSet
 232 |     | 
 233 |     |     struct AddressSet {
 234 |     |         Set _inner;
 235 |     |     }
 236 |     | 
 237 |     |     /**
 238 |     |      * @dev Add a value to a set. O(1).
 239 |     |      *
 240 |     |      * Returns true if the value was added to the set, that is if it was not
 241 |     |      * already present.
 242 |     |      */
 243 |     |     function add(AddressSet storage set, address value) internal returns (bool) {
 244 |     |         return _add(set._inner, bytes32(uint256(uint160(value))));
 245 |     |     }
 246 |     | 
 247 |     |     /**
 248 |     |      * @dev Removes a value from a set. O(1).
 249 |     |      *
 250 |     |      * Returns true if the value was removed from the set, that is if it was
 251 |     |      * present.
 252 |     |      */
 253 |     |     function remove(AddressSet storage set, address value) internal returns (bool) {
 254 |     |         return _remove(set._inner, bytes32(uint256(uint160(value))));
 255 |     |     }
 256 |     | 
 257 |     |     /**
 258 |     |      * @dev Returns true if the value is in the set. O(1).
 259 |     |      */
 260 |     |     function contains(AddressSet storage set, address value) internal view returns (bool) {
 261 |     |         return _contains(set._inner, bytes32(uint256(uint160(value))));
 262 |     |     }
 263 |     | 
 264 |     |     /**
 265 |     |      * @dev Returns the number of values in the set. O(1).
 266 |     |      */
 267 |     |     function length(AddressSet storage set) internal view returns (uint256) {
 268 |     |         return _length(set._inner);
 269 |     |     }
 270 |     | 
 271 |     |     /**
 272 |     |      * @dev Returns the value stored at position `index` in the set. O(1).
 273 |     |      *
 274 |     |      * Note that there are no guarantees on the ordering of values inside the
 275 |     |      * array, and it may change when more values are added or removed.
 276 |     |      *
 277 |     |      * Requirements:
 278 |     |      *
 279 |     |      * - `index` must be strictly less than {length}.
 280 |     |      */
 281 |     |     function at(AddressSet storage set, uint256 index) internal view returns (address) {
 282 |     |         return address(uint160(uint256(_at(set._inner, index))));
 283 |     |     }
 284 |     | 
 285 |     |     /**
 286 |     |      * @dev Return the entire set in an array
 287 |     |      *
 288 |     |      * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
 289 |     |      * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
 290 |     |      * this function has an unbounded cost, and using it as part of a state-changing function may render the function
 291 |     |      * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
 292 |     |      */
 293 |     |     function values(AddressSet storage set) internal view returns (address[] memory) {
 294 |     |         bytes32[] memory store = _values(set._inner);
 295 |     |         address[] memory result;
 296 |     | 
 297 |     |         /// @solidity memory-safe-assembly
 298 |     |         assembly {
 299 |     |             result := store
 300 |     |         }
 301 |     | 
 302 |     |         return result;
 303 |     |     }
 304 |     | 
 305 |     |     // UintSet
 306 |     | 
 307 |     |     struct UintSet {
 308 |     |         Set _inner;
 309 |     |     }
 310 |     | 
 311 |     |     /**
 312 |     |      * @dev Add a value to a set. O(1).
 313 |     |      *
 314 |     |      * Returns true if the value was added to the set, that is if it was not
 315 |     |      * already present.
 316 |     |      */
 317 |     |     function add(UintSet storage set, uint256 value) internal returns (bool) {
 318 |     |         return _add(set._inner, bytes32(value));
 319 |     |     }
 320 |     | 
 321 |     |     /**
 322 |     |      * @dev Removes a value from a set. O(1).
 323 |     |      *
 324 |     |      * Returns true if the value was removed from the set, that is if it was
 325 |     |      * present.
 326 |     |      */
 327 |     |     function remove(UintSet storage set, uint256 value) internal returns (bool) {
 328 |     |         return _remove(set._inner, bytes32(value));
 329 |     |     }
 330 |     | 
 331 |     |     /**
 332 |     |      * @dev Returns true if the value is in the set. O(1).
 333 |     |      */
 334 |     |     function contains(UintSet storage set, uint256 value) internal view returns (bool) {
 335 |     |         return _contains(set._inner, bytes32(value));
 336 |     |     }
 337 |     | 
 338 |     |     /**
 339 |     |      * @dev Returns the number of values in the set. O(1).
 340 |     |      */
 341 |     |     function length(UintSet storage set) internal view returns (uint256) {
 342 |     |         return _length(set._inner);
 343 |     |     }
 344 |     | 
 345 |     |     /**
 346 |     |      * @dev Returns the value stored at position `index` in the set. O(1).
 347 |     |      *
 348 |     |      * Note that there are no guarantees on the ordering of values inside the
 349 |     |      * array, and it may change when more values are added or removed.
 350 |     |      *
 351 |     |      * Requirements:
 352 |     |      *
 353 |     |      * - `index` must be strictly less than {length}.
 354 |     |      */
 355 |     |     function at(UintSet storage set, uint256 index) internal view returns (uint256) {
 356 |     |         return uint256(_at(set._inner, index));
 357 |     |     }
 358 |     | 
 359 |     |     /**
 360 |     |      * @dev Return the entire set in an array
 361 |     |      *
 362 |     |      * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
 363 |     |      * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
 364 |     |      * this function has an unbounded cost, and using it as part of a state-changing function may render the function
 365 |     |      * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
 366 |     |      */
 367 |     |     function values(UintSet storage set) internal view returns (uint256[] memory) {
 368 |     |         bytes32[] memory store = _values(set._inner);
 369 |     |         uint256[] memory result;
 370 |     | 
 371 |     |         /// @solidity memory-safe-assembly
 372 |     |         assembly {
 373 |     |             result := store
 374 |     |         }
 375 |     | 
 376 |     |         return result;
 377 |     |     }
 378 |     | }
 379 |     | 

/opt/scfuzzbench/work/target/src/AddressDriver.sol
   1 |     | // SPDX-License-Identifier: GPL-3.0-only
   2 |     | pragma solidity ^0.8.20;
   3 |     | 
   4 |     | import {AccountMetadata, Drips, StreamReceiver, IERC20, SplitsReceiver} from "./Drips.sol";
   5 |     | import {Managed} from "./Managed.sol";
   6 |     | import {DriverTransferUtils} from "./DriverTransferUtils.sol";
   7 |     | 
   8 |     | /// @notice A Drips driver implementing address-based account identification.
   9 |     | /// Each address can use `AddressDriver` to control a single account ID derived from that address.
  10 |     | /// No registration is required, an `AddressDriver`-based account ID
  11 |     | /// for each address is available upfront.
  12 |     | contract AddressDriver is DriverTransferUtils, Managed {
  13 |     |     /// @notice The Drips address used by this driver.
  14 |     |     Drips public immutable drips;
  15 |     |     /// @notice The driver ID which this driver uses when calling Drips.
  16 |     |     uint32 public immutable driverId;
  17 |     | 
  18 |     |     /// @param drips_ The Drips contract to use.
  19 |     |     /// @param forwarder The ERC-2771 forwarder to trust. May be the zero address.
  20 |     |     /// @param driverId_ The driver ID to use when calling Drips.
  21 | *   |     constructor(Drips drips_, address forwarder, uint32 driverId_) DriverTransferUtils(forwarder) {
  22 | *   |         drips = drips_;
  23 | *   |         driverId = driverId_;
  24 |     |     }
  25 |     | 
  26 |     |     /// @notice Calculates the account ID for an address.
  27 |     |     /// Every account ID is a 256-bit integer constructed by concatenating:
  28 |     |     /// `driverId (32 bits) | zeros (64 bits) | addr (160 bits)`.
  29 |     |     /// @param addr The address
  30 |     |     /// @return accountId The account ID
  31 | *   |     function calcAccountId(address addr) public view returns (uint256 accountId) {
  32 |     |         // By assignment we get `accountId` value:
  33 |     |         // `zeros (224 bits) | driverId (32 bits)`
  34 | *   |         accountId = driverId;
  35 |     |         // By bit shifting we get `accountId` value:
  36 |     |         // `driverId (32 bits) | zeros (224 bits)`
  37 |     |         // By bit masking we get `accountId` value:
  38 |     |         // `driverId (32 bits) | zeros (64 bits) | addr (160 bits)`
  39 | *   |         accountId = (accountId << 224) | uint160(addr);
  40 |     |     }
  41 |     | 
  42 |     |     /// @notice Calculates the account ID for the message sender
  43 |     |     /// @return accountId The account ID
  44 | *   |     function _callerAccountId() internal view returns (uint256 accountId) {
  45 | *   |         return calcAccountId(_msgSender());
  46 |     |     }
  47 |     | 
  48 |     |     /// @notice Collects the account's received already split funds
  49 |     |     /// and transfers them out of the Drips contract.
  50 |     |     /// @param erc20 The used ERC-20 token.
  51 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
  52 |     |     /// an address, then later the same amount must be transferable from that address.
  53 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
  54 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
  55 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
  56 |     |     /// @param transferTo The address to send collected funds to
  57 |     |     /// @return amt The collected amount
  58 | *   |     function collect(IERC20 erc20, address transferTo) public whenNotPaused returns (uint128 amt) {
  59 | *   |         return _collectAndTransfer(drips, _callerAccountId(), erc20, transferTo);
  60 |     |     }
  61 |     | 
  62 |     |     /// @notice Gives funds from the message sender to the receiver.
  63 |     |     /// The receiver can split and collect them immediately.
  64 |     |     /// Transfers the funds to be given from the message sender's wallet to the Drips contract.
  65 |     |     /// @param receiver The receiver account ID.
  66 |     |     /// @param erc20 The used ERC-20 token.
  67 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
  68 |     |     /// an address, then later the same amount must be transferable from that address.
  69 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
  70 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
  71 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
  72 |     |     /// @param amt The given amount
  73 | *   |     function give(uint256 receiver, IERC20 erc20, uint128 amt) public whenNotPaused {
  74 | *   |         _giveAndTransfer(drips, _callerAccountId(), receiver, erc20, amt);
  75 |     |     }
  76 |     | 
  77 |     |     /// @notice Sets the message sender's streams configuration.
  78 |     |     /// Transfers funds between the message sender's wallet and the Drips contract
  79 |     |     /// to fulfil the change of the streams balance.
  80 |     |     /// @param erc20 The used ERC-20 token.
  81 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
  82 |     |     /// an address, then later the same amount must be transferable from that address.
  83 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
  84 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
  85 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
  86 |     |     /// @param currReceivers The current streams receivers list.
  87 |     |     /// It must be exactly the same as the last list set for the sender with `setStreams`.
  88 |     |     /// If this is the first update, pass an empty array.
  89 |     |     /// @param balanceDelta The streams balance change to be applied.
  90 |     |     /// If it's positive, the balance is increased by `balanceDelta`.
  91 |     |     /// If it's zero, the balance doesn't change.
  92 |     |     /// If it's negative, the balance is decreased by `balanceDelta`,
  93 |     |     /// but the change is capped at the current balance amount, so it doesn't go below 0.
  94 |     |     /// Passing `type(int128).min` always decreases the current balance to 0.
  95 |     |     /// @param newReceivers The list of the streams receivers of the sender to be set.
  96 |     |     /// Must be sorted by the account IDs and then by the stream configurations,
  97 |     |     /// without identical elements and without 0 amtPerSecs.
  98 |     |     /// @param maxEndHint1 An optional parameter allowing gas optimization, pass `0` to ignore it.
  99 |     |     /// The first hint for finding the maximum end time when all streams stop due to funds
 100 |     |     /// running out after the balance is updated and the new receivers list is applied.
 101 |     |     /// Hints have no effect on the results of calling this function, except potentially saving gas.
 102 |     |     /// Hints are Unix timestamps used as the starting points for binary search for the time
 103 |     |     /// when funds run out in the range of timestamps from the current block's to `2^32`.
 104 |     |     /// Hints lower than the current timestamp are ignored.
 105 |     |     /// You can provide zero, one or two hints. The order of hints doesn't matter.
 106 |     |     /// Hints are the most effective when one of them is lower than or equal to
 107 |     |     /// the last timestamp when funds are still streamed, and the other one is strictly larger
 108 |     |     /// than that timestamp,the smaller the difference between such hints, the higher gas savings.
 109 |     |     /// The savings are the highest possible when one of the hints is equal to
 110 |     |     /// the last timestamp when funds are still streamed, and the other one is larger by 1.
 111 |     |     /// It's worth noting that the exact timestamp of the block in which this function is executed
 112 |     |     /// may affect correctness of the hints, especially if they're precise.
 113 |     |     /// Hints don't provide any benefits when balance is not enough to cover
 114 |     |     /// a single second of streaming or is enough to cover all streams until timestamp `2^32`.
 115 |     |     /// Even inaccurate hints can be useful, and providing a single hint
 116 |     |     /// or two hints that don't enclose the time when funds run out can still save some gas.
 117 |     |     /// Providing poor hints that don't reduce the number of binary search steps
 118 |     |     /// may cause slightly higher gas usage than not providing any hints.
 119 |     |     /// @param maxEndHint2 An optional parameter allowing gas optimization, pass `0` to ignore it.
 120 |     |     /// The second hint for finding the maximum end time, see `maxEndHint1` docs for more details.
 121 |     |     /// @param transferTo The address to send funds to in case of decreasing balance
 122 |     |     /// @return realBalanceDelta The actually applied streams balance change.
 123 |     |     /// It's equal to the passed `balanceDelta`, unless it's negative
 124 |     |     /// and it gets capped at the current balance amount.
 125 | *   |     function setStreams(
 126 |     |         IERC20 erc20,
 127 |     |         StreamReceiver[] calldata currReceivers,
 128 |     |         int128 balanceDelta,
 129 |     |         StreamReceiver[] calldata newReceivers,
 130 |     |         // slither-disable-next-line similar-names
 131 |     |         uint32 maxEndHint1,
 132 |     |         uint32 maxEndHint2,
 133 |     |         address transferTo
 134 | *   |     ) public whenNotPaused returns (int128 realBalanceDelta) {
 135 | *   |         return _setStreamsAndTransfer(
 136 | *   |             drips,
 137 | *   |             _callerAccountId(),
 138 | *   |             erc20,
 139 | *   |             currReceivers,
 140 | *   |             balanceDelta,
 141 | *   |             newReceivers,
 142 | *   |             maxEndHint1,
 143 | *   |             maxEndHint2,
 144 | *   |             transferTo
 145 |     |         );
 146 |     |     }
 147 |     | 
 148 |     |     /// @notice Sets the account splits configuration.
 149 |     |     /// The configuration is common for all ERC-20 tokens.
 150 |     |     /// Nothing happens to the currently splittable funds, but when they are split
 151 |     |     /// after this function finishes, the new splits configuration will be used.
 152 |     |     /// Because anybody can call `split` on `Drips`, calling this function may be frontrun
 153 |     |     /// and all the currently splittable funds will be split using the old splits configuration.
 154 |     |     /// @param receivers The list of the account's splits receivers to be set.
 155 |     |     /// Must be sorted by the account IDs, without duplicate account IDs and without 0 weights.
 156 |     |     /// Each splits receiver will be getting `weight / TOTAL_SPLITS_WEIGHT`
 157 |     |     /// share of the funds collected by the account.
 158 |     |     /// If the sum of weights of all receivers is less than `_TOTAL_SPLITS_WEIGHT`,
 159 |     |     /// some funds won't be split, but they will be left for the account to collect.
 160 |     |     /// Fractions of tokens are always rounder either up or down depending on the amount
 161 |     |     /// being split, the receiver's position on the list and the other receivers' weights.
 162 |     |     /// It's valid to include the account's own `accountId` in the list of receivers,
 163 |     |     /// but funds split to themselves return to their splittable balance and are not collectable.
 164 |     |     /// This is usually unwanted, because if splitting is repeated,
 165 |     |     /// funds split to themselves will be again split using the current configuration.
 166 |     |     /// Splitting 100% to self effectively blocks splitting unless the configuration is updated.
 167 | *   |     function setSplits(SplitsReceiver[] calldata receivers) public whenNotPaused {
 168 | *   |         drips.setSplits(_callerAccountId(), receivers);
 169 |     |     }
 170 |     | 
 171 |     |     /// @notice Emits the account metadata for the message sender.
 172 |     |     /// The keys and the values are not standardized by the protocol, it's up to the users
 173 |     |     /// to establish and follow conventions to ensure compatibility with the consumers.
 174 |     |     /// @param accountMetadata The list of account metadata.
 175 |     |     function emitAccountMetadata(AccountMetadata[] calldata accountMetadata) public whenNotPaused {
 176 |     |         if (accountMetadata.length != 0) {
 177 |     |             drips.emitAccountMetadata(_callerAccountId(), accountMetadata);
 178 |     |         }
 179 |     |     }
 180 |     | }
 181 |     | 

/opt/scfuzzbench/work/target/src/Drips.sol
   1 |     | // SPDX-License-Identifier: GPL-3.0-only
   2 |     | pragma solidity ^0.8.20;
   3 |     | 
   4 |     | import {
   5 |     |     Streams, StreamConfig, StreamsHistory, StreamConfigImpl, StreamReceiver
   6 |     | } from "./Streams.sol";
   7 |     | import {Managed} from "./Managed.sol";
   8 |     | import {Splits, SplitsReceiver} from "./Splits.sol";
   9 |     | import {IERC20, SafeERC20} from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol";
  10 |     | 
  11 |     | using SafeERC20 for IERC20;
  12 |     | 
  13 |     | /// @notice The account metadata.
  14 |     | /// The key and the value are not standardized by the protocol, it's up to the users
  15 |     | /// to establish and follow conventions to ensure compatibility with the consumers.
  16 |     | struct AccountMetadata {
  17 |     |     /// @param key The metadata key
  18 |     |     bytes32 key;
  19 |     |     /// @param value The metadata value
  20 |     |     bytes value;
  21 |     | }
  22 |     | 
  23 |     | /// @notice Drips protocol contract. Automatically streams and splits funds between accounts.
  24 |     | ///
  25 |     | /// The account can transfer some funds to their streams balance in the contract
  26 |     | /// and configure a list of receivers, to whom they want to stream these funds.
  27 |     | /// As soon as the streams balance is enough to cover at least 1 second of streaming
  28 |     | /// to the configured receivers, the funds start streaming automatically.
  29 |     | /// Every second funds are deducted from the streams balance and moved to their receivers.
  30 |     | /// The process stops automatically when the streams balance is not enough to cover another second.
  31 |     | ///
  32 |     | /// Every account has a receiver balance, in which they have funds received from other accounts.
  33 |     | /// The streamed funds are added to the receiver balances in global cycles.
  34 |     | /// Every `cycleSecs` seconds the protocol adds streamed funds to the receivers' balances,
  35 |     | /// so recently streamed funds may not be receivable immediately.
  36 |     | /// `cycleSecs` is a constant configured when the Drips contract is deployed.
  37 |     | /// The receiver balance is independent from the streams balance,
  38 |     | /// to stream received funds they need to be first collected and then added to the streams balance.
  39 |     | ///
  40 |     | /// The account can share collected funds with other accounts by using splits.
  41 |     | /// When collecting, the account gives each of their splits receivers
  42 |     | /// a fraction of the received funds.
  43 |     | /// Funds received from splits are available for collection immediately regardless of the cycle.
  44 |     | /// They aren't exempt from being split, so they too can be split when collected.
  45 |     | /// Accounts can build chains and networks of splits between each other.
  46 |     | /// Anybody can request collection of funds for any account,
  47 |     | /// which can be used to enforce the flow of funds in the network of splits.
  48 |     | ///
  49 |     | /// The concept of something happening periodically, e.g. every second or every `cycleSecs` are
  50 |     | /// only high-level abstractions for the account, Ethereum isn't really capable of scheduling work.
  51 |     | /// The actual implementation emulates that behavior by calculating the results of the scheduled
  52 |     | /// events based on how many seconds have passed and only when the account needs their outcomes.
  53 |     | ///
  54 |     | /// The contract can store at most `type(int128).max` which is `2 ^ 127 - 1` units of each token.
  55 |     | contract Drips is Managed, Streams, Splits {
  56 |     |     /// @notice Maximum number of streams receivers of a single account.
  57 |     |     /// Limits cost of changes in streams configuration.
  58 |     |     uint256 public constant MAX_STREAMS_RECEIVERS = _MAX_STREAMS_RECEIVERS;
  59 |     |     /// @notice The additional decimals for all amtPerSec values.
  60 |     |     uint8 public constant AMT_PER_SEC_EXTRA_DECIMALS = _AMT_PER_SEC_EXTRA_DECIMALS;
  61 |     |     /// @notice The multiplier for all amtPerSec values.
  62 |     |     uint160 public constant AMT_PER_SEC_MULTIPLIER = _AMT_PER_SEC_MULTIPLIER;
  63 |     |     /// @notice Maximum number of splits receivers of a single account.
  64 |     |     /// Limits the cost of splitting.
  65 |     |     uint256 public constant MAX_SPLITS_RECEIVERS = _MAX_SPLITS_RECEIVERS;
  66 |     |     /// @notice The total splits weight of an account
  67 | *   |     uint32 public constant TOTAL_SPLITS_WEIGHT = _TOTAL_SPLITS_WEIGHT;
  68 |     |     /// @notice The offset of the controlling driver ID in the account ID.
  69 |     |     /// In other words the controlling driver ID is the highest 32 bits of the account ID.
  70 |     |     /// Every account ID is a 256-bit integer constructed by concatenating:
  71 |     |     /// `driverId (32 bits) | driverCustomData (224 bits)`.
  72 | *   |     uint8 public constant DRIVER_ID_OFFSET = 224;
  73 |     |     /// @notice The total amount the protocol can store of each token.
  74 |     |     /// It's the minimum of _MAX_STREAMS_BALANCE and _MAX_SPLITS_BALANCE.
  75 |     |     uint128 public constant MAX_TOTAL_BALANCE = _MAX_STREAMS_BALANCE;
  76 |     |     /// @notice On every timestamp `T`, which is a multiple of `cycleSecs`, the receivers
  77 |     |     /// gain access to steams received during `T - cycleSecs` to `T - 1`.
  78 |     |     /// Always higher than 1.
  79 |     |     uint32 public immutable cycleSecs;
  80 |     |     /// @notice The minimum amtPerSec of a stream. It's 1 token per cycle.
  81 | *   |     uint160 public immutable minAmtPerSec;
  82 |     |     /// @notice The ERC-1967 storage slot holding a single `DripsStorage` structure.
  83 | *   |     bytes32 private immutable _dripsStorageSlot = _erc1967Slot("eip1967.drips.storage");
  84 |     | 
  85 |     |     /// @notice Emitted when a driver is registered
  86 |     |     /// @param driverId The driver ID
  87 |     |     /// @param driverAddr The driver address
  88 |     |     event DriverRegistered(uint32 indexed driverId, address indexed driverAddr);
  89 |     | 
  90 |     |     /// @notice Emitted when a driver address is updated
  91 |     |     /// @param driverId The driver ID
  92 |     |     /// @param oldDriverAddr The old driver address
  93 |     |     /// @param newDriverAddr The new driver address
  94 |     |     event DriverAddressUpdated(
  95 |     |         uint32 indexed driverId, address indexed oldDriverAddr, address indexed newDriverAddr
  96 |     |     );
  97 |     | 
  98 |     |     /// @notice Emitted when funds are withdrawn.
  99 |     |     /// @param erc20 The used ERC-20 token.
 100 |     |     /// @param receiver The address that the funds are sent to.
 101 |     |     /// @param amt The withdrawn amount.
 102 |     |     event Withdrawn(IERC20 indexed erc20, address indexed receiver, uint256 amt);
 103 |     | 
 104 |     |     /// @notice Emitted by the account to broadcast metadata.
 105 |     |     /// The key and the value are not standardized by the protocol, it's up to the users
 106 |     |     /// to establish and follow conventions to ensure compatibility with the consumers.
 107 |     |     /// @param accountId The ID of the account emitting metadata
 108 |     |     /// @param key The metadata key
 109 |     |     /// @param value The metadata value
 110 |     |     event AccountMetadataEmitted(uint256 indexed accountId, bytes32 indexed key, bytes value);
 111 |     | 
 112 |     |     struct DripsStorage {
 113 |     |         /// @notice The next driver ID that will be used when registering.
 114 |     |         uint32 nextDriverId;
 115 |     |         /// @notice Driver addresses.
 116 |     |         mapping(uint32 driverId => address) driverAddresses;
 117 |     |         /// @notice The balance of each token currently stored in the protocol.
 118 |     |         mapping(IERC20 erc20 => Balance) balances;
 119 |     |     }
 120 |     | 
 121 |     |     /// @notice The balance currently stored in the protocol.
 122 |     |     struct Balance {
 123 |     |         /// @notice The balance currently stored in the protocol in streaming.
 124 |     |         /// It's the sum of all the funds of all the users
 125 |     |         /// that are in the streams balances, are squeezable or are receivable.
 126 |     |         uint128 streams;
 127 |     |         /// @notice The balance currently stored in the protocol in splitting.
 128 |     |         /// It's the sum of all the funds of all the users that are splittable or are collectable.
 129 |     |         uint128 splits;
 130 |     |     }
 131 |     | 
 132 |     |     /// @param cycleSecs_ The length of cycleSecs to be used in the contract instance.
 133 |     |     /// Low value makes funds more available by shortening the average time
 134 |     |     /// of funds being frozen between being taken from the accounts'
 135 |     |     /// streams balance and being receivable by their receivers.
 136 |     |     /// High value makes receiving cheaper by making it process less cycles for a given time range.
 137 |     |     /// Must be higher than 1.
 138 | *   |     constructor(uint32 cycleSecs_)
 139 | *   |         Streams(cycleSecs_, _erc1967Slot("eip1967.streams.storage"))
 140 | *   |         Splits(_erc1967Slot("eip1967.splits.storage"))
 141 |     |     {
 142 | *   |         cycleSecs = Streams._cycleSecs;
 143 | *   |         minAmtPerSec = Streams._minAmtPerSec;
 144 |     |     }
 145 |     | 
 146 |     |     /// @notice A modifier making functions callable only by the driver controlling the account.
 147 |     |     /// @param accountId The account ID.
 148 | *   |     modifier onlyDriver(uint256 accountId) {
 149 |     |         // `accountId` has value:
 150 |     |         // `driverId (32 bits) | driverCustomData (224 bits)`
 151 |     |         // By bit shifting we get value:
 152 |     |         // `zeros (224 bits) | driverId (32 bits)`
 153 |     |         // By casting down we get value:
 154 |     |         // `driverId (32 bits)`
 155 | *   |         uint32 driverId = uint32(accountId >> DRIVER_ID_OFFSET);
 156 | *   |         _assertCallerIsDriver(driverId);
 157 |     |         _;
 158 |     |     }
 159 |     | 
 160 |     |     /// @notice Verifies that the caller controls the given driver ID and reverts otherwise.
 161 |     |     /// @param driverId The driver ID.
 162 | *   |     function _assertCallerIsDriver(uint32 driverId) internal view {
 163 | *   |         require(driverAddress(driverId) == msg.sender, "Callable only by the driver");
 164 |     |     }
 165 |     | 
 166 |     |     /// @notice Registers a driver.
 167 |     |     /// The driver is assigned a unique ID and a range of account IDs it can control.
 168 |     |     /// That range consists of all 2^224 account IDs with highest 32 bits equal to the driver ID.
 169 |     |     /// Every account ID is a 256-bit integer constructed by concatenating:
 170 |     |     /// `driverId (32 bits) | driverCustomData (224 bits)`.
 171 |     |     /// Every driver ID is assigned only to a single address,
 172 |     |     /// but a single address can have multiple driver IDs assigned to it.
 173 |     |     /// @param driverAddr The address of the driver. Must not be zero address.
 174 |     |     /// It should be a smart contract capable of dealing with the Drips API.
 175 |     |     /// It shouldn't be an EOA because the API requires making multiple calls per transaction.
 176 |     |     /// @return driverId The registered driver ID.
 177 | *   |     function registerDriver(address driverAddr) public whenNotPaused returns (uint32 driverId) {
 178 | *   |         require(driverAddr != address(0), "Driver registered for 0 address");
 179 | *   |         DripsStorage storage dripsStorage = _dripsStorage();
 180 | *   |         driverId = dripsStorage.nextDriverId++;
 181 | *   |         dripsStorage.driverAddresses[driverId] = driverAddr;
 182 | *   |         emit DriverRegistered(driverId, driverAddr);
 183 |     |     }
 184 |     | 
 185 |     |     /// @notice Returns the driver address.
 186 |     |     /// @param driverId The driver ID to look up.
 187 |     |     /// @return driverAddr The address of the driver.
 188 |     |     /// If the driver hasn't been registered yet, returns address 0.
 189 | *   |     function driverAddress(uint32 driverId) public view returns (address driverAddr) {
 190 | *   |         return _dripsStorage().driverAddresses[driverId];
 191 |     |     }
 192 |     | 
 193 |     |     /// @notice Updates the driver address. Must be called from the current driver address.
 194 |     |     /// @param driverId The driver ID.
 195 |     |     /// @param newDriverAddr The new address of the driver.
 196 |     |     /// It should be a smart contract capable of dealing with the Drips API.
 197 |     |     /// It shouldn't be an EOA because the API requires making multiple calls per transaction.
 198 | *   |     function updateDriverAddress(uint32 driverId, address newDriverAddr) public whenNotPaused {
 199 | *   |         _assertCallerIsDriver(driverId);
 200 | *   |         _dripsStorage().driverAddresses[driverId] = newDriverAddr;
 201 | *   |         emit DriverAddressUpdated(driverId, msg.sender, newDriverAddr);
 202 |     |     }
 203 |     | 
 204 |     |     /// @notice Returns the driver ID which will be assigned for the next registered driver.
 205 |     |     /// @return driverId The next driver ID.
 206 |     |     function nextDriverId() public view returns (uint32 driverId) {
 207 |     |         return _dripsStorage().nextDriverId;
 208 |     |     }
 209 |     | 
 210 |     |     /// @notice Returns the amount currently stored in the protocol of the given token.
 211 |     |     /// The sum of streaming and splitting balances can never exceed `MAX_TOTAL_BALANCE`.
 212 |     |     /// The amount of tokens held by the Drips contract exceeding the sum of
 213 |     |     /// streaming and splitting balances can be `withdraw`n.
 214 |     |     /// @param erc20 The used ERC-20 token.
 215 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 216 |     |     /// an address, then later the same amount must be transferable from that address.
 217 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 218 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 219 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 220 |     |     /// @return streamsBalance The balance currently stored in the protocol in streaming.
 221 |     |     /// It's the sum of all the funds of all the users
 222 |     |     /// that are in the streams balances, are squeezable or are receivable.
 223 |     |     /// @return splitsBalance The balance currently stored in the protocol in splitting.
 224 |     |     /// It's the sum of all the funds of all the users that are splittable or are collectable.
 225 | *   |     function balances(IERC20 erc20)
 226 |     |         public
 227 |     |         view
 228 | *   |         returns (uint128 streamsBalance, uint128 splitsBalance)
 229 |     |     {
 230 | *   |         Balance storage balance = _dripsStorage().balances[erc20];
 231 | *   |         return (balance.streams, balance.splits);
 232 |     |     }
 233 |     | 
 234 |     |     /// @notice Increases the balance of the given token currently stored in streams.
 235 |     |     /// No funds are transferred, all the tokens are expected to be already held by Drips.
 236 |     |     /// The new total balance is verified to have coverage in the held tokens
 237 |     |     /// and to be within the limit of `MAX_TOTAL_BALANCE`.
 238 |     |     /// @param erc20 The used ERC-20 token.
 239 |     |     /// @param amt The amount to increase the streams balance by.
 240 | *   |     function _increaseStreamsBalance(IERC20 erc20, uint128 amt) internal {
 241 | *   |         _verifyBalanceIncrease(erc20, amt);
 242 | *   |         _dripsStorage().balances[erc20].streams += amt;
 243 |     |     }
 244 |     | 
 245 |     |     /// @notice Decreases the balance of the given token currently stored in streams.
 246 |     |     /// No funds are transferred, but the tokens held by Drips
 247 |     |     /// above the total balance become withdrawable.
 248 |     |     /// @param erc20 The used ERC-20 token.
 249 |     |     /// @param amt The amount to decrease the streams balance by.
 250 | *   |     function _decreaseStreamsBalance(IERC20 erc20, uint128 amt) internal {
 251 | *   |         _dripsStorage().balances[erc20].streams -= amt;
 252 |     |     }
 253 |     | 
 254 |     |     /// @notice Increases the balance of the given token currently stored in splits.
 255 |     |     /// No funds are transferred, all the tokens are expected to be already held by Drips.
 256 |     |     /// The new total balance is verified to have coverage in the held tokens
 257 |     |     /// and to be within the limit of `MAX_TOTAL_BALANCE`.
 258 |     |     /// @param erc20 The used ERC-20 token.
 259 |     |     /// @param amt The amount to increase the splits balance by.
 260 | *   |     function _increaseSplitsBalance(IERC20 erc20, uint128 amt) internal {
 261 | *   |         _verifyBalanceIncrease(erc20, amt);
 262 | *   |         _dripsStorage().balances[erc20].splits += amt;
 263 |     |     }
 264 |     | 
 265 |     |     /// @notice Decreases the balance of the given token currently stored in splits.
 266 |     |     /// No funds are transferred, but the tokens held by Drips
 267 |     |     /// above the total balance become withdrawable.
 268 |     |     /// @param erc20 The used ERC-20 token.
 269 |     |     /// @param amt The amount to decrease the splits balance by.
 270 | *   |     function _decreaseSplitsBalance(IERC20 erc20, uint128 amt) internal {
 271 | *   |         _dripsStorage().balances[erc20].splits -= amt;
 272 |     |     }
 273 |     | 
 274 |     |     /// @notice Moves the balance of the given token currently stored in streams to splits.
 275 |     |     /// No funds are transferred, all the tokens are already held by Drips.
 276 |     |     /// @param erc20 The used ERC-20 token.
 277 |     |     /// @param amt The amount to decrease the splits balance by.
 278 | *   |     function _moveBalanceFromStreamsToSplits(IERC20 erc20, uint128 amt) internal {
 279 | *   |         Balance storage balance = _dripsStorage().balances[erc20];
 280 | *   |         balance.streams -= amt;
 281 | *   |         balance.splits += amt;
 282 |     |     }
 283 |     | 
 284 |     |     /// @notice Verifies that the balance of streams or splits can be increased by the given amount.
 285 |     |     /// The sum of streaming and splitting balances is checked to not exceed
 286 |     |     /// `MAX_TOTAL_BALANCE` or the amount of tokens held by the Drips.
 287 |     |     /// @param erc20 The used ERC-20 token.
 288 |     |     /// @param amt The amount to increase the streams or splits balance by.
 289 | *   |     function _verifyBalanceIncrease(IERC20 erc20, uint128 amt) internal view {
 290 | *   |         (uint256 streamsBalance, uint128 splitsBalance) = balances(erc20);
 291 | *   |         uint256 newTotalBalance = streamsBalance + splitsBalance + amt;
 292 | *   |         require(newTotalBalance <= MAX_TOTAL_BALANCE, "Total balance too high");
 293 | *   |         require(newTotalBalance <= _tokenBalance(erc20), "Token balance too low");
 294 |     |     }
 295 |     | 
 296 |     |     /// @notice Transfers withdrawable funds to an address.
 297 |     |     /// The withdrawable funds are held by the Drips contract,
 298 |     |     /// but not used in the protocol, so they are free to be transferred out.
 299 |     |     /// Anybody can call `withdraw`, so all withdrawable funds should be withdrawn
 300 |     |     /// or used in the protocol before any 3rd parties have a chance to do that.
 301 |     |     /// @param erc20 The used ERC-20 token.
 302 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 303 |     |     /// an address, then later the same amount must be transferable from that address.
 304 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 305 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 306 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 307 |     |     /// @param receiver The address to send withdrawn funds to.
 308 |     |     /// @param amt The withdrawn amount.
 309 |     |     /// It must be at most the difference between the balance of the token held by the Drips
 310 |     |     /// contract address and the sum of balances managed by the protocol as indicated by `balances`.
 311 | *   |     function withdraw(IERC20 erc20, address receiver, uint256 amt) public {
 312 | *   |         (uint128 streamsBalance, uint128 splitsBalance) = balances(erc20);
 313 | *   |         uint256 withdrawable = _tokenBalance(erc20) - streamsBalance - splitsBalance;
 314 | *   |         require(amt <= withdrawable, "Withdrawal amount too high");
 315 | *   |         emit Withdrawn(erc20, receiver, amt);
 316 | *   |         erc20.safeTransfer(receiver, amt);
 317 |     |     }
 318 |     | 
 319 | *   |     function _tokenBalance(IERC20 erc20) internal view returns (uint256) {
 320 | *   |         return erc20.balanceOf(address(this));
 321 |     |     }
 322 |     | 
 323 |     |     /// @notice Counts cycles from which streams can be collected.
 324 |     |     /// This function can be used to detect that there are
 325 |     |     /// too many cycles to analyze in a single transaction.
 326 |     |     /// @param accountId The account ID.
 327 |     |     /// @param erc20 The used ERC-20 token.
 328 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 329 |     |     /// an address, then later the same amount must be transferable from that address.
 330 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 331 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 332 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 333 |     |     /// @return cycles The number of cycles which can be flushed
 334 | *   |     function receivableStreamsCycles(uint256 accountId, IERC20 erc20)
 335 |     |         public
 336 |     |         view
 337 | *   |         returns (uint32 cycles)
 338 |     |     {
 339 | *   |         return Streams._receivableStreamsCycles(accountId, erc20);
 340 |     |     }
 341 |     | 
 342 |     |     /// @notice Calculate effects of calling `receiveStreams` with the given parameters.
 343 |     |     /// @param accountId The account ID.
 344 |     |     /// @param erc20 The used ERC-20 token.
 345 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 346 |     |     /// an address, then later the same amount must be transferable from that address.
 347 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 348 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 349 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 350 |     |     /// @param maxCycles The maximum number of received streams cycles.
 351 |     |     /// If too low, receiving will be cheap, but may not cover many cycles.
 352 |     |     /// If too high, receiving may become too expensive to fit in a single transaction.
 353 |     |     /// @return receivableAmt The amount which would be received
 354 | *   |     function receiveStreamsResult(uint256 accountId, IERC20 erc20, uint32 maxCycles)
 355 |     |         public
 356 |     |         view
 357 | *   |         returns (uint128 receivableAmt)
 358 |     |     {
 359 | *   |         (receivableAmt,,,,) = Streams._receiveStreamsResult(accountId, erc20, maxCycles);
 360 |     |     }
 361 |     | 
 362 |     |     /// @notice Receive streams for the account.
 363 |     |     /// Received streams cycles won't need to be analyzed ever again.
 364 |     |     /// Calling this function does not collect but makes the funds ready to be split and collected.
 365 |     |     /// @param accountId The account ID.
 366 |     |     /// @param erc20 The used ERC-20 token.
 367 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 368 |     |     /// an address, then later the same amount must be transferable from that address.
 369 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 370 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 371 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 372 |     |     /// @param maxCycles The maximum number of received streams cycles.
 373 |     |     /// If too low, receiving will be cheap, but may not cover many cycles.
 374 |     |     /// If too high, receiving may become too expensive to fit in a single transaction.
 375 |     |     /// @return receivedAmt The received amount
 376 | *   |     function receiveStreams(uint256 accountId, IERC20 erc20, uint32 maxCycles)
 377 |     |         public
 378 |     |         whenNotPaused
 379 | *   |         returns (uint128 receivedAmt)
 380 |     |     {
 381 | *   |         receivedAmt = Streams._receiveStreams(accountId, erc20, maxCycles);
 382 | *   |         if (receivedAmt != 0) {
 383 | *   |             _moveBalanceFromStreamsToSplits(erc20, receivedAmt);
 384 | *   |             Splits._addSplittable(accountId, erc20, receivedAmt);
 385 |     |         }
 386 |     |     }
 387 |     | 
 388 |     |     /// @notice Receive streams from the currently running cycle from a single sender.
 389 |     |     /// It doesn't receive streams from the finished cycles, to do that use `receiveStreams`.
 390 |     |     /// Squeezed funds won't be received in the next calls to `squeezeStreams` or `receiveStreams`.
 391 |     |     /// Only funds streamed before `block.timestamp` can be squeezed.
 392 |     |     /// @param accountId The ID of the account receiving streams to squeeze funds for.
 393 |     |     /// @param erc20 The used ERC-20 token.
 394 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 395 |     |     /// an address, then later the same amount must be transferable from that address.
 396 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 397 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 398 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 399 |     |     /// @param senderId The ID of the streaming account to squeeze funds from.
 400 |     |     /// @param historyHash The sender's history hash that was valid right before
 401 |     |     /// they set up the sequence of configurations described by `streamsHistory`.
 402 |     |     /// @param streamsHistory The sequence of the sender's streams configurations.
 403 |     |     /// It can start at an arbitrary past configuration, but must describe all the configurations
 404 |     |     /// which have been used since then including the current one, in the chronological order.
 405 |     |     /// Only streams described by `streamsHistory` will be squeezed.
 406 |     |     /// If `streamsHistory` entries have no receivers, they won't be squeezed.
 407 |     |     /// @return amt The squeezed amount.
 408 | *   |     function squeezeStreams(
 409 |     |         uint256 accountId,
 410 |     |         IERC20 erc20,
 411 |     |         uint256 senderId,
 412 |     |         bytes32 historyHash,
 413 |     |         StreamsHistory[] memory streamsHistory
 414 | *   |     ) public whenNotPaused returns (uint128 amt) {
 415 | *   |         amt = Streams._squeezeStreams(accountId, erc20, senderId, historyHash, streamsHistory);
 416 | *   |         if (amt != 0) {
 417 | *   |             _moveBalanceFromStreamsToSplits(erc20, amt);
 418 | *   |             Splits._addSplittable(accountId, erc20, amt);
 419 |     |         }
 420 |     |     }
 421 |     | 
 422 |     |     /// @notice Calculate effects of calling `squeezeStreams` with the given parameters.
 423 |     |     /// See its documentation for more details.
 424 |     |     /// @param accountId The ID of the account receiving streams to squeeze funds for.
 425 |     |     /// @param erc20 The used ERC-20 token.
 426 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 427 |     |     /// an address, then later the same amount must be transferable from that address.
 428 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 429 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 430 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 431 |     |     /// @param senderId The ID of the streaming account to squeeze funds from.
 432 |     |     /// @param historyHash The sender's history hash that was valid right before `streamsHistory`.
 433 |     |     /// @param streamsHistory The sequence of the sender's streams configurations.
 434 |     |     /// @return amt The squeezed amount.
 435 | *   |     function squeezeStreamsResult(
 436 |     |         uint256 accountId,
 437 |     |         IERC20 erc20,
 438 |     |         uint256 senderId,
 439 |     |         bytes32 historyHash,
 440 |     |         StreamsHistory[] memory streamsHistory
 441 | *   |     ) public view returns (uint128 amt) {
 442 | *   |         (amt,,,,) =
 443 | *   |             Streams._squeezeStreamsResult(accountId, erc20, senderId, historyHash, streamsHistory);
 444 |     |     }
 445 |     | 
 446 |     |     /// @notice Returns account's received but not split yet funds.
 447 |     |     /// @param accountId The account ID.
 448 |     |     /// @param erc20 The used ERC-20 token.
 449 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 450 |     |     /// an address, then later the same amount must be transferable from that address.
 451 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 452 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 453 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 454 |     |     /// @return amt The amount received but not split yet.
 455 | *   |     function splittable(uint256 accountId, IERC20 erc20) public view returns (uint128 amt) {
 456 | *   |         return Splits._splittable(accountId, erc20);
 457 |     |     }
 458 |     | 
 459 |     |     /// @notice Calculate the result of splitting an amount using the current splits configuration.
 460 |     |     /// Fractions of tokens are always rounder either up or down depending on the amount
 461 |     |     /// being split, the receiver's position on the list and the other receivers' weights.
 462 |     |     /// @param accountId The account ID.
 463 |     |     /// @param currReceivers The list of the account's current splits receivers.
 464 |     |     /// It must be exactly the same as the last list set for the account with `setSplits`.
 465 |     |     /// If the splits have never been set, pass an empty array.
 466 |     |     /// @param amount The amount being split.
 467 |     |     /// @return collectableAmt The amount made collectable for the account
 468 |     |     /// on top of what was collectable before.
 469 |     |     /// @return splitAmt The amount split to the account's splits receivers
 470 | *   |     function splitResult(uint256 accountId, SplitsReceiver[] memory currReceivers, uint128 amount)
 471 |     |         public
 472 |     |         view
 473 | *   |         returns (uint128 collectableAmt, uint128 splitAmt)
 474 |     |     {
 475 | *   |         return Splits._splitResult(accountId, currReceivers, amount);
 476 |     |     }
 477 |     | 
 478 |     |     /// @notice Splits the account's splittable funds among receivers.
 479 |     |     /// The entire splittable balance of the given ERC-20 token is split.
 480 |     |     /// Fractions of tokens are always rounder either up or down depending on the amount
 481 |     |     /// being split, the receiver's position on the list and the other receivers' weights.
 482 |     |     /// All split funds are split using the current splits configuration.
 483 |     |     /// Because the account can update their splits configuration at any time,
 484 |     |     /// it is possible that calling this function will be frontrun,
 485 |     |     /// and all the splittable funds will become splittable only using the new configuration.
 486 |     |     /// The account must be trusted with how funds sent to them will be splits,
 487 |     |     /// in the end they can do with their funds whatever they want by changing the configuration.
 488 |     |     /// @param accountId The account ID.
 489 |     |     /// @param erc20 The used ERC-20 token.
 490 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 491 |     |     /// an address, then later the same amount must be transferable from that address.
 492 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 493 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 494 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 495 |     |     /// @param currReceivers The list of the account's current splits receivers.
 496 |     |     /// It must be exactly the same as the last list set for the account with `setSplits`.
 497 |     |     /// If the splits have never been set, pass an empty array.
 498 |     |     /// @return collectableAmt The amount made collectable for the account
 499 |     |     /// on top of what was collectable before.
 500 |     |     /// @return splitAmt The amount split to the account's splits receivers
 501 | *   |     function split(uint256 accountId, IERC20 erc20, SplitsReceiver[] memory currReceivers)
 502 |     |         public
 503 |     |         whenNotPaused
 504 | *   |         returns (uint128 collectableAmt, uint128 splitAmt)
 505 |     |     {
 506 | *   |         return Splits._split(accountId, erc20, currReceivers);
 507 |     |     }
 508 |     | 
 509 |     |     /// @notice Returns account's received funds already split and ready to be collected.
 510 |     |     /// @param accountId The account ID.
 511 |     |     /// @param erc20 The used ERC-20 token.
 512 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 513 |     |     /// an address, then later the same amount must be transferable from that address.
 514 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 515 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 516 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 517 |     |     /// @return amt The collectable amount.
 518 | *   |     function collectable(uint256 accountId, IERC20 erc20) public view returns (uint128 amt) {
 519 | *   |         return Splits._collectable(accountId, erc20);
 520 |     |     }
 521 |     | 
 522 |     |     /// @notice Collects account's received already split funds and makes them withdrawable.
 523 |     |     /// Anybody can call `withdraw`, so all withdrawable funds should be withdrawn
 524 |     |     /// or used in the protocol before any 3rd parties have a chance to do that.
 525 |     |     /// @param accountId The account ID.
 526 |     |     /// @param erc20 The used ERC-20 token.
 527 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 528 |     |     /// an address, then later the same amount must be transferable from that address.
 529 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 530 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 531 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 532 |     |     /// @return amt The collected amount
 533 | *   |     function collect(uint256 accountId, IERC20 erc20)
 534 |     |         public
 535 |     |         whenNotPaused
 536 | *   |         onlyDriver(accountId)
 537 | *   |         returns (uint128 amt)
 538 |     |     {
 539 | *   |         amt = Splits._collect(accountId, erc20);
 540 | *   |         if (amt != 0) _decreaseSplitsBalance(erc20, amt);
 541 |     |     }
 542 |     | 
 543 |     |     /// @notice Gives funds from the account to the receiver.
 544 |     |     /// The receiver can split and collect them immediately.
 545 |     |     /// Requires that the tokens used to give are already sent to Drips and are withdrawable.
 546 |     |     /// Anybody can call `withdraw`, so all withdrawable funds should be withdrawn
 547 |     |     /// or used in the protocol before any 3rd parties have a chance to do that.
 548 |     |     /// @param accountId The account ID.
 549 |     |     /// @param receiver The receiver account ID.
 550 |     |     /// @param erc20 The used ERC-20 token.
 551 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 552 |     |     /// an address, then later the same amount must be transferable from that address.
 553 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 554 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 555 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 556 |     |     /// @param amt The given amount
 557 | *   |     function give(uint256 accountId, uint256 receiver, IERC20 erc20, uint128 amt)
 558 |     |         public
 559 |     |         whenNotPaused
 560 | *   |         onlyDriver(accountId)
 561 |     |     {
 562 | *   |         if (amt != 0) _increaseSplitsBalance(erc20, amt);
 563 | *   |         Splits._give(accountId, receiver, erc20, amt);
 564 |     |     }
 565 |     | 
 566 |     |     /// @notice Current account streams state.
 567 |     |     /// @param accountId The account ID.
 568 |     |     /// @param erc20 The used ERC-20 token.
 569 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 570 |     |     /// an address, then later the same amount must be transferable from that address.
 571 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 572 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 573 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 574 |     |     /// @return streamsHash The current streams receivers list hash, see `hashStreams`
 575 |     |     /// @return streamsHistoryHash The current streams history hash, see `hashStreamsHistory`.
 576 |     |     /// @return updateTime The time when streams have been configured for the last time.
 577 |     |     /// @return balance The balance when streams have been configured for the last time.
 578 |     |     /// @return maxEnd The current maximum end time of streaming.
 579 | *   |     function streamsState(uint256 accountId, IERC20 erc20)
 580 |     |         public
 581 |     |         view
 582 |     |         returns (
 583 | *   |             bytes32 streamsHash,
 584 | *   |             bytes32 streamsHistoryHash,
 585 | *   |             uint32 updateTime,
 586 | *   |             uint128 balance,
 587 | *   |             uint32 maxEnd
 588 |     |         )
 589 |     |     {
 590 | *   |         return Streams._streamsState(accountId, erc20);
 591 |     |     }
 592 |     | 
 593 |     |     /// @notice The account's streams balance at the given timestamp.
 594 |     |     /// @param accountId The account ID.
 595 |     |     /// @param erc20 The used ERC-20 token.
 596 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 597 |     |     /// an address, then later the same amount must be transferable from that address.
 598 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 599 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 600 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 601 |     |     /// @param currReceivers The current streams receivers list.
 602 |     |     /// It must be exactly the same as the last list set for the account with `setStreams`.
 603 |     |     /// @param timestamp The timestamp for which balance should be calculated.
 604 |     |     /// It can't be lower than the timestamp of the last call to `setStreams`.
 605 |     |     /// If it's bigger than `block.timestamp`, then it's a prediction assuming
 606 |     |     /// that `setStreams` won't be called before `timestamp`.
 607 |     |     /// @return balance The account balance on `timestamp`
 608 | *   |     function balanceAt(
 609 |     |         uint256 accountId,
 610 |     |         IERC20 erc20,
 611 |     |         StreamReceiver[] memory currReceivers,
 612 |     |         uint32 timestamp
 613 | *   |     ) public view returns (uint128 balance) {
 614 | *   |         return Streams._balanceAt(accountId, erc20, currReceivers, timestamp);
 615 |     |     }
 616 |     | 
 617 |     |     /// @notice Sets the account's streams configuration.
 618 |     |     /// Requires that the tokens used to increase the streams balance
 619 |     |     /// are already sent to Drips and are withdrawable.
 620 |     |     /// If the streams balance is decreased, the released tokens become withdrawable.
 621 |     |     /// Anybody can call `withdraw`, so all withdrawable funds should be withdrawn
 622 |     |     /// or used in the protocol before any 3rd parties have a chance to do that.
 623 |     |     /// @param accountId The account ID.
 624 |     |     /// @param erc20 The used ERC-20 token.
 625 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
 626 |     |     /// an address, then later the same amount must be transferable from that address.
 627 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
 628 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
 629 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
 630 |     |     /// @param currReceivers The current streams receivers list.
 631 |     |     /// It must be exactly the same as the last list set for the account with `setStreams`.
 632 |     |     /// If this is the first update, pass an empty array.
 633 |     |     /// @param balanceDelta The streams balance change to be applied.
 634 |     |     /// If it's positive, the balance is increased by `balanceDelta`.
 635 |     |     /// If it's zero, the balance doesn't change.
 636 |     |     /// If it's negative, the balance is decreased by `balanceDelta`,
 637 |     |     /// but the change is capped at the current balance amount, so it doesn't go below 0.
 638 |     |     /// Passing `type(int128).min` always decreases the current balance to 0.
 639 |     |     /// @param newReceivers The list of the streams receivers of the account to be set.
 640 |     |     /// Must be sorted by the account IDs and then by the stream configurations,
 641 |     |     /// without identical elements and without 0 amtPerSecs.
 642 |     |     /// @param maxEndHint1 An optional parameter allowing gas optimization, pass `0` to ignore it.
 643 |     |     /// The first hint for finding the maximum end time when all streams stop due to funds
 644 |     |     /// running out after the balance is updated and the new receivers list is applied.
 645 |     |     /// Hints have no effect on the results of calling this function, except potentially saving gas.
 646 |     |     /// Hints are Unix timestamps used as the starting points for binary search for the time
 647 |     |     /// when funds run out in the range of timestamps from the current block's to `2^32`.
 648 |     |     /// Hints lower than the current timestamp are ignored.
 649 |     |     /// You can provide zero, one or two hints. The order of hints doesn't matter.
 650 |     |     /// Hints are the most effective when one of them is lower than or equal to
 651 |     |     /// the last timestamp when funds are still streamed, and the other one is strictly larger
 652 |     |     /// than that timestamp,the smaller the difference between such hints, the higher gas savings.
 653 |     |     /// The savings are the highest possible when one of the hints is equal to
 654 |     |     /// the last timestamp when funds are still streamed, and the other one is larger by 1.
 655 |     |     /// It's worth noting that the exact timestamp of the block in which this function is executed
 656 |     |     /// may affect correctness of the hints, especially if they're precise.
 657 |     |     /// Hints don't provide any benefits when balance is not enough to cover
 658 |     |     /// a single second of streaming or is enough to cover all streams until timestamp `2^32`.
 659 |     |     /// Even inaccurate hints can be useful, and providing a single hint
 660 |     |     /// or two hints that don't enclose the time when funds run out can still save some gas.
 661 |     |     /// Providing poor hints that don't reduce the number of binary search steps
 662 |     |     /// may cause slightly higher gas usage than not providing any hints.
 663 |     |     /// @param maxEndHint2 An optional parameter allowing gas optimization, pass `0` to ignore it.
 664 |     |     /// The second hint for finding the maximum end time, see `maxEndHint1` docs for more details.
 665 |     |     /// @return realBalanceDelta The actually applied streams balance change.
 666 |     |     /// It's equal to the passed `balanceDelta`, unless it's negative
 667 |     |     /// and it gets capped at the current balance amount.
 668 |     |     /// If it's lower than zero, it's the negative of the amount that became withdrawable.
 669 | *   |     function setStreams(
 670 |     |         uint256 accountId,
 671 |     |         IERC20 erc20,
 672 |     |         StreamReceiver[] memory currReceivers,
 673 |     |         int128 balanceDelta,
 674 |     |         StreamReceiver[] memory newReceivers,
 675 |     |         // slither-disable-next-line similar-names
 676 |     |         uint32 maxEndHint1,
 677 |     |         uint32 maxEndHint2
 678 | *   |     ) public whenNotPaused onlyDriver(accountId) returns (int128 realBalanceDelta) {
 679 | *   |         if (balanceDelta > 0) _increaseStreamsBalance(erc20, uint128(balanceDelta));
 680 | *   |         realBalanceDelta = Streams._setStreams(
 681 | *   |             accountId, erc20, currReceivers, balanceDelta, newReceivers, maxEndHint1, maxEndHint2
 682 |     |         );
 683 | *   |         if (realBalanceDelta < 0) _decreaseStreamsBalance(erc20, uint128(-realBalanceDelta));
 684 |     |     }
 685 |     | 
 686 |     |     /// @notice Calculates the hash of the streams configuration.
 687 |     |     /// It's used to verify if streams configuration is the previously set one.
 688 |     |     /// @param receivers The list of the streams receivers.
 689 |     |     /// Must be sorted by the account IDs and then by the stream configurations,
 690 |     |     /// without identical elements and without 0 amtPerSecs.
 691 |     |     /// If the streams have never been set, pass an empty array.
 692 |     |     /// @return streamsHash The hash of the streams configuration
 693 | *   |     function hashStreams(StreamReceiver[] memory receivers)
 694 |     |         public
 695 |     |         pure
 696 | *   |         returns (bytes32 streamsHash)
 697 |     |     {
 698 | *   |         return Streams._hashStreams(receivers);
 699 |     |     }
 700 |     | 
 701 |     |     /// @notice Calculates the hash of the streams history
 702 |     |     /// after the streams configuration is updated.
 703 |     |     /// @param oldStreamsHistoryHash The history hash
 704 |     |     /// that was valid before the streams were updated.
 705 |     |     /// The `streamsHistoryHash` of the account before they set streams for the first time is `0`.
 706 |     |     /// @param streamsHash The hash of the streams receivers being set.
 707 |     |     /// @param updateTime The timestamp when the streams were updated.
 708 |     |     /// @param maxEnd The maximum end of the streams being set.
 709 |     |     /// @return streamsHistoryHash The hash of the updated streams history.
 710 | *   |     function hashStreamsHistory(
 711 |     |         bytes32 oldStreamsHistoryHash,
 712 |     |         bytes32 streamsHash,
 713 |     |         uint32 updateTime,
 714 |     |         uint32 maxEnd
 715 | *   |     ) public pure returns (bytes32 streamsHistoryHash) {
 716 | *   |         return Streams._hashStreamsHistory(oldStreamsHistoryHash, streamsHash, updateTime, maxEnd);
 717 |     |     }
 718 |     | 
 719 |     |     /// @notice Sets the account splits configuration.
 720 |     |     /// The configuration is common for all ERC-20 tokens.
 721 |     |     /// Nothing happens to the currently splittable funds, but when they are split
 722 |     |     /// after this function finishes, the new splits configuration will be used.
 723 |     |     /// Because anybody can call `split`, calling this function may be frontrun
 724 |     |     /// and all the currently splittable funds will be split using the old splits configuration.
 725 |     |     /// @param accountId The account ID.
 726 |     |     /// @param receivers The list of the account's splits receivers to be set.
 727 |     |     /// Must be sorted by the account IDs, without duplicate account IDs and without 0 weights.
 728 |     |     /// Each splits receiver will be getting `weight / TOTAL_SPLITS_WEIGHT`
 729 |     |     /// share of the funds collected by the account.
 730 |     |     /// If the sum of weights of all receivers is less than `_TOTAL_SPLITS_WEIGHT`,
 731 |     |     /// some funds won't be split, but they will be left for the account to collect.
 732 |     |     /// Fractions of tokens are always rounder either up or down depending on the amount
 733 |     |     /// being split, the receiver's position on the list and the other receivers' weights.
 734 |     |     /// It's valid to include the account's own `accountId` in the list of receivers,
 735 |     |     /// but funds split to themselves return to their splittable balance and are not collectable.
 736 |     |     /// This is usually unwanted, because if splitting is repeated,
 737 |     |     /// funds split to themselves will be again split using the current configuration.
 738 |     |     /// Splitting 100% to self effectively blocks splitting unless the configuration is updated.
 739 | *   |     function setSplits(uint256 accountId, SplitsReceiver[] memory receivers)
 740 |     |         public
 741 |     |         whenNotPaused
 742 | *   |         onlyDriver(accountId)
 743 |     |     {
 744 | *   |         Splits._setSplits(accountId, receivers);
 745 |     |     }
 746 |     | 
 747 |     |     /// @notice Current account's splits hash, see `hashSplits`.
 748 |     |     /// @param accountId The account ID.
 749 |     |     /// @return currSplitsHash The current account's splits hash
 750 |     |     function splitsHash(uint256 accountId) public view returns (bytes32 currSplitsHash) {
 751 |     |         return Splits._splitsHash(accountId);
 752 |     |     }
 753 |     | 
 754 |     |     /// @notice Calculates the hash of the list of splits receivers.
 755 |     |     /// @param receivers The list of the splits receivers.
 756 |     |     /// Must be sorted by the account IDs, without duplicate account IDs and without 0 weights.
 757 |     |     /// @return receiversHash The hash of the list of splits receivers.
 758 |     |     function hashSplits(SplitsReceiver[] memory receivers)
 759 |     |         public
 760 |     |         pure
 761 |     |         returns (bytes32 receiversHash)
 762 |     |     {
 763 |     |         return Splits._hashSplits(receivers);
 764 |     |     }
 765 |     | 
 766 |     |     /// @notice Emits account metadata.
 767 |     |     /// The keys and the values are not standardized by the protocol, it's up to the users
 768 |     |     /// to establish and follow conventions to ensure compatibility with the consumers.
 769 |     |     /// @param accountId The account ID.
 770 |     |     /// @param accountMetadata The list of account metadata.
 771 |     |     function emitAccountMetadata(uint256 accountId, AccountMetadata[] calldata accountMetadata)
 772 |     |         public
 773 |     |         whenNotPaused
 774 |     |         onlyDriver(accountId)
 775 |     |     {
 776 |     |         unchecked {
 777 |     |             for (uint256 i = 0; i < accountMetadata.length; i++) {
 778 |     |                 AccountMetadata calldata metadata = accountMetadata[i];
 779 |     |                 emit AccountMetadataEmitted(accountId, metadata.key, metadata.value);
 780 |     |             }
 781 |     |         }
 782 |     |     }
 783 |     | 
 784 |     |     /// @notice Returns the Drips storage.
 785 |     |     /// @return storageRef The storage.
 786 | *   |     function _dripsStorage() internal view returns (DripsStorage storage storageRef) {
 787 | *   |         bytes32 slot = _dripsStorageSlot;
 788 |     |         // slither-disable-next-line assembly
 789 | *   |         assembly {
 790 | *   |             storageRef.slot := slot
 791 |     |         }
 792 |     |     }
 793 |     | }
 794 |     | 

/opt/scfuzzbench/work/target/src/DriverTransferUtils.sol
   1 |     | // SPDX-License-Identifier: GPL-3.0-only
   2 |     | pragma solidity ^0.8.20;
   3 |     | 
   4 |     | import {Drips, StreamReceiver, IERC20, SafeERC20} from "./Drips.sol";
   5 |     | import {ERC2771Context} from "openzeppelin-contracts/metatx/ERC2771Context.sol";
   6 |     | 
   7 |     | /// @notice ERC-20 token transfer utilities for drivers.
   8 |     | /// Encapsulates the logic for token transfers made by drivers implementing user identities.
   9 |     | /// All funds going into Drips are transferred ad-hoc from the caller (`msg.sender`),
  10 |     | /// and all funds going out of Drips are transferred in full to the provided address.
  11 |     | /// Compatible with `Caller` by supporting ERC-2771.
  12 |     | abstract contract DriverTransferUtils is ERC2771Context {
  13 |     |     /// @param forwarder The ERC-2771 forwarder to trust. May be the zero address.
  14 | *   |     constructor(address forwarder) ERC2771Context(forwarder) {}
  15 |     | 
  16 |     |     /// @notice Collects the account's received already split funds
  17 |     |     /// and transfers them out of the Drips contract.
  18 |     |     /// @param drips The Drips contract to use.
  19 |     |     /// @param erc20 The used ERC-20 token.
  20 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
  21 |     |     /// an address, then later the same amount must be transferable from that address.
  22 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
  23 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
  24 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
  25 |     |     /// @param transferTo The address to send collected funds to
  26 |     |     /// @return amt The collected amount
  27 | *   |     function _collectAndTransfer(Drips drips, uint256 accountId, IERC20 erc20, address transferTo)
  28 |     |         internal
  29 | *   |         returns (uint128 amt)
  30 |     |     {
  31 | *   |         amt = drips.collect(accountId, erc20);
  32 | *   |         if (amt > 0) drips.withdraw(erc20, transferTo, amt);
  33 |     |     }
  34 |     | 
  35 |     |     /// @notice Gives funds from the message sender to the receiver.
  36 |     |     /// The receiver can split and collect them immediately.
  37 |     |     /// Transfers the funds to be given from the message sender's wallet to the Drips contract.
  38 |     |     /// @param drips The Drips contract to use.
  39 |     |     /// @param receiver The receiver account ID.
  40 |     |     /// @param erc20 The used ERC-20 token.
  41 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
  42 |     |     /// an address, then later the same amount must be transferable from that address.
  43 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
  44 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
  45 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
  46 |     |     /// @param amt The given amount
  47 | *   |     function _giveAndTransfer(
  48 |     |         Drips drips,
  49 |     |         uint256 accountId,
  50 |     |         uint256 receiver,
  51 |     |         IERC20 erc20,
  52 |     |         uint128 amt
  53 |     |     ) internal {
  54 | *   |         if (amt > 0) _transferFromCaller(drips, erc20, amt);
  55 | *   |         drips.give(accountId, receiver, erc20, amt);
  56 |     |     }
  57 |     | 
  58 |     |     /// @notice Sets the message sender's streams configuration.
  59 |     |     /// Transfers funds between the message sender's wallet and the Drips contract
  60 |     |     /// to fulfil the change of the streams balance.
  61 |     |     /// @param drips The Drips contract to use.
  62 |     |     /// @param erc20 The used ERC-20 token.
  63 |     |     /// It must preserve amounts, so if some amount of tokens is transferred to
  64 |     |     /// an address, then later the same amount must be transferable from that address.
  65 |     |     /// Tokens which rebase the holders' balances, collect taxes on transfers,
  66 |     |     /// or impose any restrictions on holding or transferring tokens are not supported.
  67 |     |     /// If you use such tokens in the protocol, they can get stuck or lost.
  68 |     |     /// @param currReceivers The current streams receivers list.
  69 |     |     /// It must be exactly the same as the last list set for the sender with `setStreams`.
  70 |     |     /// If this is the first update, pass an empty array.
  71 |     |     /// @param balanceDelta The streams balance change to be applied.
  72 |     |     /// If it's positive, the balance is increased by `balanceDelta`.
  73 |     |     /// If it's zero, the balance doesn't change.
  74 |     |     /// If it's negative, the balance is decreased by `balanceDelta`,
  75 |     |     /// but the change is capped at the current balance amount, so it doesn't go below 0.
  76 |     |     /// Passing `type(int128).min` always decreases the current balance to 0.
  77 |     |     /// @param newReceivers The list of the streams receivers of the sender to be set.
  78 |     |     /// Must be sorted by the account IDs and then by the stream configurations,
  79 |     |     /// without identical elements and without 0 amtPerSecs.
  80 |     |     /// @param maxEndHint1 An optional parameter allowing gas optimization, pass `0` to ignore it.
  81 |     |     /// The first hint for finding the maximum end time when all streams stop due to funds
  82 |     |     /// running out after the balance is updated and the new receivers list is applied.
  83 |     |     /// Hints have no effect on the results of calling this function, except potentially saving gas.
  84 |     |     /// Hints are Unix timestamps used as the starting points for binary search for the time
  85 |     |     /// when funds run out in the range of timestamps from the current block's to `2^32`.
  86 |     |     /// Hints lower than the current timestamp are ignored.
  87 |     |     /// You can provide zero, one or two hints. The order of hints doesn't matter.
  88 |     |     /// Hints are the most effective when one of them is lower than or equal to
  89 |     |     /// the last timestamp when funds are still streamed, and the other one is strictly larger
  90 |     |     /// than that timestamp,the smaller the difference between such hints, the higher gas savings.
  91 |     |     /// The savings are the highest possible when one of the hints is equal to
  92 |     |     /// the last timestamp when funds are still streamed, and the other one is larger by 1.
  93 |     |     /// It's worth noting that the exact timestamp of the block in which this function is executed
  94 |     |     /// may affect correctness of the hints, especially if they're precise.
  95 |     |     /// Hints don't provide any benefits when balance is not enough to cover
  96 |     |     /// a single second of streaming or is enough to cover all streams until timestamp `2^32`.
  97 |     |     /// Even inaccurate hints can be useful, and providing a single hint
  98 |     |     /// or two hints that don't enclose the time when funds run out can still save some gas.
  99 |     |     /// Providing poor hints that don't reduce the number of binary search steps
 100 |     |     /// may cause slightly higher gas usage than not providing any hints.
 101 |     |     /// @param maxEndHint2 An optional parameter allowing gas optimization, pass `0` to ignore it.
 102 |     |     /// The second hint for finding the maximum end time, see `maxEndHint1` docs for more details.
 103 |     |     /// @param transferTo The address to send funds to in case of decreasing balance
 104 |     |     /// @return realBalanceDelta The actually applied streams balance change.
 105 |     |     /// It's equal to the passed `balanceDelta`, unless it's negative
 106 |     |     /// and it gets capped at the current balance amount.
 107 | *   |     function _setStreamsAndTransfer(
 108 |     |         Drips drips,
 109 |     |         uint256 accountId,
 110 |     |         IERC20 erc20,
 111 |     |         StreamReceiver[] calldata currReceivers,
 112 |     |         int128 balanceDelta,
 113 |     |         StreamReceiver[] calldata newReceivers,
 114 |     |         // slither-disable-next-line similar-names
 115 |     |         uint32 maxEndHint1,
 116 |     |         uint32 maxEndHint2,
 117 |     |         address transferTo
 118 | *   |     ) internal returns (int128 realBalanceDelta) {
 119 | *   |         if (balanceDelta > 0) _transferFromCaller(drips, erc20, uint128(balanceDelta));
 120 | *   |         realBalanceDelta = drips.setStreams(
 121 | *   |             accountId, erc20, currReceivers, balanceDelta, newReceivers, maxEndHint1, maxEndHint2
 122 |     |         );
 123 | *   |         if (realBalanceDelta < 0) drips.withdraw(erc20, transferTo, uint128(-realBalanceDelta));
 124 |     |     }
 125 |     | 
 126 |     |     /// @notice Transfers tokens from the sender to Drips.
 127 |     |     /// @param drips The Drips contract to use.
 128 |     |     /// @param erc20 The used ERC-20 token.
 129 |     |     /// @param amt The transferred amount
 130 | *   |     function _transferFromCaller(Drips drips, IERC20 erc20, uint128 amt) internal {
 131 | *   |         SafeERC20.safeTransferFrom(erc20, _msgSender(), address(drips), amt);
 132 |     |     }
 133 |     | }
 134 |     | 

/opt/scfuzzbench/work/target/src/Managed.sol
   1 |     | // SPDX-License-Identifier: GPL-3.0-only
   2 |     | pragma solidity ^0.8.20;
   3 |     | 
   4 |     | import {UUPSUpgradeable} from "openzeppelin-contracts/proxy/utils/UUPSUpgradeable.sol";
   5 |     | import {ERC1967Proxy} from "openzeppelin-contracts/proxy/ERC1967/ERC1967Proxy.sol";
   6 |     | import {EnumerableSet} from "openzeppelin-contracts/utils/structs/EnumerableSet.sol";
   7 |     | import {StorageSlot} from "openzeppelin-contracts/utils/StorageSlot.sol";
   8 |     | 
   9 |     | using EnumerableSet for EnumerableSet.AddressSet;
  10 |     | 
  11 |     | /// @notice A mix-in for contract pausing, upgrading and admin management.
  12 |     | /// It can't be used directly, only via a proxy. It uses the upgrade-safe ERC-1967 storage scheme.
  13 |     | ///
  14 |     | /// Managed uses the ERC-1967 admin slot to store the admin address.
  15 |     | /// All instances of the contracts have admin address `0x00` and are forever paused.
  16 |     | /// When a proxy uses such contract via delegation, the proxy should define
  17 |     | /// the initial admin address and the contract is initially unpaused.
  18 |     | abstract contract Managed is UUPSUpgradeable {
  19 |     |     /// @notice The pointer to the storage slot holding a single `ManagedStorage` structure.
  20 | *   |     bytes32 private immutable _managedStorageSlot = _erc1967Slot("eip1967.managed.storage");
  21 |     | 
  22 |     |     /// @notice Emitted when a new admin of the contract is proposed.
  23 |     |     /// The proposed admin must call `acceptAdmin` to finalize the change.
  24 |     |     /// @param currentAdmin The current admin address.
  25 |     |     /// @param newAdmin The proposed admin address.
  26 |     |     event NewAdminProposed(address indexed currentAdmin, address indexed newAdmin);
  27 |     | 
  28 |     |     /// @notice Emitted when the pauses role is granted.
  29 |     |     /// @param pauser The address that the pauser role was granted to.
  30 |     |     /// @param admin The address of the admin that triggered the change.
  31 |     |     event PauserGranted(address indexed pauser, address indexed admin);
  32 |     | 
  33 |     |     /// @notice Emitted when the pauses role is revoked.
  34 |     |     /// @param pauser The address that the pauser role was revoked from.
  35 |     |     /// @param admin The address of the admin that triggered the change.
  36 |     |     event PauserRevoked(address indexed pauser, address indexed admin);
  37 |     | 
  38 |     |     /// @notice Emitted when the pause is triggered.
  39 |     |     /// @param pauser The address that triggered the change.
  40 |     |     event Paused(address indexed pauser);
  41 |     | 
  42 |     |     /// @notice Emitted when the pause is lifted.
  43 |     |     /// @param pauser The address that triggered the change.
  44 |     |     event Unpaused(address indexed pauser);
  45 |     | 
  46 |     |     struct ManagedStorage {
  47 |     |         bool isPaused;
  48 |     |         EnumerableSet.AddressSet pausers;
  49 |     |         address proposedAdmin;
  50 |     |     }
  51 |     | 
  52 |     |     /// @notice Throws if called by any caller other than the admin.
  53 |     |     modifier onlyAdmin() {
  54 |     |         require(admin() == msg.sender, "Caller not the admin");
  55 |     |         _;
  56 |     |     }
  57 |     | 
  58 |     |     /// @notice Throws if called by any caller other than the admin or a pauser.
  59 |     |     modifier onlyAdminOrPauser() {
  60 |     |         require(admin() == msg.sender || isPauser(msg.sender), "Caller not the admin or a pauser");
  61 |     |         _;
  62 |     |     }
  63 |     | 
  64 |     |     /// @notice Modifier to make a function callable only when the contract is not paused.
  65 |     |     modifier whenNotPaused() {
  66 | *   |         require(!isPaused(), "Contract paused");
  67 | *   |         _;
  68 |     |     }
  69 |     | 
  70 |     |     /// @notice Modifier to make a function callable only when the contract is paused.
  71 |     |     modifier whenPaused() {
  72 |     |         require(isPaused(), "Contract not paused");
  73 |     |         _;
  74 |     |     }
  75 |     | 
  76 |     |     /// @notice Initializes the contract in paused state and with no admin.
  77 |     |     /// The contract instance can be used only as a call delegation target for a proxy.
  78 |     |     constructor() {
  79 | *   |         _managedStorage().isPaused = true;
  80 |     |     }
  81 |     | 
  82 |     |     /// @notice Returns the current implementation address.
  83 |     |     function implementation() public view returns (address) {
  84 |     |         return _getImplementation();
  85 |     |     }
  86 |     | 
  87 |     |     /// @notice Returns the address of the current admin.
  88 |     |     function admin() public view returns (address) {
  89 |     |         return _getAdmin();
  90 |     |     }
  91 |     | 
  92 |     |     /// @notice Returns the proposed address to change the admin to.
  93 |     |     function proposedAdmin() public view returns (address) {
  94 |     |         return _managedStorage().proposedAdmin;
  95 |     |     }
  96 |     | 
  97 |     |     /// @notice Proposes a change of the admin of the contract.
  98 |     |     /// The proposed new admin must call `acceptAdmin` to finalize the change.
  99 |     |     /// To cancel a proposal propose a different address, e.g. the zero address.
 100 |     |     /// Can only be called by the current admin.
 101 |     |     /// @param newAdmin The proposed admin address.
 102 |     |     function proposeNewAdmin(address newAdmin) public onlyAdmin {
 103 |     |         emit NewAdminProposed(msg.sender, newAdmin);
 104 |     |         _managedStorage().proposedAdmin = newAdmin;
 105 |     |     }
 106 |     | 
 107 |     |     /// @notice Applies a proposed change of the admin of the contract.
 108 |     |     /// Sets the proposed admin to the zero address.
 109 |     |     /// Can only be called by the proposed admin.
 110 |     |     function acceptAdmin() public {
 111 |     |         require(proposedAdmin() == msg.sender, "Caller not the proposed admin");
 112 |     |         _updateAdmin(msg.sender);
 113 |     |     }
 114 |     | 
 115 |     |     /// @notice Changes the admin of the contract to address zero.
 116 |     |     /// It's no longer possible to change the admin or upgrade the contract afterwards.
 117 |     |     /// Can only be called by the current admin.
 118 |     |     function renounceAdmin() public onlyAdmin {
 119 |     |         _updateAdmin(address(0));
 120 |     |     }
 121 |     | 
 122 |     |     /// @notice Sets the current admin of the contract and clears the proposed admin.
 123 |     |     /// @param newAdmin The admin address being set. Can be the zero address.
 124 |     |     function _updateAdmin(address newAdmin) internal {
 125 |     |         emit AdminChanged(admin(), newAdmin);
 126 |     |         _managedStorage().proposedAdmin = address(0);
 127 |     |         StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
 128 |     |     }
 129 |     | 
 130 |     |     /// @notice Grants the pauser role to an address. Callable only by the admin.
 131 |     |     /// @param pauser The granted address.
 132 |     |     function grantPauser(address pauser) public onlyAdmin {
 133 |     |         require(_managedStorage().pausers.add(pauser), "Address already is a pauser");
 134 |     |         emit PauserGranted(pauser, msg.sender);
 135 |     |     }
 136 |     | 
 137 |     |     /// @notice Revokes the pauser role from an address. Callable only by the admin.
 138 |     |     /// @param pauser The revoked address.
 139 |     |     function revokePauser(address pauser) public onlyAdmin {
 140 |     |         require(_managedStorage().pausers.remove(pauser), "Address is not a pauser");
 141 |     |         emit PauserRevoked(pauser, msg.sender);
 142 |     |     }
 143 |     | 
 144 |     |     /// @notice Checks if an address is a pauser.
 145 |     |     /// @param pauser The checked address.
 146 |     |     /// @return isAddrPauser True if the address is a pauser.
 147 |     |     function isPauser(address pauser) public view returns (bool isAddrPauser) {
 148 |     |         return _managedStorage().pausers.contains(pauser);
 149 |     |     }
 150 |     | 
 151 |     |     /// @notice Returns all the addresses with the pauser role.
 152 |     |     /// @return pausersList The list of all the pausers, ordered arbitrarily.
 153 |     |     /// The list's order may change after granting or revoking the pauser role.
 154 |     |     function allPausers() public view returns (address[] memory pausersList) {
 155 |     |         return _managedStorage().pausers.values();
 156 |     |     }
 157 |     | 
 158 |     |     /// @notice Returns true if the contract is paused, and false otherwise.
 159 | *   |     function isPaused() public view returns (bool) {
 160 | *   |         return _managedStorage().isPaused;
 161 |     |     }
 162 |     | 
 163 |     |     /// @notice Triggers stopped state. Callable only by the admin or a pauser.
 164 |     |     function pause() public onlyAdminOrPauser whenNotPaused {
 165 |     |         _managedStorage().isPaused = true;
 166 |     |         emit Paused(msg.sender);
 167 |     |     }
 168 |     | 
 169 |     |     /// @notice Returns to normal state. Callable only by the admin or a pauser.
 170 |     |     function unpause() public onlyAdminOrPauser whenPaused {
 171 |     |         _managedStorage().isPaused = false;
 172 |     |         emit Unpaused(msg.sender);
 173 |     |     }
 174 |     | 
 175 |     |     /// @notice Calculates the quasi ERC-1967 slot pointer.
 176 |     |     /// @param name The name of the slot, should be globally unique
 177 |     |     /// @return slot The slot pointer
 178 | *   |     function _erc1967Slot(string memory name) internal pure returns (bytes32 slot) {
 179 |     |         // The original ERC-1967 subtracts 1 from the hash to get 1 storage slot
 180 |     |         // under an index without a known hash preimage which is enough to store a single address.
 181 |     |         // This implementation subtracts 1024 to get 1024 slots without a known preimage
 182 |     |         // allowing securely storing much larger structures.
 183 | *   |         return bytes32(uint256(keccak256(bytes(name))) - 1024);
 184 |     |     }
 185 |     | 
 186 |     |     /// @notice Returns the Managed storage.
 187 |     |     /// @return storageRef The storage.
 188 | *   |     function _managedStorage() internal view returns (ManagedStorage storage storageRef) {
 189 | *   |         bytes32 slot = _managedStorageSlot;
 190 |     |         // slither-disable-next-line assembly
 191 | *   |         assembly {
 192 | *   |             storageRef.slot := slot
 193 |     |         }
 194 |     |     }
 195 |     | 
 196 |     |     /// @notice Authorizes the contract upgrade. See `UUPSUpgradeable` docs for more details.
 197 |     |     function _authorizeUpgrade(address /* newImplementation */ ) internal view override onlyAdmin {
 198 |     |         return;
 199 |     |     }
 200 |     | }
 201 |     | 
 202 |     | /// @notice A generic proxy for contracts implementing `Managed`.
 203 |     | contract ManagedProxy is ERC1967Proxy {
 204 |     |     constructor(Managed logic, address admin) ERC1967Proxy(address(logic), new bytes(0)) {
 205 |     |         _changeAdmin(admin);
 206 |     |     }
 207 |     | }
 208 |     | 

/opt/scfuzzbench/work/target/src/Splits.sol
   1 |     | // SPDX-License-Identifier: GPL-3.0-only
   2 |     | pragma solidity ^0.8.20;
   3 |     | 
   4 |     | import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";
   5 |     | 
   6 |     | /// @notice A splits receiver
   7 |     | struct SplitsReceiver {
   8 |     |     /// @notice The account ID.
   9 |     |     uint256 accountId;
  10 |     |     /// @notice The splits weight. Must never be zero.
  11 |     |     /// The account will be getting `weight / _TOTAL_SPLITS_WEIGHT`
  12 |     |     /// share of the funds collected by the splitting account.
  13 |     |     uint32 weight;
  14 |     | }
  15 |     | 
  16 |     | /// @notice Splits can keep track of at most `type(uint128).max`
  17 |     | /// which is `2 ^ 128 - 1` units of each ERC-20 token.
  18 |     | /// It's up to the caller to guarantee that this limit is never exceeded,
  19 |     | /// failing to do so may result in a total protocol collapse.
  20 |     | abstract contract Splits {
  21 |     |     /// @notice Maximum number of splits receivers of a single account.
  22 |     |     /// Limits the cost of splitting.
  23 | *   |     uint256 internal constant _MAX_SPLITS_RECEIVERS = 200;
  24 |     |     /// @notice The total splits weight of an account.
  25 | *   |     uint32 internal constant _TOTAL_SPLITS_WEIGHT = 1_000_000;
  26 |     |     /// @notice The amount the contract can keep track of each ERC-20 token.
  27 |     |     // slither-disable-next-line unused-state
  28 |     |     uint128 internal constant _MAX_SPLITS_BALANCE = type(uint128).max;
  29 |     |     /// @notice The storage slot holding a single `SplitsStorage` structure.
  30 |     |     bytes32 private immutable _splitsStorageSlot;
  31 |     | 
  32 |     |     /// @notice Emitted when an account collects funds
  33 |     |     /// @param accountId The account ID.
  34 |     |     /// @param erc20 The used ERC-20 token.
  35 |     |     /// @param collected The collected amount
  36 |     |     event Collected(uint256 indexed accountId, IERC20 indexed erc20, uint128 collected);
  37 |     | 
  38 |     |     /// @notice Emitted when funds are split from an account to a receiver.
  39 |     |     /// This is caused by the account collecting received funds.
  40 |     |     /// @param accountId The account ID.
  41 |     |     /// @param receiver The splits receiver account ID
  42 |     |     /// @param erc20 The used ERC-20 token.
  43 |     |     /// @param amt The amount split to the receiver
  44 |     |     event Split(
  45 |     |         uint256 indexed accountId, uint256 indexed receiver, IERC20 indexed erc20, uint128 amt
  46 |     |     );
  47 |     | 
  48 |     |     /// @notice Emitted when funds are made collectable after splitting.
  49 |     |     /// @param accountId The account ID.
  50 |     |     /// @param erc20 The used ERC-20 token.
  51 |     |     /// @param amt The amount made collectable for the account
  52 |     |     /// on top of what was collectable before.
  53 |     |     event Collectable(uint256 indexed accountId, IERC20 indexed erc20, uint128 amt);
  54 |     | 
  55 |     |     /// @notice Emitted when funds are given from the account to the receiver.
  56 |     |     /// @param accountId The account ID.
  57 |     |     /// @param receiver The receiver account ID.
  58 |     |     /// @param erc20 The used ERC-20 token.
  59 |     |     /// @param amt The given amount
  60 |     |     event Given(
  61 |     |         uint256 indexed accountId, uint256 indexed receiver, IERC20 indexed erc20, uint128 amt
  62 |     |     );
  63 |     | 
  64 |     |     /// @notice Emitted when the account's splits are updated.
  65 |     |     /// @param accountId The account ID.
  66 |     |     /// @param receiversHash The splits receivers list hash
  67 |     |     event SplitsSet(uint256 indexed accountId, bytes32 indexed receiversHash);
  68 |     | 
  69 |     |     /// @notice Emitted when an account is seen in a splits receivers list.
  70 |     |     /// @param receiversHash The splits receivers list hash
  71 |     |     /// @param accountId The account ID.
  72 |     |     /// @param weight The splits weight. Must never be zero.
  73 |     |     /// The account will be getting `weight / _TOTAL_SPLITS_WEIGHT`
  74 |     |     /// share of the funds collected by the splitting account.
  75 |     |     event SplitsReceiverSeen(
  76 |     |         bytes32 indexed receiversHash, uint256 indexed accountId, uint32 weight
  77 |     |     );
  78 |     | 
  79 |     |     struct SplitsStorage {
  80 |     |         /// @notice Account splits states.
  81 |     |         mapping(uint256 accountId => SplitsState) splitsStates;
  82 |     |     }
  83 |     | 
  84 |     |     struct SplitsState {
  85 |     |         /// @notice The account's splits configuration hash, see `hashSplits`.
  86 |     |         bytes32 splitsHash;
  87 |     |         /// @notice The account's splits balances.
  88 |     |         mapping(IERC20 erc20 => SplitsBalance) balances;
  89 |     |     }
  90 |     | 
  91 |     |     struct SplitsBalance {
  92 |     |         /// @notice The not yet split balance, must be split before collecting by the account.
  93 |     |         uint128 splittable;
  94 |     |         /// @notice The already split balance, ready to be collected by the account.
  95 |     |         uint128 collectable;
  96 |     |     }
  97 |     | 
  98 |     |     /// @param splitsStorageSlot The storage slot to holding a single `SplitsStorage` structure.
  99 | *   |     constructor(bytes32 splitsStorageSlot) {
 100 | *   |         _splitsStorageSlot = splitsStorageSlot;
 101 |     |     }
 102 |     | 
 103 | *   |     function _addSplittable(uint256 accountId, IERC20 erc20, uint128 amt) internal {
 104 |     |         // This will not overflow if the requirement of tracking in the contract
 105 |     |         // no more than `_MAX_SPLITS_BALANCE` of each token is followed.
 106 | *   |         _splitsStorage().splitsStates[accountId].balances[erc20].splittable += amt;
 107 |     |     }
 108 |     | 
 109 |     |     /// @notice Returns account's received but not split yet funds.
 110 |     |     /// @param accountId The account ID.
 111 |     |     /// @param erc20 The used ERC-20 token.
 112 |     |     /// @return amt The amount received but not split yet.
 113 | *   |     function _splittable(uint256 accountId, IERC20 erc20) internal view returns (uint128 amt) {
 114 | *   |         return _splitsStorage().splitsStates[accountId].balances[erc20].splittable;
 115 |     |     }
 116 |     | 
 117 |     |     /// @notice Calculate the result of splitting an amount using the current splits configuration.
 118 |     |     /// @param accountId The account ID.
 119 |     |     /// @param currReceivers The list of the account's current splits receivers.
 120 |     |     /// It must be exactly the same as the last list set for the account with `_setSplits`.
 121 |     |     /// If the splits have never been set, pass an empty array.
 122 |     |     /// @param amount The amount being split.
 123 |     |     /// @return collectableAmt The amount made collectable for the account
 124 |     |     /// on top of what was collectable before.
 125 |     |     /// @return splitAmt The amount split to the account's splits receivers
 126 | *   |     function _splitResult(uint256 accountId, SplitsReceiver[] memory currReceivers, uint128 amount)
 127 |     |         internal
 128 |     |         view
 129 | *   |         returns (uint128 collectableAmt, uint128 splitAmt)
 130 |     |     {
 131 | *   |         _assertCurrSplits(accountId, currReceivers);
 132 | *   |         if (amount == 0) {
 133 | *   |             return (0, 0);
 134 |     |         }
 135 | *   |         unchecked {
 136 | *   |             uint256 splitsWeight = 0;
 137 | *   |             for (uint256 i = currReceivers.length; i != 0;) {
 138 | *   |                 splitsWeight += currReceivers[--i].weight;
 139 |     |             }
 140 | *   |             splitAmt = uint128(amount * splitsWeight / _TOTAL_SPLITS_WEIGHT);
 141 | *   |             collectableAmt = amount - splitAmt;
 142 |     |         }
 143 |     |     }
 144 |     | 
 145 |     |     /// @notice Splits the account's splittable funds among receivers.
 146 |     |     /// The entire splittable balance of the given ERC-20 token is split.
 147 |     |     /// All split funds are split using the current splits configuration.
 148 |     |     /// @param accountId The account ID.
 149 |     |     /// @param erc20 The used ERC-20 token.
 150 |     |     /// @param currReceivers The list of the account's current splits receivers.
 151 |     |     /// It must be exactly the same as the last list set for the account with `_setSplits`.
 152 |     |     /// If the splits have never been set, pass an empty array.
 153 |     |     /// @return collectableAmt The amount made collectable for the account
 154 |     |     /// on top of what was collectable before.
 155 |     |     /// @return splitAmt The amount split to the account's splits receivers
 156 | *   |     function _split(uint256 accountId, IERC20 erc20, SplitsReceiver[] memory currReceivers)
 157 |     |         internal
 158 | *   |         returns (uint128 collectableAmt, uint128 splitAmt)
 159 | *   |     {
 160 | *   |         _assertCurrSplits(accountId, currReceivers);
 161 | *   |         SplitsBalance storage balance = _splitsStorage().splitsStates[accountId].balances[erc20];
 162 |     | 
 163 | *   |         collectableAmt = balance.splittable;
 164 | *   |         if (collectableAmt == 0) {
 165 | *   |             return (0, 0);
 166 |     |         }
 167 | *   |         balance.splittable = 0;
 168 |     | 
 169 | *   |         unchecked {
 170 | *   |             uint256 splitsWeight = 0;
 171 | *   |             for (uint256 i = 0; i < currReceivers.length; i++) {
 172 | *   |                 splitsWeight += currReceivers[i].weight;
 173 | *   |                 uint128 currSplitAmt = splitAmt;
 174 | *   |                 splitAmt = uint128(collectableAmt * splitsWeight / _TOTAL_SPLITS_WEIGHT);
 175 | *   |                 currSplitAmt = splitAmt - currSplitAmt;
 176 | *   |                 uint256 receiver = currReceivers[i].accountId;
 177 | *   |                 _addSplittable(receiver, erc20, currSplitAmt);
 178 | *   |                 emit Split(accountId, receiver, erc20, currSplitAmt);
 179 |     |             }
 180 | *   |             collectableAmt -= splitAmt;
 181 |     |             // This will not overflow if the requirement of tracking in the contract
 182 |     |             // no more than `_MAX_SPLITS_BALANCE` of each token is followed.
 183 | *   |             balance.collectable += collectableAmt;
 184 |     |         }
 185 | *   |         emit Collectable(accountId, erc20, collectableAmt);
 186 |     |     }
 187 |     | 
 188 |     |     /// @notice Returns account's received funds already split and ready to be collected.
 189 |     |     /// @param accountId The account ID.
 190 |     |     /// @param erc20 The used ERC-20 token.
 191 |     |     /// @return amt The collectable amount.
 192 | *   |     function _collectable(uint256 accountId, IERC20 erc20) internal view returns (uint128 amt) {
 193 | *   |         return _splitsStorage().splitsStates[accountId].balances[erc20].collectable;
 194 |     |     }
 195 |     | 
 196 |     |     /// @notice Collects account's received already split funds.
 197 |     |     /// @param accountId The account ID.
 198 |     |     /// @param erc20 The used ERC-20 token.
 199 |     |     /// @return amt The collected amount
 200 | *   |     function _collect(uint256 accountId, IERC20 erc20) internal returns (uint128 amt) {
 201 | *   |         SplitsBalance storage balance = _splitsStorage().splitsStates[accountId].balances[erc20];
 202 | *   |         amt = balance.collectable;
 203 | *   |         balance.collectable = 0;
 204 | *   |         emit Collected(accountId, erc20, amt);
 205 |     |     }
 206 |     | 
 207 |     |     /// @notice Gives funds from the account to the receiver.
 208 |     |     /// The receiver can split and collect them immediately.
 209 |     |     /// @param accountId The account ID.
 210 |     |     /// @param receiver The receiver account ID.
 211 |     |     /// @param erc20 The used ERC-20 token.
 212 |     |     /// @param amt The given amount
 213 | *   |     function _give(uint256 accountId, uint256 receiver, IERC20 erc20, uint128 amt) internal {
 214 | *   |         _addSplittable(receiver, erc20, amt);
 215 | *   |         emit Given(accountId, receiver, erc20, amt);
 216 |     |     }
 217 |     | 
 218 |     |     /// @notice Sets the account splits configuration.
 219 |     |     /// The configuration is common for all ERC-20 tokens.
 220 |     |     /// Nothing happens to the currently splittable funds, but when they are split
 221 |     |     /// after this function finishes, the new splits configuration will be used.
 222 |     |     /// @param accountId The account ID.
 223 |     |     /// @param receivers The list of the account's splits receivers to be set.
 224 |     |     /// Must be sorted by the account IDs, without duplicate account IDs and without 0 weights.
 225 |     |     /// Each splits receiver will be getting `weight / _TOTAL_SPLITS_WEIGHT`
 226 |     |     /// share of the funds collected by the account.
 227 |     |     /// If the sum of weights of all receivers is less than `_TOTAL_SPLITS_WEIGHT`,
 228 |     |     /// some funds won't be split, but they will be left for the account to collect.
 229 |     |     /// Fractions of tokens are always rounder either up or down depending on the amount
 230 |     |     /// being split, the receiver's position on the list and the other receivers' weights.
 231 |     |     /// It's valid to include the account's own `accountId` in the list of receivers,
 232 |     |     /// but funds split to themselves return to their splittable balance and are not collectable.
 233 |     |     /// This is usually unwanted, because if splitting is repeated,
 234 |     |     /// funds split to themselves will be again split using the current configuration.
 235 |     |     /// Splitting 100% to self effectively blocks splitting unless the configuration is updated.
 236 | *   |     function _setSplits(uint256 accountId, SplitsReceiver[] memory receivers) internal {
 237 | *   |         SplitsState storage state = _splitsStorage().splitsStates[accountId];
 238 | *   |         bytes32 newSplitsHash = _hashSplits(receivers);
 239 | *   |         if (newSplitsHash == state.splitsHash) return;
 240 | *   |         emit SplitsSet(accountId, newSplitsHash);
 241 | *   |         _assertSplitsValid(receivers, newSplitsHash);
 242 | *   |         state.splitsHash = newSplitsHash;
 243 |     |     }
 244 |     | 
 245 |     |     /// @notice Validates a list of splits receivers and emits events for them
 246 |     |     /// @param receivers The list of splits receivers
 247 |     |     /// @param receiversHash The hash of the list of splits receivers.
 248 |     |     /// Must be sorted by the account IDs, without duplicate account IDs and without 0 weights.
 249 | *   |     function _assertSplitsValid(SplitsReceiver[] memory receivers, bytes32 receiversHash) private {
 250 | *   |         unchecked {
 251 | *   |             require(receivers.length <= _MAX_SPLITS_RECEIVERS, "Too many splits receivers");
 252 | *   |             uint256 totalWeight = 0;
 253 | *   |             uint256 prevAccountId = 0;
 254 | *   |             for (uint256 i = 0; i < receivers.length; i++) {
 255 | *   |                 SplitsReceiver memory receiver = receivers[i];
 256 | *   |                 uint32 weight = receiver.weight;
 257 | *   |                 require(weight != 0, "Splits receiver weight is zero");
 258 | *   |                 totalWeight += weight;
 259 | *   |                 uint256 accountId = receiver.accountId;
 260 | *   |                 if (accountId <= prevAccountId) require(i == 0, "Splits receivers not sorted");
 261 | *   |                 prevAccountId = accountId;
 262 | *   |                 emit SplitsReceiverSeen(receiversHash, accountId, weight);
 263 |     |             }
 264 | *   |             require(totalWeight <= _TOTAL_SPLITS_WEIGHT, "Splits weights sum too high");
 265 |     |         }
 266 |     |     }
 267 |     | 
 268 |     |     /// @notice Asserts that the list of splits receivers is the account's currently used one.
 269 |     |     /// @param accountId The account ID.
 270 |     |     /// @param currReceivers The list of the account's current splits receivers.
 271 |     |     /// If the splits have never been set, pass an empty array.
 272 | *   |     function _assertCurrSplits(uint256 accountId, SplitsReceiver[] memory currReceivers)
 273 |     |         internal
 274 |     |         view
 275 |     |     {
 276 | *   |         require(
 277 | *   |             _hashSplits(currReceivers) == _splitsHash(accountId), "Invalid current splits receivers"
 278 |     |         );
 279 |     |     }
 280 |     | 
 281 |     |     /// @notice Current account's splits hash, see `hashSplits`.
 282 |     |     /// @param accountId The account ID.
 283 |     |     /// @return currSplitsHash The current account's splits hash
 284 | *   |     function _splitsHash(uint256 accountId) internal view returns (bytes32 currSplitsHash) {
 285 | *   |         return _splitsStorage().splitsStates[accountId].splitsHash;
 286 |     |     }
 287 |     | 
 288 |     |     /// @notice Calculates the hash of the list of splits receivers.
 289 |     |     /// @param receivers The list of the splits receivers.
 290 |     |     /// If the splits have never been set, pass an empty array.
 291 |     |     /// @return receiversHash The hash of the list of splits receivers.
 292 | *   |     function _hashSplits(SplitsReceiver[] memory receivers)
 293 |     |         internal
 294 |     |         pure
 295 | *   |         returns (bytes32 receiversHash)
 296 |     |     {
 297 | *   |         if (receivers.length == 0) {
 298 | *   |             return bytes32(0);
 299 |     |         }
 300 | *   |         return keccak256(abi.encode(receivers));
 301 |     |     }
 302 |     | 
 303 |     |     /// @notice Returns the Splits storage.
 304 |     |     /// @return splitsStorage The storage.
 305 | *   |     function _splitsStorage() private view returns (SplitsStorage storage splitsStorage) {
 306 | *   |         bytes32 slot = _splitsStorageSlot;
 307 |     |         // slither-disable-next-line assembly
 308 | *   |         assembly {
 309 | *   |             splitsStorage.slot := slot
 310 |     |         }
 311 |     |     }
 312 |     | }
 313 |     | 

/opt/scfuzzbench/work/target/src/Streams.sol
    1 |     | // SPDX-License-Identifier: GPL-3.0-only
    2 |     | pragma solidity ^0.8.20;
    3 |     | 
    4 |     | import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";
    5 |     | 
    6 |     | /// @notice A stream receiver
    7 |     | struct StreamReceiver {
    8 |     |     /// @notice The account ID.
    9 |     |     uint256 accountId;
   10 |     |     /// @notice The stream configuration.
   11 |     |     StreamConfig config;
   12 |     | }
   13 |     | 
   14 |     | /// @notice The sender streams history entry, used when squeezing streams.
   15 |     | struct StreamsHistory {
   16 |     |     /// @notice Streams receivers list hash, see `_hashStreams`.
   17 |     |     /// If it's non-zero, `receivers` must be empty.
   18 |     |     bytes32 streamsHash;
   19 |     |     /// @notice The streams receivers. If it's non-empty, `streamsHash` must be `0`.
   20 |     |     /// If it's empty, this history entry will be skipped when squeezing streams
   21 |     |     /// and `streamsHash` will be used when verifying the streams history validity.
   22 |     |     /// Skipping a history entry allows cutting gas usage on analysis
   23 |     |     /// of parts of the streams history which are not worth squeezing.
   24 |     |     /// The hash of an empty receivers list is `0`, so when the sender updates
   25 |     |     /// their receivers list to be empty, the new `StreamsHistory` entry will have
   26 |     |     /// both the `streamsHash` equal to `0` and the `receivers` empty making it always skipped.
   27 |     |     /// This is fine, because there can't be any funds to squeeze from that entry anyway.
   28 |     |     StreamReceiver[] receivers;
   29 |     |     /// @notice The time when streams have been configured
   30 |     |     uint32 updateTime;
   31 |     |     /// @notice The maximum end time of streaming.
   32 |     |     uint32 maxEnd;
   33 |     | }
   34 |     | 
   35 |     | /// @notice Describes a streams configuration.
   36 |     | /// It's a 256-bit integer constructed by concatenating the configuration parameters:
   37 |     | /// `streamId (32 bits) | amtPerSec (160 bits) | start (32 bits) | duration (32 bits)`.
   38 |     | /// `streamId` is an arbitrary number used to identify a stream.
   39 |     | /// It's a part of the configuration but the protocol doesn't use it.
   40 |     | /// `amtPerSec` is the amount per second being streamed. Must never be zero.
   41 |     | /// It must have additional `Streams._AMT_PER_SEC_EXTRA_DECIMALS` decimals and can have fractions.
   42 |     | /// To achieve that its value must be multiplied by `Streams._AMT_PER_SEC_MULTIPLIER`.
   43 |     | /// `start` is the timestamp when streaming should start.
   44 |     | /// If zero, use the timestamp when the stream is configured.
   45 |     | /// `duration` is the duration of streaming.
   46 |     | /// If zero, stream until balance runs out.
   47 |     | type StreamConfig is uint256;
   48 |     | 
   49 |     | using StreamConfigImpl for StreamConfig global;
   50 |     | 
   51 |     | library StreamConfigImpl {
   52 |     |     /// @notice Create a new StreamConfig.
   53 |     |     /// @param streamId_ An arbitrary number used to identify a stream.
   54 |     |     /// It's a part of the configuration but the protocol doesn't use it.
   55 |     |     /// @param amtPerSec_ The amount per second being streamed. Must never be zero.
   56 |     |     /// It must have additional `Streams._AMT_PER_SEC_EXTRA_DECIMALS`
   57 |     |     /// decimals and can have fractions.
   58 |     |     /// To achieve that the passed value must be multiplied by `Streams._AMT_PER_SEC_MULTIPLIER`.
   59 |     |     /// @param start_ The timestamp when streaming should start.
   60 |     |     /// If zero, use the timestamp when the stream is configured.
   61 |     |     /// @param duration_ The duration of streaming. If zero, stream until the balance runs out.
   62 | *   |     function create(uint32 streamId_, uint160 amtPerSec_, uint32 start_, uint32 duration_)
   63 |     |         internal
   64 |     |         pure
   65 | *   |         returns (StreamConfig)
   66 |     |     {
   67 |     |         // By assignment we get `config` value:
   68 |     |         // `zeros (224 bits) | streamId (32 bits)`
   69 | *   |         uint256 config = streamId_;
   70 |     |         // By bit shifting we get `config` value:
   71 |     |         // `zeros (64 bits) | streamId (32 bits) | zeros (160 bits)`
   72 |     |         // By bit masking we get `config` value:
   73 |     |         // `zeros (64 bits) | streamId (32 bits) | amtPerSec (160 bits)`
   74 | *   |         config = (config << 160) | amtPerSec_;
   75 |     |         // By bit shifting we get `config` value:
   76 |     |         // `zeros (32 bits) | streamId (32 bits) | amtPerSec (160 bits) | zeros (32 bits)`
   77 |     |         // By bit masking we get `config` value:
   78 |     |         // `zeros (32 bits) | streamId (32 bits) | amtPerSec (160 bits) | start (32 bits)`
   79 | *   |         config = (config << 32) | start_;
   80 |     |         // By bit shifting we get `config` value:
   81 |     |         // `streamId (32 bits) | amtPerSec (160 bits) | start (32 bits) | zeros (32 bits)`
   82 |     |         // By bit masking we get `config` value:
   83 |     |         // `streamId (32 bits) | amtPerSec (160 bits) | start (32 bits) | duration (32 bits)`
   84 | *   |         config = (config << 32) | duration_;
   85 | *   |         return StreamConfig.wrap(config);
   86 |     |     }
   87 |     | 
   88 |     |     /// @notice Extracts streamId from a `StreamConfig`
   89 |     |     function streamId(StreamConfig config) internal pure returns (uint32) {
   90 |     |         // `config` has value:
   91 |     |         // `streamId (32 bits) | amtPerSec (160 bits) | start (32 bits) | duration (32 bits)`
   92 |     |         // By bit shifting we get value:
   93 |     |         // `zeros (224 bits) | streamId (32 bits)`
   94 |     |         // By casting down we get value:
   95 |     |         // `streamId (32 bits)`
   96 |     |         return uint32(StreamConfig.unwrap(config) >> 224);
   97 |     |     }
   98 |     | 
   99 |     |     /// @notice Extracts amtPerSec from a `StreamConfig`
  100 | *   |     function amtPerSec(StreamConfig config) internal pure returns (uint160) {
  101 |     |         // `config` has value:
  102 |     |         // `streamId (32 bits) | amtPerSec (160 bits) | start (32 bits) | duration (32 bits)`
  103 |     |         // By bit shifting we get value:
  104 |     |         // `zeros (64 bits) | streamId (32 bits) | amtPerSec (160 bits)`
  105 |     |         // By casting down we get value:
  106 |     |         // `amtPerSec (160 bits)`
  107 | *   |         return uint160(StreamConfig.unwrap(config) >> 64);
  108 |     |     }
  109 |     | 
  110 |     |     /// @notice Extracts start from a `StreamConfig`
  111 | *   |     function start(StreamConfig config) internal pure returns (uint32) {
  112 |     |         // `config` has value:
  113 |     |         // `streamId (32 bits) | amtPerSec (160 bits) | start (32 bits) | duration (32 bits)`
  114 |     |         // By bit shifting we get value:
  115 |     |         // `zeros (32 bits) | streamId (32 bits) | amtPerSec (160 bits) | start (32 bits)`
  116 |     |         // By casting down we get value:
  117 |     |         // `start (32 bits)`
  118 | *   |         return uint32(StreamConfig.unwrap(config) >> 32);
  119 |     |     }
  120 |     | 
  121 |     |     /// @notice Extracts duration from a `StreamConfig`
  122 | *   |     function duration(StreamConfig config) internal pure returns (uint32) {
  123 |     |         // `config` has value:
  124 |     |         // `streamId (32 bits) | amtPerSec (160 bits) | start (32 bits) | duration (32 bits)`
  125 |     |         // By casting down we get value:
  126 |     |         // `duration (32 bits)`
  127 | *   |         return uint32(StreamConfig.unwrap(config));
  128 |     |     }
  129 |     | 
  130 |     |     /// @notice Compares two `StreamConfig`s.
  131 |     |     /// First compares `streamId`s, then `amtPerSec`s, then `start`s and finally `duration`s.
  132 |     |     /// @return isLower True if `config` is strictly lower than `otherConfig`.
  133 | *   |     function lt(StreamConfig config, StreamConfig otherConfig)
  134 |     |         internal
  135 |     |         pure
  136 | *   |         returns (bool isLower)
  137 |     |     {
  138 |     |         // Both configs have value:
  139 |     |         // `streamId (32 bits) | amtPerSec (160 bits) | start (32 bits) | duration (32 bits)`
  140 |     |         // Comparing them as integers is equivalent to comparing their fields from left to right.
  141 | *   |         return StreamConfig.unwrap(config) < StreamConfig.unwrap(otherConfig);
  142 |     |     }
  143 |     | }
  144 |     | 
  145 |     | /// @notice Streams can keep track of at most `type(int128).max`
  146 |     | /// which is `2 ^ 127 - 1` units of each ERC-20 token.
  147 |     | /// It's up to the caller to guarantee that this limit is never exceeded,
  148 |     | /// failing to do so may result in a total protocol collapse.
  149 |     | abstract contract Streams {
  150 |     |     /// @notice Maximum number of streams receivers of a single account.
  151 |     |     /// Limits cost of changes in streams configuration.
  152 | *   |     uint256 internal constant _MAX_STREAMS_RECEIVERS = 100;
  153 |     |     /// @notice The additional decimals for all amtPerSec values.
  154 |     |     uint8 internal constant _AMT_PER_SEC_EXTRA_DECIMALS = 9;
  155 |     |     /// @notice The multiplier for all amtPerSec values. It's `10 ** _AMT_PER_SEC_EXTRA_DECIMALS`.
  156 | *   |     uint160 internal constant _AMT_PER_SEC_MULTIPLIER = 1_000_000_000;
  157 |     |     /// @notice The amount the contract can keep track of each ERC-20 token.
  158 | *   |     uint128 internal constant _MAX_STREAMS_BALANCE = uint128(type(int128).max);
  159 |     |     /// @notice On every timestamp `T`, which is a multiple of `cycleSecs`, the receivers
  160 |     |     /// gain access to streams received during `T - cycleSecs` to `T - 1`.
  161 |     |     /// Always higher than 1.
  162 |     |     // slither-disable-next-line naming-convention
  163 |     |     uint32 internal immutable _cycleSecs;
  164 |     |     /// @notice The minimum amtPerSec of a stream. It's 1 token per cycle.
  165 |     |     // slither-disable-next-line naming-convention
  166 |     |     uint160 internal immutable _minAmtPerSec;
  167 |     |     /// @notice The storage slot holding a single `StreamsStorage` structure.
  168 |     |     bytes32 private immutable _streamsStorageSlot;
  169 |     | 
  170 |     |     /// @notice Emitted when the streams configuration of an account is updated.
  171 |     |     /// @param accountId The account ID.
  172 |     |     /// @param erc20 The used ERC-20 token.
  173 |     |     /// @param receiversHash The streams receivers list hash
  174 |     |     /// @param streamsHistoryHash The streams history hash that was valid right before the update.
  175 |     |     /// @param balance The account's streams balance. These funds will be streamed to the receivers.
  176 |     |     /// @param maxEnd The maximum end time of streaming, when funds run out.
  177 |     |     /// If funds run out after the timestamp `type(uint32).max`, it's set to `type(uint32).max`.
  178 |     |     /// If the balance is 0 or there are no receivers, it's set to the current timestamp.
  179 |     |     event StreamsSet(
  180 |     |         uint256 indexed accountId,
  181 |     |         IERC20 indexed erc20,
  182 |     |         bytes32 indexed receiversHash,
  183 |     |         bytes32 streamsHistoryHash,
  184 |     |         uint128 balance,
  185 |     |         uint32 maxEnd
  186 |     |     );
  187 |     | 
  188 |     |     /// @notice Emitted when an account is seen in a streams receivers list.
  189 |     |     /// @param receiversHash The streams receivers list hash
  190 |     |     /// @param accountId The account ID.
  191 |     |     /// @param config The streams configuration.
  192 |     |     event StreamReceiverSeen(
  193 |     |         bytes32 indexed receiversHash, uint256 indexed accountId, StreamConfig config
  194 |     |     );
  195 |     | 
  196 |     |     /// @notice Emitted when streams are received.
  197 |     |     /// @param accountId The account ID.
  198 |     |     /// @param erc20 The used ERC-20 token.
  199 |     |     /// @param amt The received amount.
  200 |     |     /// @param receivableCycles The number of cycles which still can be received.
  201 |     |     event ReceivedStreams(
  202 |     |         uint256 indexed accountId, IERC20 indexed erc20, uint128 amt, uint32 receivableCycles
  203 |     |     );
  204 |     | 
  205 |     |     /// @notice Emitted when streams are squeezed.
  206 |     |     /// @param accountId The squeezing account ID.
  207 |     |     /// @param erc20 The used ERC-20 token.
  208 |     |     /// @param senderId The ID of the streaming account from whom funds are squeezed.
  209 |     |     /// @param amt The squeezed amount.
  210 |     |     /// @param streamsHistoryHashes The history hashes of all squeezed streams history entries.
  211 |     |     /// Each history hash matches `streamsHistoryHash` emitted in its `StreamsSet`
  212 |     |     /// when the squeezed streams configuration was set.
  213 |     |     /// Sorted in the oldest streams configuration to the newest.
  214 |     |     event SqueezedStreams(
  215 |     |         uint256 indexed accountId,
  216 |     |         IERC20 indexed erc20,
  217 |     |         uint256 indexed senderId,
  218 |     |         uint128 amt,
  219 |     |         bytes32[] streamsHistoryHashes
  220 |     |     );
  221 |     | 
  222 |     |     struct StreamsStorage {
  223 |     |         /// @notice Account streams states.
  224 |     |         mapping(IERC20 erc20 => mapping(uint256 accountId => StreamsState)) states;
  225 |     |     }
  226 |     | 
  227 |     |     struct StreamsState {
  228 |     |         /// @notice The streams history hash, see `_hashStreamsHistory`.
  229 |     |         bytes32 streamsHistoryHash;
  230 |     |         /// @notice The next squeezable timestamps.
  231 |     |         /// Each `N`th element of the array is the next squeezable timestamp
  232 |     |         /// of the `N`th sender's streams configuration in effect in the current cycle.
  233 |     |         mapping(uint256 accountId => uint32[2 ** 32]) nextSqueezed;
  234 |     |         /// @notice The streams receivers list hash, see `_hashStreams`.
  235 |     |         bytes32 streamsHash;
  236 |     |         /// @notice The next cycle to be received
  237 |     |         uint32 nextReceivableCycle;
  238 |     |         /// @notice The time when streams have been configured for the last time.
  239 |     |         uint32 updateTime;
  240 |     |         /// @notice The maximum end time of streaming.
  241 |     |         uint32 maxEnd;
  242 |     |         /// @notice The balance when streams have been configured for the last time.
  243 |     |         uint128 balance;
  244 |     |         /// @notice The number of streams configurations seen in the cycle
  245 |     |         /// during which streams have been configured for the last time.
  246 |     |         uint32 lastUpdatedCycleConfigs;
  247 |     |         /// @notice The changes of the received amounts in each cycle.
  248 |     |         /// The keys are cycles, each cycle `C` becomes receivable on timestamp `C * cycleSecs`.
  249 |     |         /// Each cycle is described by 2 deltas, the cycle's `thisCycle` and the previous cycle's
  250 |     |         /// `nextCycle`, so to get the change of the amount sent during the cycle `C`,
  251 |     |         /// you need to calculate `amtDeltas[C].thisCycle + amtDeltas[C-1].nextCycle`.
  252 |     |         /// To calculate the absolute amount streamed in the cycle `C`, you need to take the
  253 |     |         /// amount streamed during the cycle `C - 1` and add the change applied in the cycle `C`.
  254 |     |         /// Values for cycles before `nextReceivableCycle` are guaranteed to be zeroed.
  255 |     |         /// This means that the value of `amtDeltas[nextReceivableCycle].thisCycle` is always
  256 |     |         /// relative to 0 or in other words it's an absolute value independent from other cycles.
  257 |     |         mapping(uint32 cycle => AmtDelta) amtDeltas;
  258 |     |     }
  259 |     | 
  260 |     |     /// @notice The change of the received amounts in the given cycle and the cycle after it.
  261 |     |     struct AmtDelta {
  262 |     |         /// @notice Amount delta applied in this cycle.
  263 |     |         int128 thisCycle;
  264 |     |         /// @notice Amount delta applied on the next cycle.
  265 |     |         int128 nextCycle;
  266 |     |     }
  267 |     | 
  268 |     |     /// @param cycleSecs The length of cycleSecs to be used in the contract instance.
  269 |     |     /// Low value makes funds more available by shortening the average time
  270 |     |     /// of funds being frozen between being taken from the accounts'
  271 |     |     /// streams balance and being receivable by their receivers.
  272 |     |     /// High value makes receiving cheaper by making it process less cycles for a given time range.
  273 |     |     /// Must be higher than 1.
  274 |     |     /// @param streamsStorageSlot The storage slot to holding a single `StreamsStorage` structure.
  275 | *   |     constructor(uint32 cycleSecs, bytes32 streamsStorageSlot) {
  276 | *   |         require(cycleSecs > 1, "Cycle length too low");
  277 | *   |         _cycleSecs = cycleSecs;
  278 | *   |         _minAmtPerSec = (_AMT_PER_SEC_MULTIPLIER + cycleSecs - 1) / cycleSecs;
  279 | *   |         _streamsStorageSlot = streamsStorageSlot;
  280 |     |     }
  281 |     | 
  282 |     |     /// @notice Receive streams from unreceived cycles of the account.
  283 |     |     /// Received streams cycles won't need to be analyzed ever again.
  284 |     |     /// @param accountId The account ID.
  285 |     |     /// @param erc20 The used ERC-20 token.
  286 |     |     /// @param maxCycles The maximum number of received streams cycles.
  287 |     |     /// If too low, receiving will be cheap, but may not cover many cycles.
  288 |     |     /// If too high, receiving may become too expensive to fit in a single transaction.
  289 |     |     /// @return receivedAmt The received amount
  290 | *   |     function _receiveStreams(uint256 accountId, IERC20 erc20, uint32 maxCycles)
  291 |     |         internal
  292 | *   |         returns (uint128 receivedAmt)
  293 | *   |     {
  294 | *   |         uint32 receivableCycles;
  295 | *   |         uint32 fromCycle;
  296 | *   |         uint32 toCycle;
  297 | *   |         int128 finalAmtPerCycle;
  298 | *   |         (receivedAmt, receivableCycles, fromCycle, toCycle, finalAmtPerCycle) =
  299 | *   |             _receiveStreamsResult(accountId, erc20, maxCycles);
  300 | *   |         if (fromCycle != toCycle) {
  301 | *   |             StreamsState storage state = _streamsStorage().states[erc20][accountId];
  302 | *   |             state.nextReceivableCycle = toCycle;
  303 | *   |             mapping(uint32 cycle => AmtDelta) storage amtDeltas = state.amtDeltas;
  304 |     |             unchecked {
  305 | *   |                 for (uint32 cycle = fromCycle; cycle < toCycle; cycle++) {
  306 | *   |                     delete amtDeltas[cycle];
  307 |     |                 }
  308 |     |                 // The next cycle delta must be relative to the last received cycle, which deltas
  309 |     |                 // got zeroed. In other words the next cycle delta must be an absolute value.
  310 | *   |                 if (finalAmtPerCycle != 0) {
  311 | *   |                     amtDeltas[toCycle].thisCycle += finalAmtPerCycle;
  312 |     |                 }
  313 |     |             }
  314 |     |         }
  315 | *   |         emit ReceivedStreams(accountId, erc20, receivedAmt, receivableCycles);
  316 |     |     }
  317 |     | 
  318 |     |     /// @notice Calculate effects of calling `_receiveStreams` with the given parameters.
  319 |     |     /// @param accountId The account ID.
  320 |     |     /// @param erc20 The used ERC-20 token.
  321 |     |     /// @param maxCycles The maximum number of received streams cycles.
  322 |     |     /// If too low, receiving will be cheap, but may not cover many cycles.
  323 |     |     /// If too high, receiving may become too expensive to fit in a single transaction.
  324 |     |     /// @return receivedAmt The amount which would be received
  325 |     |     /// @return receivableCycles The number of cycles which would still be receivable after the call
  326 |     |     /// @return fromCycle The cycle from which funds would be received
  327 |     |     /// @return toCycle The cycle to which funds would be received
  328 |     |     /// @return amtPerCycle The amount per cycle when `toCycle` starts.
  329 | *   |     function _receiveStreamsResult(uint256 accountId, IERC20 erc20, uint32 maxCycles)
  330 |     |         internal
  331 |     |         view
  332 |     |         returns (
  333 | *   |             uint128 receivedAmt,
  334 | *   |             uint32 receivableCycles,
  335 | *   |             uint32 fromCycle,
  336 | *   |             uint32 toCycle,
  337 | *   |             int128 amtPerCycle
  338 |     |         )
  339 |     |     {
  340 | *   |         unchecked {
  341 | *   |             (fromCycle, toCycle) = _receivableStreamsCyclesRange(accountId, erc20);
  342 | *   |             if (toCycle - fromCycle > maxCycles) {
  343 | *   |                 receivableCycles = toCycle - fromCycle - maxCycles;
  344 | *   |                 toCycle -= receivableCycles;
  345 |     |             }
  346 | *   |             mapping(uint32 cycle => AmtDelta) storage amtDeltas =
  347 | *   |                 _streamsStorage().states[erc20][accountId].amtDeltas;
  348 | *   |             for (uint32 cycle = fromCycle; cycle < toCycle; cycle++) {
  349 | *   |                 AmtDelta memory amtDelta = amtDeltas[cycle];
  350 | *   |                 amtPerCycle += amtDelta.thisCycle;
  351 |     |                 // This will not overflow if the requirement of tracking in the contract
  352 |     |                 // no more than `_MAX_STREAMS_BALANCE` of each token is followed.
  353 | *   |                 receivedAmt += uint128(amtPerCycle);
  354 | *   |                 amtPerCycle += amtDelta.nextCycle;
  355 |     |             }
  356 |     |         }
  357 |     |     }
  358 |     | 
  359 |     |     /// @notice Counts cycles from which streams can be received.
  360 |     |     /// This function can be used to detect that there are
  361 |     |     /// too many cycles to analyze in a single transaction.
  362 |     |     /// @param accountId The account ID.
  363 |     |     /// @param erc20 The used ERC-20 token.
  364 |     |     /// @return cycles The number of cycles which can be flushed
  365 | *   |     function _receivableStreamsCycles(uint256 accountId, IERC20 erc20)
  366 |     |         internal
  367 |     |         view
  368 | *   |         returns (uint32 cycles)
  369 |     |     {
  370 |     |         unchecked {
  371 | *   |             (uint32 fromCycle, uint32 toCycle) = _receivableStreamsCyclesRange(accountId, erc20);
  372 | *   |             return toCycle - fromCycle;
  373 |     |         }
  374 |     |     }
  375 |     | 
  376 |     |     /// @notice Calculates the cycles range from which streams can be received.
  377 |     |     /// @param accountId The account ID.
  378 |     |     /// @param erc20 The used ERC-20 token.
  379 |     |     /// @return fromCycle The cycle from which funds can be received
  380 |     |     /// @return toCycle The cycle to which funds can be received
  381 | *   |     function _receivableStreamsCyclesRange(uint256 accountId, IERC20 erc20)
  382 |     |         private
  383 |     |         view
  384 | *   |         returns (uint32 fromCycle, uint32 toCycle)
  385 |     |     {
  386 | *   |         fromCycle = _streamsStorage().states[erc20][accountId].nextReceivableCycle;
  387 | *   |         toCycle = _cycleOf(_currTimestamp());
  388 |     |         // slither-disable-next-line timestamp
  389 | *   |         if (fromCycle == 0 || toCycle < fromCycle) {
  390 | *   |             toCycle = fromCycle;
  391 |     |         }
  392 |     |     }
  393 |     | 
  394 |     |     /// @notice Receive streams from the currently running cycle from a single sender.
  395 |     |     /// It doesn't receive streams from the finished cycles, to do that use `_receiveStreams`.
  396 |     |     /// Squeezed funds won't be received in the next calls
  397 |     |     /// to `_squeezeStreams` or `_receiveStreams`.
  398 |     |     /// Only funds streamed before `block.timestamp` can be squeezed.
  399 |     |     /// @param accountId The ID of the account receiving streams to squeeze funds for.
  400 |     |     /// @param erc20 The used ERC-20 token.
  401 |     |     /// @param senderId The ID of the streaming account to squeeze funds from.
  402 |     |     /// @param historyHash The sender's history hash that was valid right before
  403 |     |     /// they set up the sequence of configurations described by `streamsHistory`.
  404 |     |     /// @param streamsHistory The sequence of the sender's streams configurations.
  405 |     |     /// It can start at an arbitrary past configuration, but must describe all the configurations
  406 |     |     /// which have been used since then including the current one, in the chronological order.
  407 |     |     /// Only streams described by `streamsHistory` will be squeezed.
  408 |     |     /// If `streamsHistory` entries have no receivers, they won't be squeezed.
  409 |     |     /// @return amt The squeezed amount.
  410 | *   |     function _squeezeStreams(
  411 |     |         uint256 accountId,
  412 |     |         IERC20 erc20,
  413 |     |         uint256 senderId,
  414 |     |         bytes32 historyHash,
  415 |     |         StreamsHistory[] memory streamsHistory
  416 | *   |     ) internal returns (uint128 amt) {
  417 | *   |         unchecked {
  418 | *   |             uint256 squeezedNum;
  419 | *   |             uint256[] memory squeezedRevIdxs;
  420 | *   |             bytes32[] memory historyHashes;
  421 | *   |             uint256 currCycleConfigs;
  422 | *   |             (amt, squeezedNum, squeezedRevIdxs, historyHashes, currCycleConfigs) =
  423 | *   |                 _squeezeStreamsResult(accountId, erc20, senderId, historyHash, streamsHistory);
  424 | *   |             bytes32[] memory squeezedHistoryHashes = new bytes32[](squeezedNum);
  425 | *   |             StreamsState storage state = _streamsStorage().states[erc20][accountId];
  426 | *   |             uint32[2 ** 32] storage nextSqueezed = state.nextSqueezed[senderId];
  427 | *   |             for (uint256 i = 0; i < squeezedNum; i++) {
  428 |     |                 // `squeezedRevIdxs` are sorted from the newest configuration to the oldest,
  429 |     |                 // but we need to consume them from the oldest to the newest.
  430 | *   |                 uint256 revIdx = squeezedRevIdxs[squeezedNum - i - 1];
  431 | *   |                 squeezedHistoryHashes[i] = historyHashes[historyHashes.length - revIdx];
  432 | *   |                 nextSqueezed[currCycleConfigs - revIdx] = _currTimestamp();
  433 |     |             }
  434 | *   |             uint32 cycleStart = _currCycleStart();
  435 | *   |             _addDeltaRange(
  436 | *   |                 state, cycleStart, cycleStart + 1, -int160(amt * _AMT_PER_SEC_MULTIPLIER)
  437 |     |             );
  438 | *   |             emit SqueezedStreams(accountId, erc20, senderId, amt, squeezedHistoryHashes);
  439 |     |         }
  440 |     |     }
  441 |     | 
  442 |     |     /// @notice Calculate effects of calling `_squeezeStreams` with the given parameters.
  443 |     |     /// See its documentation for more details.
  444 |     |     /// @param accountId The ID of the account receiving streams to squeeze funds for.
  445 |     |     /// @param erc20 The used ERC-20 token.
  446 |     |     /// @param senderId The ID of the streaming account to squeeze funds from.
  447 |     |     /// @param historyHash The sender's history hash that was valid right before `streamsHistory`.
  448 |     |     /// @param streamsHistory The sequence of the sender's streams configurations.
  449 |     |     /// @return amt The squeezed amount.
  450 |     |     /// @return squeezedNum The number of squeezed history entries.
  451 |     |     /// @return squeezedRevIdxs The indexes of the squeezed history entries.
  452 |     |     /// The indexes are reversed, meaning that to get the actual index in an array,
  453 |     |     /// they must counted from the end of arrays, as in `arrayLength - squeezedRevIdxs[i]`.
  454 |     |     /// These indexes can be safely used to access `streamsHistory`, `historyHashes`
  455 |     |     /// and `nextSqueezed` regardless of their lengths.
  456 |     |     /// `squeezeRevIdxs` is sorted ascending, from pointing at the most recent entry to the oldest.
  457 |     |     /// @return historyHashes The history hashes valid
  458 |     |     /// for squeezing each of `streamsHistory` entries.
  459 |     |     /// In other words history hashes which had been valid right before each streams
  460 |     |     /// configuration was set, matching `streamsHistoryHash` emitted in its `StreamsSet`.
  461 |     |     /// The first item is always equal to `historyHash`.
  462 |     |     /// @return currCycleConfigs The number of the sender's
  463 |     |     /// streams configurations which have been seen in the current cycle.
  464 |     |     /// This is also the number of used entries in each of the sender's `nextSqueezed` arrays.
  465 | *   |     function _squeezeStreamsResult(
  466 |     |         uint256 accountId,
  467 |     |         IERC20 erc20,
  468 |     |         uint256 senderId,
  469 |     |         bytes32 historyHash,
  470 |     |         StreamsHistory[] memory streamsHistory
  471 |     |     )
  472 |     |         internal
  473 |     |         view
  474 |     |         returns (
  475 | *   |             uint128 amt,
  476 | *   |             uint256 squeezedNum,
  477 | *   |             uint256[] memory squeezedRevIdxs,
  478 | *   |             bytes32[] memory historyHashes,
  479 | *   |             uint256 currCycleConfigs
  480 |     |         )
  481 | *   |     {
  482 | *   |         {
  483 | *   |             StreamsState storage sender = _streamsStorage().states[erc20][senderId];
  484 | *   |             historyHashes =
  485 | *   |                 _verifyStreamsHistory(historyHash, streamsHistory, sender.streamsHistoryHash);
  486 |     |             // If the last update was not in the current cycle,
  487 |     |             // there's only the single latest history entry to squeeze in the current cycle.
  488 | *   |             currCycleConfigs = 1;
  489 |     |             // slither-disable-next-line timestamp
  490 | *   |             if (sender.updateTime >= _currCycleStart()) {
  491 | *   |                 currCycleConfigs = sender.lastUpdatedCycleConfigs;
  492 |     |             }
  493 |     |         }
  494 | *   |         squeezedRevIdxs = new uint256[](streamsHistory.length);
  495 | *   |         uint32[2 ** 32] storage nextSqueezed =
  496 | *   |             _streamsStorage().states[erc20][accountId].nextSqueezed[senderId];
  497 | *   |         uint32 squeezeEndCap = _currTimestamp();
  498 |     |         unchecked {
  499 | *   |             for (uint256 i = 1; i <= streamsHistory.length && i <= currCycleConfigs; i++) {
  500 | *   |                 StreamsHistory memory historyEntry = streamsHistory[streamsHistory.length - i];
  501 | *   |                 if (historyEntry.receivers.length != 0) {
  502 | *   |                     uint32 squeezeStartCap = nextSqueezed[currCycleConfigs - i];
  503 | *   |                     if (squeezeStartCap < _currCycleStart()) squeezeStartCap = _currCycleStart();
  504 | *   |                     if (squeezeStartCap < historyEntry.updateTime) {
  505 | *   |                         squeezeStartCap = historyEntry.updateTime;
  506 |     |                     }
  507 | *   |                     if (squeezeStartCap < squeezeEndCap) {
  508 | *   |                         squeezedRevIdxs[squeezedNum++] = i;
  509 |     |                         // This will not overflow if the requirement of tracking in the contract
  510 |     |                         // no more than `_MAX_STREAMS_BALANCE` of each token is followed.
  511 | *   |                         amt += _squeezedAmt(accountId, historyEntry, squeezeStartCap, squeezeEndCap);
  512 |     |                     }
  513 |     |                 }
  514 | *   |                 squeezeEndCap = historyEntry.updateTime;
  515 |     |             }
  516 |     |         }
  517 |     |     }
  518 |     | 
  519 |     |     /// @notice Verify a streams history and revert if it's invalid.
  520 |     |     /// @param historyHash The account's history hash that was valid right before `streamsHistory`.
  521 |     |     /// @param streamsHistory The sequence of the account's streams configurations.
  522 |     |     /// @param finalHistoryHash The history hash at the end of `streamsHistory`.
  523 |     |     /// @return historyHashes The history hashes valid
  524 |     |     /// for squeezing each of `streamsHistory` entries.
  525 |     |     /// In other words history hashes which had been valid right before each streams
  526 |     |     /// configuration was set, matching `streamsHistoryHash`es emitted in `StreamsSet`.
  527 |     |     /// The first item is always equal to `historyHash` and `finalHistoryHash` is never included.
  528 | *   |     function _verifyStreamsHistory(
  529 |     |         bytes32 historyHash,
  530 |     |         StreamsHistory[] memory streamsHistory,
  531 |     |         bytes32 finalHistoryHash
  532 | *   |     ) private pure returns (bytes32[] memory historyHashes) {
  533 | *   |         historyHashes = new bytes32[](streamsHistory.length);
  534 | *   |         for (uint256 i = 0; i < streamsHistory.length; i++) {
  535 | *   |             StreamsHistory memory historyEntry = streamsHistory[i];
  536 | *   |             bytes32 streamsHash = historyEntry.streamsHash;
  537 | *   |             if (historyEntry.receivers.length != 0) {
  538 | *   |                 require(streamsHash == 0, "Entry with hash and receivers");
  539 | *   |                 streamsHash = _hashStreams(historyEntry.receivers);
  540 |     |             }
  541 | *   |             historyHashes[i] = historyHash;
  542 | *   |             historyHash = _hashStreamsHistory(
  543 | *   |                 historyHash, streamsHash, historyEntry.updateTime, historyEntry.maxEnd
  544 |     |             );
  545 |     |         }
  546 |     |         // slither-disable-next-line incorrect-equality,timestamp
  547 | *   |         require(historyHash == finalHistoryHash, "Invalid streams history");
  548 |     |     }
  549 |     | 
  550 |     |     /// @notice Calculate the amount squeezable by an account from a single streams history entry.
  551 |     |     /// @param accountId The ID of the account to squeeze streams for.
  552 |     |     /// @param historyEntry The squeezed history entry.
  553 |     |     /// @param squeezeStartCap The squeezed time range start.
  554 |     |     /// @param squeezeEndCap The squeezed time range end.
  555 |     |     /// @return squeezedAmt The squeezed amount.
  556 | *   |     function _squeezedAmt(
  557 |     |         uint256 accountId,
  558 |     |         StreamsHistory memory historyEntry,
  559 |     |         uint32 squeezeStartCap,
  560 |     |         uint32 squeezeEndCap
  561 | *   |     ) private view returns (uint128 squeezedAmt) {
  562 |     |         unchecked {
  563 | *   |             StreamReceiver[] memory receivers = historyEntry.receivers;
  564 |     |             // Binary search for the `idx` of the first occurrence of `accountId`
  565 | *   |             uint256 idx = 0;
  566 | *   |             for (uint256 idxCap = receivers.length; idx < idxCap;) {
  567 | *   |                 uint256 idxMid = (idx + idxCap) / 2;
  568 | *   |                 if (receivers[idxMid].accountId < accountId) {
  569 | *   |                     idx = idxMid + 1;
  570 |     |                 } else {
  571 | *   |                     idxCap = idxMid;
  572 |     |                 }
  573 |     |             }
  574 | *   |             uint32 updateTime = historyEntry.updateTime;
  575 | *   |             uint32 maxEnd = historyEntry.maxEnd;
  576 | *   |             uint256 amt = 0;
  577 | *   |             for (; idx < receivers.length; idx++) {
  578 | *   |                 StreamReceiver memory receiver = receivers[idx];
  579 | *   |                 if (receiver.accountId != accountId) break;
  580 | *   |                 (uint32 start, uint32 end) =
  581 | *   |                     _streamRange(receiver, updateTime, maxEnd, squeezeStartCap, squeezeEndCap);
  582 |     |                 // This will not overflow if the requirement of tracking in the contract
  583 |     |                 // no more than `_MAX_STREAMS_BALANCE` of each token is followed.
  584 | *   |                 amt += _streamedAmt(receiver.config.amtPerSec(), start, end);
  585 |     |             }
  586 | *   |             return uint128(amt);
  587 |     |         }
  588 |     |     }
  589 |     | 
  590 |     |     /// @notice Current account streams state.
  591 |     |     /// @param accountId The account ID.
  592 |     |     /// @param erc20 The used ERC-20 token.
  593 |     |     /// @return streamsHash The current streams receivers list hash, see `_hashStreams`
  594 |     |     /// @return streamsHistoryHash The current streams history hash, see `_hashStreamsHistory`.
  595 |     |     /// @return updateTime The time when streams have been configured for the last time.
  596 |     |     /// @return balance The balance when streams have been configured for the last time.
  597 |     |     /// @return maxEnd The current maximum end time of streaming.
  598 | *   |     function _streamsState(uint256 accountId, IERC20 erc20)
  599 |     |         internal
  600 |     |         view
  601 |     |         returns (
  602 | *   |             bytes32 streamsHash,
  603 | *   |             bytes32 streamsHistoryHash,
  604 | *   |             uint32 updateTime,
  605 | *   |             uint128 balance,
  606 | *   |             uint32 maxEnd
  607 |     |         )
  608 |     |     {
  609 | *   |         StreamsState storage state = _streamsStorage().states[erc20][accountId];
  610 | *   |         return (
  611 | *   |             state.streamsHash,
  612 | *   |             state.streamsHistoryHash,
  613 | *   |             state.updateTime,
  614 | *   |             state.balance,
  615 | *   |             state.maxEnd
  616 |     |         );
  617 |     |     }
  618 |     | 
  619 |     |     /// @notice The account's streams balance at the given timestamp.
  620 |     |     /// @param accountId The account ID.
  621 |     |     /// @param erc20 The used ERC-20 token.
  622 |     |     /// @param currReceivers The current streams receivers list.
  623 |     |     /// It must be exactly the same as the last list set for the account with `_setStreams`.
  624 |     |     /// @param timestamp The timestamp for which balance should be calculated.
  625 |     |     /// It can't be lower than the timestamp of the last call to `_setStreams`.
  626 |     |     /// If it's bigger than `block.timestamp`, then it's a prediction assuming
  627 |     |     /// that `_setStreams` won't be called before `timestamp`.
  628 |     |     /// @return balance The account balance on `timestamp`
  629 | *   |     function _balanceAt(
  630 |     |         uint256 accountId,
  631 |     |         IERC20 erc20,
  632 |     |         StreamReceiver[] memory currReceivers,
  633 |     |         uint32 timestamp
  634 | *   |     ) internal view returns (uint128 balance) {
  635 | *   |         StreamsState storage state = _streamsStorage().states[erc20][accountId];
  636 | *   |         require(timestamp >= state.updateTime, "Timestamp before the last update");
  637 | *   |         _verifyStreamsReceivers(currReceivers, state);
  638 | *   |         return _calcBalance(state.balance, state.updateTime, state.maxEnd, currReceivers, timestamp);
  639 |     |     }
  640 |     | 
  641 |     |     /// @notice Calculates the streams balance at a given timestamp.
  642 |     |     /// @param lastBalance The balance when streaming started.
  643 |     |     /// @param lastUpdate The timestamp when streaming started.
  644 |     |     /// @param maxEnd The maximum end time of streaming.
  645 |     |     /// @param receivers The list of streams receivers.
  646 |     |     /// @param timestamp The timestamp for which balance should be calculated.
  647 |     |     /// It can't be lower than `lastUpdate`.
  648 |     |     /// If it's bigger than `block.timestamp`, then it's a prediction assuming
  649 |     |     /// that `_setStreams` won't be called before `timestamp`.
  650 |     |     /// @return balance The account balance on `timestamp`
  651 | *   |     function _calcBalance(
  652 |     |         uint128 lastBalance,
  653 |     |         uint32 lastUpdate,
  654 |     |         uint32 maxEnd,
  655 |     |         StreamReceiver[] memory receivers,
  656 |     |         uint32 timestamp
  657 | *   |     ) private view returns (uint128 balance) {
  658 |     |         unchecked {
  659 | *   |             balance = lastBalance;
  660 | *   |             for (uint256 i = 0; i < receivers.length; i++) {
  661 | *   |                 StreamReceiver memory receiver = receivers[i];
  662 | *   |                 (uint32 start, uint32 end) = _streamRange({
  663 | *   |                     receiver: receiver,
  664 | *   |                     updateTime: lastUpdate,
  665 | *   |                     maxEnd: maxEnd,
  666 | *   |                     startCap: lastUpdate,
  667 | *   |                     endCap: timestamp
  668 |     |                 });
  669 | *   |                 balance -= uint128(_streamedAmt(receiver.config.amtPerSec(), start, end));
  670 |     |             }
  671 |     |         }
  672 |     |     }
  673 |     | 
  674 |     |     /// @notice Sets the account's streams configuration.
  675 |     |     /// @param accountId The account ID.
  676 |     |     /// @param erc20 The used ERC-20 token.
  677 |     |     /// @param currReceivers The current streams receivers list.
  678 |     |     /// It must be exactly the same as the last list set for the account with `_setStreams`.
  679 |     |     /// If this is the first update, pass an empty array.
  680 |     |     /// @param balanceDelta The streams balance change to be applied.
  681 |     |     /// If it's positive, the balance is increased by `balanceDelta`.
  682 |     |     /// If it's zero, the balance doesn't change.
  683 |     |     /// If it's negative, the balance is decreased by `balanceDelta`,
  684 |     |     /// but the change is capped at the current balance amount, so it doesn't go below 0.
  685 |     |     /// Passing `type(int128).min` always decreases the current balance to 0.
  686 |     |     /// @param newReceivers The list of the streams receivers of the account to be set.
  687 |     |     /// Must be sorted by the account IDs and then by the stream configurations,
  688 |     |     /// without identical elements and without 0 amtPerSecs.
  689 |     |     /// @param maxEndHint1 An optional parameter allowing gas optimization, pass `0` to ignore it.
  690 |     |     /// The first hint for finding the maximum end time when all streams stop due to funds
  691 |     |     /// running out after the balance is updated and the new receivers list is applied.
  692 |     |     /// Hints have no effect on the results of calling this function, except potentially saving gas.
  693 |     |     /// Hints are Unix timestamps used as the starting points for binary search for the time
  694 |     |     /// when funds run out in the range of timestamps from the current block's to `2^32`.
  695 |     |     /// Hints lower than the current timestamp are ignored.
  696 |     |     /// You can provide zero, one or two hints. The order of hints doesn't matter.
  697 |     |     /// Hints are the most effective when one of them is lower than or equal to
  698 |     |     /// the last timestamp when funds are still streamed, and the other one is strictly larger
  699 |     |     /// than that timestamp,the smaller the difference between such hints, the higher gas savings.
  700 |     |     /// The savings are the highest possible when one of the hints is equal to
  701 |     |     /// the last timestamp when funds are still streamed, and the other one is larger by 1.
  702 |     |     /// It's worth noting that the exact timestamp of the block in which this function is executed
  703 |     |     /// may affect correctness of the hints, especially if they're precise.
  704 |     |     /// Hints don't provide any benefits when balance is not enough to cover
  705 |     |     /// a single second of streaming or is enough to cover all streams until timestamp `2^32`.
  706 |     |     /// Even inaccurate hints can be useful, and providing a single hint
  707 |     |     /// or two hints that don't enclose the time when funds run out can still save some gas.
  708 |     |     /// Providing poor hints that don't reduce the number of binary search steps
  709 |     |     /// may cause slightly higher gas usage than not providing any hints.
  710 |     |     /// @param maxEndHint2 An optional parameter allowing gas optimization, pass `0` to ignore it.
  711 |     |     /// The second hint for finding the maximum end time, see `maxEndHint1` docs for more details.
  712 |     |     /// @return realBalanceDelta The actually applied streams balance change.
  713 |     |     /// It's equal to the passed `balanceDelta`, unless it's negative
  714 |     |     /// and it gets capped at the current balance amount.
  715 | *   |     function _setStreams(
  716 |     |         uint256 accountId,
  717 |     |         IERC20 erc20,
  718 |     |         StreamReceiver[] memory currReceivers,
  719 |     |         int128 balanceDelta,
  720 |     |         StreamReceiver[] memory newReceivers,
  721 |     |         // slither-disable-next-line similar-names
  722 |     |         uint32 maxEndHint1,
  723 |     |         uint32 maxEndHint2
  724 | *   |     ) internal returns (int128 realBalanceDelta) {
  725 | *   |         unchecked {
  726 | *   |             StreamsState storage state = _streamsStorage().states[erc20][accountId];
  727 | *   |             _verifyStreamsReceivers(currReceivers, state);
  728 | *   |             uint32 lastUpdate = state.updateTime;
  729 | *   |             uint128 newBalance;
  730 | *   |             uint32 newMaxEnd;
  731 | *   |             {
  732 | *   |                 uint32 currMaxEnd = state.maxEnd;
  733 | *   |                 int128 currBalance = int128(
  734 | *   |                     _calcBalance(
  735 | *   |                         state.balance, lastUpdate, currMaxEnd, currReceivers, _currTimestamp()
  736 |     |                     )
  737 |     |                 );
  738 | *   |                 realBalanceDelta = balanceDelta;
  739 |     |                 // Cap `realBalanceDelta` at withdrawal of the entire `currBalance`
  740 | *   |                 if (realBalanceDelta < -currBalance) {
  741 | *   |                     realBalanceDelta = -currBalance;
  742 |     |                 }
  743 |     |                 // This will not overflow if the requirement of tracking in the contract
  744 |     |                 // no more than `_MAX_STREAMS_BALANCE` of each token is followed.
  745 | *   |                 newBalance = uint128(currBalance + realBalanceDelta);
  746 | *   |                 newMaxEnd = _calcMaxEnd(newBalance, newReceivers, maxEndHint1, maxEndHint2);
  747 | *   |                 _updateReceiverStates(
  748 | *   |                     _streamsStorage().states[erc20],
  749 | *   |                     currReceivers,
  750 | *   |                     lastUpdate,
  751 | *   |                     currMaxEnd,
  752 | *   |                     newReceivers,
  753 | *   |                     newMaxEnd
  754 |     |                 );
  755 |     |             }
  756 | *   |             state.updateTime = _currTimestamp();
  757 | *   |             state.maxEnd = newMaxEnd;
  758 | *   |             state.balance = newBalance;
  759 | *   |             bytes32 streamsHistory = state.streamsHistoryHash;
  760 |     |             // slither-disable-next-line timestamp
  761 | *   |             if (streamsHistory != 0 && _cycleOf(lastUpdate) != _cycleOf(_currTimestamp())) {
  762 | *   |                 state.lastUpdatedCycleConfigs = 2;
  763 |     |             } else {
  764 | *   |                 state.lastUpdatedCycleConfigs++;
  765 |     |             }
  766 | *   |             bytes32 newStreamsHash = _hashStreams(newReceivers);
  767 | *   |             state.streamsHistoryHash =
  768 | *   |                 _hashStreamsHistory(streamsHistory, newStreamsHash, _currTimestamp(), newMaxEnd);
  769 | *   |             emit StreamsSet(accountId, erc20, newStreamsHash, streamsHistory, newBalance, newMaxEnd);
  770 |     |             // slither-disable-next-line timestamp
  771 | *   |             if (newStreamsHash != state.streamsHash) {
  772 | *   |                 state.streamsHash = newStreamsHash;
  773 | *   |                 for (uint256 i = 0; i < newReceivers.length; i++) {
  774 | *   |                     StreamReceiver memory receiver = newReceivers[i];
  775 | *   |                     emit StreamReceiverSeen(newStreamsHash, receiver.accountId, receiver.config);
  776 |     |                 }
  777 |     |             }
  778 |     |         }
  779 |     |     }
  780 |     | 
  781 |     |     /// @notice Verifies that the provided list of receivers is currently active for the account.
  782 |     |     /// @param currReceivers The verified list of receivers.
  783 |     |     /// @param state The account's state.
  784 | *   |     function _verifyStreamsReceivers(
  785 |     |         StreamReceiver[] memory currReceivers,
  786 |     |         StreamsState storage state
  787 |     |     ) private view {
  788 | *   |         require(_hashStreams(currReceivers) == state.streamsHash, "Invalid streams receivers list");
  789 |     |     }
  790 |     | 
  791 |     |     /// @notice Calculates the maximum end time of all streams.
  792 |     |     /// @param balance The balance when streaming starts.
  793 |     |     /// @param receivers The list of streams receivers.
  794 |     |     /// Must be sorted by the account IDs and then by the stream configurations,
  795 |     |     /// without identical elements and without 0 amtPerSecs.
  796 |     |     /// @param hint1 The first hint for finding the maximum end time.
  797 |     |     /// See `_setStreams` docs for `maxEndHint1` for more details.
  798 |     |     /// @param hint2 The second hint for finding the maximum end time.
  799 |     |     /// See `_setStreams` docs for `maxEndHint2` for more details.
  800 |     |     /// @return maxEnd The maximum end time of streaming.
  801 | *   |     function _calcMaxEnd(
  802 |     |         uint128 balance,
  803 |     |         StreamReceiver[] memory receivers,
  804 |     |         uint32 hint1,
  805 |     |         uint32 hint2
  806 | *   |     ) private view returns (uint32 maxEnd) {
  807 | *   |         (uint256[] memory configs, uint256 configsLen) = _buildConfigs(receivers);
  808 |     | 
  809 | *   |         uint256 enoughEnd = _currTimestamp();
  810 |     |         // slither-disable-start incorrect-equality,timestamp
  811 | *   |         if (configsLen == 0 || balance == 0) {
  812 | *   |             return uint32(enoughEnd);
  813 |     |         }
  814 |     | 
  815 | *   |         uint256 notEnoughEnd = type(uint32).max;
  816 | *   |         if (_isBalanceEnough(balance, configs, configsLen, notEnoughEnd)) {
  817 | *   |             return uint32(notEnoughEnd);
  818 |     |         }
  819 |     | 
  820 | *   |         if (hint1 > enoughEnd && hint1 < notEnoughEnd) {
  821 | *   |             if (_isBalanceEnough(balance, configs, configsLen, hint1)) {
  822 | *   |                 enoughEnd = hint1;
  823 |     |             } else {
  824 | *   |                 notEnoughEnd = hint1;
  825 |     |             }
  826 |     |         }
  827 |     | 
  828 | *   |         if (hint2 > enoughEnd && hint2 < notEnoughEnd) {
  829 | *   |             if (_isBalanceEnough(balance, configs, configsLen, hint2)) {
  830 | *   |                 enoughEnd = hint2;
  831 |     |             } else {
  832 | *   |                 notEnoughEnd = hint2;
  833 |     |             }
  834 |     |         }
  835 |     | 
  836 | *   |         while (true) {
  837 | *   |             uint256 end;
  838 |     |             unchecked {
  839 | *   |                 end = (enoughEnd + notEnoughEnd) / 2;
  840 |     |             }
  841 | *   |             if (end == enoughEnd) {
  842 | *   |                 return uint32(end);
  843 |     |             }
  844 | *   |             if (_isBalanceEnough(balance, configs, configsLen, end)) {
  845 | *   |                 enoughEnd = end;
  846 |     |             } else {
  847 | *   |                 notEnoughEnd = end;
  848 |     |             }
  849 |     |         }
  850 |     |         // slither-disable-end incorrect-equality,timestamp
  851 |     |     }
  852 |     | 
  853 |     |     /// @notice Check if a given balance is enough to cover all streams with the given `maxEnd`.
  854 |     |     /// @param balance The balance when streaming starts.
  855 |     |     /// @param configs The list of streams configurations.
  856 |     |     /// @param configsLen The length of `configs`.
  857 |     |     /// @param maxEnd The maximum end time of streaming.
  858 |     |     /// @return isEnough `true` if the balance is enough, `false` otherwise.
  859 | *   |     function _isBalanceEnough(
  860 |     |         uint256 balance,
  861 |     |         uint256[] memory configs,
  862 |     |         uint256 configsLen,
  863 |     |         uint256 maxEnd
  864 | *   |     ) private view returns (bool isEnough) {
  865 |     |         unchecked {
  866 | *   |             uint256 spent = 0;
  867 | *   |             for (uint256 i = 0; i < configsLen; i++) {
  868 | *   |                 (uint256 amtPerSec, uint256 start, uint256 end) = _getConfig(configs, i);
  869 |     |                 // slither-disable-next-line timestamp
  870 | *   |                 if (maxEnd <= start) {
  871 | *   |                     continue;
  872 |     |                 }
  873 |     |                 // slither-disable-next-line timestamp
  874 | *   |                 if (end > maxEnd) {
  875 | *   |                     end = maxEnd;
  876 |     |                 }
  877 | *   |                 spent += _streamedAmt(amtPerSec, start, end);
  878 | *   |                 if (spent > balance) {
  879 | *   |                     return false;
  880 |     |                 }
  881 |     |             }
  882 | *   |             return true;
  883 |     |         }
  884 |     |     }
  885 |     | 
  886 |     |     /// @notice Build a preprocessed list of streams configurations from receivers.
  887 |     |     /// @param receivers The list of streams receivers.
  888 |     |     /// Must be sorted by the account IDs and then by the stream configurations,
  889 |     |     /// without identical elements and without 0 amtPerSecs.
  890 |     |     /// @return configs The list of streams configurations
  891 |     |     /// @return configsLen The length of `configs`
  892 | *   |     function _buildConfigs(StreamReceiver[] memory receivers)
  893 |     |         private
  894 |     |         view
  895 | *   |         returns (uint256[] memory configs, uint256 configsLen)
  896 |     |     {
  897 |     |         unchecked {
  898 | *   |             require(receivers.length <= _MAX_STREAMS_RECEIVERS, "Too many streams receivers");
  899 | *   |             configs = new uint256[](receivers.length);
  900 | *   |             for (uint256 i = 0; i < receivers.length; i++) {
  901 | *   |                 StreamReceiver memory receiver = receivers[i];
  902 | *   |                 if (i > 0) {
  903 | *   |                     require(_isOrdered(receivers[i - 1], receiver), "Streams receivers not sorted");
  904 |     |                 }
  905 | *   |                 configsLen = _addConfig(configs, configsLen, receiver);
  906 |     |             }
  907 |     |         }
  908 |     |     }
  909 |     | 
  910 |     |     /// @notice Preprocess and add a stream receiver to the list of configurations.
  911 |     |     /// @param configs The list of streams configurations
  912 |     |     /// @param configsLen The length of `configs`
  913 |     |     /// @param receiver The added stream receiver.
  914 |     |     /// @return newConfigsLen The new length of `configs`
  915 | *   |     function _addConfig(
  916 |     |         uint256[] memory configs,
  917 |     |         uint256 configsLen,
  918 |     |         StreamReceiver memory receiver
  919 | *   |     ) private view returns (uint256 newConfigsLen) {
  920 | *   |         uint160 amtPerSec = receiver.config.amtPerSec();
  921 | *   |         require(amtPerSec >= _minAmtPerSec, "Stream receiver amtPerSec too low");
  922 | *   |         (uint32 start, uint32 end) =
  923 | *   |             _streamRangeInFuture(receiver, _currTimestamp(), type(uint32).max);
  924 |     |         // slither-disable-next-line incorrect-equality,timestamp
  925 | *   |         if (start == end) {
  926 | *   |             return configsLen;
  927 |     |         }
  928 |     |         // By assignment we get `config` value:
  929 |     |         // `zeros (96 bits) | amtPerSec (160 bits)`
  930 | *   |         uint256 config = amtPerSec;
  931 |     |         // By bit shifting we get `config` value:
  932 |     |         // `zeros (64 bits) | amtPerSec (160 bits) | zeros (32 bits)`
  933 |     |         // By bit masking we get `config` value:
  934 |     |         // `zeros (64 bits) | amtPerSec (160 bits) | start (32 bits)`
  935 | *   |         config = (config << 32) | start;
  936 |     |         // By bit shifting we get `config` value:
  937 |     |         // `zeros (32 bits) | amtPerSec (160 bits) | start (32 bits) | zeros (32 bits)`
  938 |     |         // By bit masking we get `config` value:
  939 |     |         // `zeros (32 bits) | amtPerSec (160 bits) | start (32 bits) | end (32 bits)`
  940 | *   |         config = (config << 32) | end;
  941 | *   |         configs[configsLen] = config;
  942 |     |         unchecked {
  943 | *   |             return configsLen + 1;
  944 |     |         }
  945 |     |     }
  946 |     | 
  947 |     |     /// @notice Load a streams configuration from the list.
  948 |     |     /// @param configs The list of streams configurations
  949 |     |     /// @param idx The loaded configuration index. It must be smaller than the `configs` length.
  950 |     |     /// @return amtPerSec The amount per second being streamed.
  951 |     |     /// @return start The timestamp when streaming starts.
  952 |     |     /// @return end The maximum timestamp when streaming ends.
  953 | *   |     function _getConfig(uint256[] memory configs, uint256 idx)
  954 |     |         private
  955 |     |         pure
  956 | *   |         returns (uint256 amtPerSec, uint256 start, uint256 end)
  957 | *   |     {
  958 | *   |         uint256 config;
  959 |     |         // `config` has value:
  960 |     |         // `zeros (32 bits) | amtPerSec (160 bits) | start (32 bits) | end (32 bits)`
  961 |     |         // slither-disable-next-line assembly
  962 |     |         assembly ("memory-safe") {
  963 | *   |             config := mload(add(32, add(configs, shl(5, idx))))
  964 |     |         }
  965 |     |         // By bit shifting we get value:
  966 |     |         // `zeros (96 bits) | amtPerSec (160 bits)`
  967 | *   |         amtPerSec = config >> 64;
  968 |     |         // By bit shifting we get value:
  969 |     |         // `zeros (64 bits) | amtPerSec (160 bits) | start (32 bits)`
  970 |     |         // By casting down we get value:
  971 |     |         // `start (32 bits)`
  972 | *   |         start = uint32(config >> 32);
  973 |     |         // By casting down we get value:
  974 |     |         // `end (32 bits)`
  975 | *   |         end = uint32(config);
  976 |     |     }
  977 |     | 
  978 |     |     /// @notice Calculates the hash of the streams configuration.
  979 |     |     /// It's used to verify if streams configuration is the previously set one.
  980 |     |     /// @param receivers The list of the streams receivers.
  981 |     |     /// If the streams have never been set, pass an empty array.
  982 |     |     /// @return streamsHash The hash of the streams configuration
  983 | *   |     function _hashStreams(StreamReceiver[] memory receivers)
  984 |     |         internal
  985 |     |         pure
  986 | *   |         returns (bytes32 streamsHash)
  987 |     |     {
  988 | *   |         if (receivers.length == 0) {
  989 | *   |             return bytes32(0);
  990 |     |         }
  991 | *   |         return keccak256(abi.encode(receivers));
  992 |     |     }
  993 |     | 
  994 |     |     /// @notice Calculates the hash of the streams history
  995 |     |     /// after the streams configuration is updated.
  996 |     |     /// @param oldStreamsHistoryHash The history hash
  997 |     |     /// that was valid before the streams were updated.
  998 |     |     /// The `streamsHistoryHash` of an account before they set streams for the first time is `0`.
  999 |     |     /// @param streamsHash The hash of the streams receivers being set.
 1000 |     |     /// @param updateTime The timestamp when the streams were updated.
 1001 |     |     /// @param maxEnd The maximum end of the streams being set.
 1002 |     |     /// @return streamsHistoryHash The hash of the updated streams history.
 1003 | *   |     function _hashStreamsHistory(
 1004 |     |         bytes32 oldStreamsHistoryHash,
 1005 |     |         bytes32 streamsHash,
 1006 |     |         uint32 updateTime,
 1007 |     |         uint32 maxEnd
 1008 | *   |     ) internal pure returns (bytes32 streamsHistoryHash) {
 1009 | *   |         return keccak256(abi.encode(oldStreamsHistoryHash, streamsHash, updateTime, maxEnd));
 1010 |     |     }
 1011 |     | 
 1012 |     |     /// @notice Applies the effects of the change of the streams on the receivers' streams state.
 1013 |     |     /// Only affects `amtDeltas` and `nextReceivableCycle` of the accounts
 1014 |     |     /// present either in `currReceivers` or in `newReceivers`.
 1015 |     |     /// @param states The streams states for the used ERC-20 token.
 1016 |     |     /// @param currReceivers The list of the streams receivers
 1017 |     |     /// set in the last streams update of the account.
 1018 |     |     /// If this is the first update, pass an empty array.
 1019 |     |     /// @param lastUpdate the last time the sender updated the streams.
 1020 |     |     /// If this is the first update, pass zero.
 1021 |     |     /// @param currMaxEnd The maximum end time of streaming according to the last streams update.
 1022 |     |     /// @param newReceivers  The list of the streams receivers of the account to be set.
 1023 |     |     /// Must be sorted by the account IDs and then by the stream configurations,
 1024 |     |     /// without identical elements and without 0 amtPerSecs.
 1025 |     |     /// @param newMaxEnd The maximum end time of streaming according to the new configuration.
 1026 |     |     // slither-disable-next-line cyclomatic-complexity
 1027 | *   |     function _updateReceiverStates(
 1028 |     |         mapping(uint256 accountId => StreamsState) storage states,
 1029 |     |         StreamReceiver[] memory currReceivers,
 1030 |     |         uint32 lastUpdate,
 1031 |     |         uint32 currMaxEnd,
 1032 |     |         StreamReceiver[] memory newReceivers,
 1033 |     |         uint32 newMaxEnd
 1034 | *   |     ) private {
 1035 | *   |         uint256 currIdx = 0;
 1036 | *   |         uint256 newIdx = 0;
 1037 | *   |         while (true) {
 1038 | *   |             bool pickCurr = currIdx < currReceivers.length;
 1039 |     |             // slither-disable-next-line uninitialized-local
 1040 | *   |             StreamReceiver memory currRecv;
 1041 | *   |             if (pickCurr) {
 1042 | *   |                 currRecv = currReceivers[currIdx];
 1043 |     |             }
 1044 |     | 
 1045 | *   |             bool pickNew = newIdx < newReceivers.length;
 1046 |     |             // slither-disable-next-line uninitialized-local
 1047 | *   |             StreamReceiver memory newRecv;
 1048 | *   |             if (pickNew) {
 1049 | *   |                 newRecv = newReceivers[newIdx];
 1050 |     |             }
 1051 |     | 
 1052 |     |             // Limit picking both curr and new to situations when they
 1053 |     |             // differ only by the stream ID, the start or the duration.
 1054 | *   |             if (pickCurr && pickNew) {
 1055 | *   |                 if (
 1056 | *   |                     currRecv.accountId != newRecv.accountId
 1057 | *   |                         || currRecv.config.amtPerSec() != newRecv.config.amtPerSec()
 1058 |     |                 ) {
 1059 | *   |                     pickCurr = _isOrdered(currRecv, newRecv);
 1060 | *   |                     pickNew = !pickCurr;
 1061 |     |                 }
 1062 |     |             }
 1063 |     | 
 1064 | *   |             if (pickCurr && pickNew) {
 1065 |     |                 // Shift the existing stream to fulfil the new configuration
 1066 | *   |                 StreamsState storage state = states[currRecv.accountId];
 1067 | *   |                 (uint32 currStart, uint32 currEnd) =
 1068 | *   |                     _streamRangeInFuture(currRecv, lastUpdate, currMaxEnd);
 1069 | *   |                 (uint32 newStart, uint32 newEnd) =
 1070 | *   |                     _streamRangeInFuture(newRecv, _currTimestamp(), newMaxEnd);
 1071 | *   |                 int256 amtPerSec = int256(uint256(currRecv.config.amtPerSec()));
 1072 |     |                 // Move the start and end times if updated. This has the same effects as calling
 1073 |     |                 // _addDeltaRange(state, currStart, currEnd, -amtPerSec);
 1074 |     |                 // _addDeltaRange(state, newStart, newEnd, amtPerSec);
 1075 |     |                 // but it allows skipping storage access if there's no change to the starts or ends.
 1076 | *   |                 _addDeltaRange(state, currStart, newStart, -amtPerSec);
 1077 | *   |                 _addDeltaRange(state, currEnd, newEnd, amtPerSec);
 1078 |     |                 // Ensure that the account receives the updated cycles
 1079 | *   |                 uint32 currStartCycle = _cycleOf(currStart);
 1080 | *   |                 uint32 newStartCycle = _cycleOf(newStart);
 1081 |     |                 // The `currStartCycle > newStartCycle` check is just an optimization.
 1082 |     |                 // If it's false, then `state.nextReceivableCycle > newStartCycle` must be
 1083 |     |                 // false too, there's no need to pay for the storage access to check it.
 1084 |     |                 // slither-disable-next-line timestamp
 1085 | *   |                 if (currStartCycle > newStartCycle && state.nextReceivableCycle > newStartCycle) {
 1086 | *   |                     state.nextReceivableCycle = newStartCycle;
 1087 |     |                 }
 1088 | *   |             } else if (pickCurr) {
 1089 |     |                 // Remove an existing stream
 1090 |     |                 // slither-disable-next-line similar-names
 1091 | *   |                 StreamsState storage state = states[currRecv.accountId];
 1092 | *   |                 (uint32 start, uint32 end) = _streamRangeInFuture(currRecv, lastUpdate, currMaxEnd);
 1093 |     |                 // slither-disable-next-line similar-names
 1094 | *   |                 int256 amtPerSec = int256(uint256(currRecv.config.amtPerSec()));
 1095 | *   |                 _addDeltaRange(state, start, end, -amtPerSec);
 1096 | *   |             } else if (pickNew) {
 1097 |     |                 // Create a new stream
 1098 | *   |                 StreamsState storage state = states[newRecv.accountId];
 1099 |     |                 // slither-disable-next-line uninitialized-local
 1100 | *   |                 (uint32 start, uint32 end) =
 1101 | *   |                     _streamRangeInFuture(newRecv, _currTimestamp(), newMaxEnd);
 1102 | *   |                 int256 amtPerSec = int256(uint256(newRecv.config.amtPerSec()));
 1103 | *   |                 _addDeltaRange(state, start, end, amtPerSec);
 1104 |     |                 // Ensure that the account receives the updated cycles
 1105 | *   |                 uint32 startCycle = _cycleOf(start);
 1106 |     |                 // slither-disable-next-line timestamp
 1107 | *   |                 uint32 nextReceivableCycle = state.nextReceivableCycle;
 1108 | *   |                 if (nextReceivableCycle == 0 || nextReceivableCycle > startCycle) {
 1109 | *   |                     state.nextReceivableCycle = startCycle;
 1110 |     |                 }
 1111 |     |             } else {
 1112 | *   |                 break;
 1113 |     |             }
 1114 |     | 
 1115 |     |             unchecked {
 1116 | *   |                 if (pickCurr) {
 1117 | *   |                     currIdx++;
 1118 |     |                 }
 1119 | *   |                 if (pickNew) {
 1120 | *   |                     newIdx++;
 1121 |     |                 }
 1122 |     |             }
 1123 |     |         }
 1124 |     |     }
 1125 |     | 
 1126 |     |     /// @notice Calculates the time range in the future in which a receiver will be streamed to.
 1127 |     |     /// @param receiver The stream receiver.
 1128 |     |     /// @param maxEnd The maximum end time of streaming.
 1129 | *   |     function _streamRangeInFuture(StreamReceiver memory receiver, uint32 updateTime, uint32 maxEnd)
 1130 |     |         private
 1131 |     |         view
 1132 | *   |         returns (uint32 start, uint32 end)
 1133 |     |     {
 1134 | *   |         return _streamRange(receiver, updateTime, maxEnd, _currTimestamp(), type(uint32).max);
 1135 |     |     }
 1136 |     | 
 1137 |     |     /// @notice Calculates the time range in which a receiver is to be streamed to.
 1138 |     |     /// This range is capped to provide a view on the stream through a specific time window.
 1139 |     |     /// @param receiver The stream receiver.
 1140 |     |     /// @param updateTime The time when the stream is configured.
 1141 |     |     /// @param maxEnd The maximum end time of streaming.
 1142 |     |     /// @param startCap The timestamp the streaming range start should be capped to.
 1143 |     |     /// @param endCap The timestamp the streaming range end should be capped to.
 1144 | *   |     function _streamRange(
 1145 |     |         StreamReceiver memory receiver,
 1146 |     |         uint32 updateTime,
 1147 |     |         uint32 maxEnd,
 1148 |     |         uint32 startCap,
 1149 |     |         uint32 endCap
 1150 | *   |     ) private pure returns (uint32 start, uint32 end_) {
 1151 | *   |         start = receiver.config.start();
 1152 |     |         // slither-disable-start timestamp
 1153 | *   |         if (start == 0) {
 1154 | *   |             start = updateTime;
 1155 |     |         }
 1156 | *   |         uint40 end;
 1157 |     |         unchecked {
 1158 | *   |             end = uint40(start) + receiver.config.duration();
 1159 |     |         }
 1160 |     |         // slither-disable-next-line incorrect-equality
 1161 | *   |         if (end == start || end > maxEnd) {
 1162 | *   |             end = maxEnd;
 1163 |     |         }
 1164 | *   |         if (start < startCap) {
 1165 | *   |             start = startCap;
 1166 |     |         }
 1167 | *   |         if (end > endCap) {
 1168 | *   |             end = endCap;
 1169 |     |         }
 1170 | *   |         if (end < start) {
 1171 | *   |             end = start;
 1172 |     |         }
 1173 |     |         // slither-disable-end timestamp
 1174 | *   |         return (start, uint32(end));
 1175 |     |     }
 1176 |     | 
 1177 |     |     /// @notice Adds funds received by an account in a given time range
 1178 |     |     /// @param state The account state
 1179 |     |     /// @param start The timestamp from which the delta takes effect
 1180 |     |     /// @param end The timestamp until which the delta takes effect
 1181 |     |     /// @param amtPerSec The streaming rate
 1182 | *   |     function _addDeltaRange(StreamsState storage state, uint32 start, uint32 end, int256 amtPerSec)
 1183 |     |         private
 1184 | *   |     {
 1185 |     |         // slither-disable-next-line incorrect-equality,timestamp
 1186 | *   |         if (start == end) {
 1187 | *   |             return;
 1188 |     |         }
 1189 | *   |         mapping(uint32 cycle => AmtDelta) storage amtDeltas = state.amtDeltas;
 1190 | *   |         _addDelta(amtDeltas, start, amtPerSec);
 1191 | *   |         _addDelta(amtDeltas, end, -amtPerSec);
 1192 |     |     }
 1193 |     | 
 1194 |     |     /// @notice Adds delta of funds received by an account at a given time
 1195 |     |     /// @param amtDeltas The account amount deltas
 1196 |     |     /// @param timestamp The timestamp when the deltas need to be added
 1197 |     |     /// @param amtPerSec The streaming rate
 1198 | *   |     function _addDelta(
 1199 |     |         mapping(uint32 cycle => AmtDelta) storage amtDeltas,
 1200 |     |         uint256 timestamp,
 1201 |     |         int256 amtPerSec
 1202 |     |     ) private {
 1203 | *   |         unchecked {
 1204 |     |             // In order to set a delta on a specific timestamp it must be introduced in two cycles.
 1205 |     |             // These formulas follow the logic from `_streamedAmt`, see it for more details.
 1206 | *   |             int256 amtPerSecMultiplier = int160(_AMT_PER_SEC_MULTIPLIER);
 1207 | *   |             int256 fullCycle = (int256(uint256(_cycleSecs)) * amtPerSec) / amtPerSecMultiplier;
 1208 |     |             // slither-disable-next-line weak-prng
 1209 | *   |             int256 nextCycle = (int256(timestamp % _cycleSecs) * amtPerSec) / amtPerSecMultiplier;
 1210 | *   |             AmtDelta storage amtDelta = amtDeltas[_cycleOf(uint32(timestamp))];
 1211 |     |             // Any over- or under-flows are fine, they're guaranteed to be fixed by a matching
 1212 |     |             // under- or over-flow from the other call to `_addDelta` made by `_addDeltaRange`.
 1213 |     |             // This is because the total balance of `Streams` can never exceed `type(int128).max`,
 1214 |     |             // so in the end no amtDelta can have delta higher than `type(int128).max`.
 1215 | *   |             amtDelta.thisCycle += int128(fullCycle - nextCycle);
 1216 | *   |             amtDelta.nextCycle += int128(nextCycle);
 1217 |     |         }
 1218 |     |     }
 1219 |     | 
 1220 |     |     /// @notice Checks if two receivers fulfil the sortedness requirement of the receivers list.
 1221 |     |     /// @param prev The previous receiver
 1222 |     |     /// @param next The next receiver
 1223 | *   |     function _isOrdered(StreamReceiver memory prev, StreamReceiver memory next)
 1224 |     |         private
 1225 |     |         pure
 1226 | *   |         returns (bool)
 1227 |     |     {
 1228 | *   |         if (prev.accountId != next.accountId) {
 1229 | *   |             return prev.accountId < next.accountId;
 1230 |     |         }
 1231 | *   |         return prev.config.lt(next.config);
 1232 |     |     }
 1233 |     | 
 1234 |     |     /// @notice Calculates the amount streamed over a time range.
 1235 |     |     /// The amount streamed in the `N`th second of each cycle is:
 1236 |     |     /// `(N + 1) * amtPerSec / AMT_PER_SEC_MULTIPLIER - N * amtPerSec / AMT_PER_SEC_MULTIPLIER`.
 1237 |     |     /// For a range of `N`s from `0` to `M` the sum of the streamed amounts is calculated as:
 1238 |     |     /// `M * amtPerSec / AMT_PER_SEC_MULTIPLIER` assuming that `M <= cycleSecs`.
 1239 |     |     /// For an arbitrary time range across multiple cycles the amount
 1240 |     |     /// is calculated as the sum of the amount streamed in the start cycle,
 1241 |     |     /// each of the full cycles in between and the end cycle.
 1242 |     |     /// This algorithm has the following properties:
 1243 |     |     /// - During every second full units are streamed, there are no partially streamed units.
 1244 |     |     /// - Unstreamed fractions are streamed when they add up into full units.
 1245 |     |     /// - Unstreamed fractions don't add up across cycle end boundaries.
 1246 |     |     /// - Some seconds stream 1 unit more to emulate streaming fractions of the unit.
 1247 |     |     /// - Every `N`th second of each cycle streams the same amount.
 1248 |     |     /// - Every full cycle streams the same amount.
 1249 |     |     /// - The amount streamed in a given second is independent from the streaming start and end.
 1250 |     |     /// - Streaming over time ranges `A:B` and then `B:C` is equivalent to streaming over `A:C`.
 1251 |     |     /// - Different streams existing in the system don't interfere with each other.
 1252 |     |     /// @param amtPerSec The streaming rate
 1253 |     |     /// @param start The streaming start time
 1254 |     |     /// @param end The streaming end time
 1255 |     |     /// @return amt The streamed amount
 1256 | *   |     function _streamedAmt(uint256 amtPerSec, uint256 start, uint256 end)
 1257 |     |         private
 1258 |     |         view
 1259 | *   |         returns (uint256 amt)
 1260 |     |     {
 1261 |     |         // This function is written in Yul because it can be called thousands of times
 1262 |     |         // per transaction and it needs to be optimized as much as possible.
 1263 |     |         // As of Solidity 0.8.13, rewriting it in unchecked Solidity triples its gas cost.
 1264 | *   |         uint256 cycleSecs = _cycleSecs;
 1265 |     |         // slither-disable-next-line assembly
 1266 | *   |         assembly {
 1267 | *   |             let endedCycles := sub(div(end, cycleSecs), div(start, cycleSecs))
 1268 |     |             // slither-disable-next-line divide-before-multiply
 1269 | *   |             let amtPerCycle := div(mul(cycleSecs, amtPerSec), _AMT_PER_SEC_MULTIPLIER)
 1270 | *   |             amt := mul(endedCycles, amtPerCycle)
 1271 |     |             // slither-disable-next-line weak-prng
 1272 | *   |             let amtEnd := div(mul(mod(end, cycleSecs), amtPerSec), _AMT_PER_SEC_MULTIPLIER)
 1273 | *   |             amt := add(amt, amtEnd)
 1274 |     |             // slither-disable-next-line weak-prng
 1275 | *   |             let amtStart := div(mul(mod(start, cycleSecs), amtPerSec), _AMT_PER_SEC_MULTIPLIER)
 1276 | *   |             amt := sub(amt, amtStart)
 1277 |     |         }
 1278 |     |     }
 1279 |     | 
 1280 |     |     /// @notice Calculates the cycle containing the given timestamp.
 1281 |     |     /// @param timestamp The timestamp.
 1282 |     |     /// @return cycle The cycle containing the timestamp.
 1283 | *   |     function _cycleOf(uint32 timestamp) private view returns (uint32 cycle) {
 1284 |     |         unchecked {
 1285 | *   |             return timestamp / _cycleSecs + 1;
 1286 |     |         }
 1287 |     |     }
 1288 |     | 
 1289 |     |     /// @notice The current timestamp, casted to the contract's internal representation.
 1290 |     |     /// @return timestamp The current timestamp
 1291 | *   |     function _currTimestamp() private view returns (uint32 timestamp) {
 1292 | *   |         return uint32(block.timestamp);
 1293 |     |     }
 1294 |     | 
 1295 |     |     /// @notice The current cycle start timestamp, casted to the contract's internal representation.
 1296 |     |     /// @return timestamp The current cycle start timestamp
 1297 | *   |     function _currCycleStart() private view returns (uint32 timestamp) {
 1298 |     |         unchecked {
 1299 | *   |             uint32 currTimestamp = _currTimestamp();
 1300 |     |             // slither-disable-next-line weak-prng
 1301 | *   |             return currTimestamp - (currTimestamp % _cycleSecs);
 1302 |     |         }
 1303 |     |     }
 1304 |     | 
 1305 |     |     /// @notice Returns the Streams storage.
 1306 |     |     /// @return streamsStorage The storage.
 1307 | *   |     function _streamsStorage() private view returns (StreamsStorage storage streamsStorage) {
 1308 | *   |         bytes32 slot = _streamsStorageSlot;
 1309 |     |         // slither-disable-next-line assembly
 1310 | *   |         assembly {
 1311 | *   |             streamsStorage.slot := slot
 1312 |     |         }
 1313 |     |     }
 1314 |     | }
 1315 |     | 

/opt/scfuzzbench/work/target/src/echidna/Echidna.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | 
  3 |     | import "./EchidnaInvariantTests.sol";
  4 |     | import "./EchidnaBasicTests.sol";
  5 |     | import "./EchidnaSplitsTests.sol";
  6 |     | import "./EchidnaStreamsTests.sol";
  7 |     | import "./EchidnaSqueezeTests.sol";
  8 |     | 
  9 |     | /**
 10 |     |  * @title Echidna contract for testing the Drips contract
 11 |     |  * @author Rappie <rappie@perimetersec.io>
 12 |     |  * @dev Running the tests:
 13 |     |  * For Echidna use `echidna . --contract Echidna --config echidna-config.yaml`.
 14 |     |  * For Medusa use `medusa fuzz`.
 15 |     |  * The tests are split into multiple files to be able to toggle the fuzzing
 16 |     |  * of specific features on and off. This is done by commenting out the
 17 |     |  * corresponding inherited contract in the Echidna contract below.
 18 |     |  * Basic tests contain basic features like giving, receiving, splitting and
 19 |     |  * collecting.
 20 |     |  * Splits tests contain tests for splitting.
 21 |     |  * Streams tests contain tests for receiving streams.
 22 |     |  * Squeeze tests contain tests for squeezing.
 23 |     |  * Invariant tests contain tests for invariant properties of the system. These
 24 |     |  * make most sense with all other tests enabled.
 25 |     |  * For further performance improvements, resource heavy tests can be toggled.
 26 |     |  * To do so, change the value of TOGGLE_HEAVY_TESTS_ENABLED in EchidnaConfig.
 27 |     |  */
 28 |     | contract Echidna is
 29 |     |     EchidnaBasicTests,
 30 |     |     EchidnaSplitsTests,
 31 |     |     EchidnaStreamsTests,
 32 |     |     EchidnaSqueezeTests,
 33 |     |     EchidnaInvariantTests
 34 |     | {
 35 |     | 
 36 |     | }
 37 |     | 

/opt/scfuzzbench/work/target/src/echidna/EchidnaBasicHelpers.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | 
   3 |     | import "./base/EchidnaBase.sol";
   4 |     | 
   5 |     | /**
   6 |     |  * @title Mixin containing basic helper functions
   7 |     |  * @author Rappie <rappie@perimetersec.io>
   8 |     |  */
   9 |     | contract EchidnaBasicHelpers is EchidnaBase {
  10 |     |     /**
  11 |     |      * @notice Give balance to an account
  12 |     |      * @param fromAccId Account id of the giver
  13 |     |      * @param toAccId Account id of the receiver
  14 |     |      * @param amount Amount to give
  15 |     |      */
  16 | *   |     function give(
  17 |     |         uint8 fromAccId,
  18 |     |         uint8 toAccId,
  19 |     |         uint128 amount
  20 | *   |     ) public {
  21 | *   |         address from = getAccount(fromAccId);
  22 | *   |         address to = getAccount(toAccId);
  23 |     | 
  24 | *   |         uint256 toDripsAccId = getDripsAccountId(to);
  25 |     | 
  26 | *   |         hevm.prank(from);
  27 | *r  |         driver.give(toDripsAccId, token, amount);
  28 |     |     }
  29 |     | 
  30 |     |     /**
  31 |     |      * @notice Give a clamped amount to an account
  32 |     |      * @param fromAccId Account id of the giver
  33 |     |      * @param toAccId Account id of the receiver
  34 |     |      * @param amount Amount to give
  35 |     |      */
  36 | *   |     function giveClampedAmount(
  37 |     |         uint8 fromAccId,
  38 |     |         uint8 toAccId,
  39 |     |         uint128 amount
  40 | *   |     ) public {
  41 | *   |         address from = getAccount(fromAccId);
  42 |     | 
  43 | *   |         uint128 min = 1000;
  44 | *   |         uint128 max = uint128(token.balanceOf(from));
  45 | *   |         uint128 clampedAmount = min + (amount % (max - min + 1));
  46 |     | 
  47 | *   |         give(fromAccId, toAccId, clampedAmount);
  48 |     |     }
  49 |     | 
  50 |     |     /**
  51 |     |      * @notice Receive streams
  52 |     |      * @param targetAccId Account id of the receiver
  53 |     |      * @param maxCycles Maximum number of cycles to receive
  54 |     |      * @return Amount received
  55 |     |      * @dev Receiving means moving receivable (already streamed) balance to
  56 |     |      * splittable (available for splitting) balance
  57 |     |      */
  58 | *   |     function receiveStreams(uint8 targetAccId, uint32 maxCycles)
  59 |     |         public
  60 | *   |         returns (uint128)
  61 |     |     {
  62 | *   |         address target = getAccount(targetAccId);
  63 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  64 |     | 
  65 | *   |         uint128 receivedAmt = drips.receiveStreams(
  66 | *   |             targetDripsAccId,
  67 | *   |             token,
  68 | *   |             maxCycles
  69 |     |         );
  70 |     | 
  71 | *   |         return receivedAmt;
  72 |     |     }
  73 |     | 
  74 |     |     /**
  75 |     |      * @notice Receive streams for all possible cycles
  76 |     |      * @param targetAccId Account id of the receiver
  77 |     |      * @return Amount received
  78 |     |      * @dev We pass maxuint32 to receive all possible cycles
  79 |     |      */
  80 | *   |     function receiveStreamsAllCycles(uint8 targetAccId)
  81 |     |         public
  82 | *   |         returns (uint128)
  83 |     |     {
  84 | *   |         return receiveStreams(targetAccId, type(uint32).max);
  85 |     |     }
  86 |     | 
  87 |     |     /**
  88 |     |      * @notice Split received funds
  89 |     |      * @param targetAccId Account to have their funds split
  90 |     |      * @return Amount collectable and amount split
  91 |     |      * @dev Splitting means moving splittable (available for splitting) balance
  92 |     |      * to collectable (available for collecting) balance
  93 |     |      */
  94 | *   |     function split(uint8 targetAccId) public returns (uint128, uint128) {
  95 | *   |         address target = getAccount(targetAccId);
  96 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  97 |     | 
  98 | *   |         (uint128 collectableAmt, uint128 splitAmt) = drips.split(
  99 | *   |             targetDripsAccId,
 100 | *   |             token,
 101 | *   |             getSplitsReceivers(target)
 102 |     |         );
 103 |     | 
 104 | *   |         return (collectableAmt, splitAmt);
 105 |     |     }
 106 |     | 
 107 |     |     /**
 108 |     |      * @notice Collect funds
 109 |     |      * @param fromAccId Account id of the giver
 110 |     |      * @param toAccId Account id of the receiver
 111 |     |      * @return Amount collected
 112 |     |      * @dev Collecting means moving withdrawing collectable funds to actual
 113 |     |      * balance of the erc20 token
 114 |     |      */
 115 | *   |     function collect(uint8 fromAccId, uint8 toAccId) public returns (uint128) {
 116 | *   |         address from = getAccount(fromAccId);
 117 | *   |         address to = getAccount(toAccId);
 118 |     | 
 119 | *   |         hevm.prank(from);
 120 | *   |         uint128 collected = driver.collect(token, to);
 121 |     | 
 122 | *   |         return collected;
 123 |     |     }
 124 |     | 
 125 |     |     /**
 126 |     |      * @notice Collect funds to self
 127 |     |      * @param targetAccId Target account
 128 |     |      */
 129 | *   |     function collectToSelf(uint8 targetAccId) public {
 130 | *   |         collect(targetAccId, targetAccId);
 131 |     |     }
 132 |     | 
 133 |     |     /**
 134 |     |      * @notice Split and collect funds to self
 135 |     |      * @param targetAccId Target account
 136 |     |      * @dev Extra helper that narrows the search space for the fuzzer
 137 |     |      */
 138 | *   |     function splitAndCollectToSelf(uint8 targetAccId) public {
 139 | *   |         split(targetAccId);
 140 | *   |         collectToSelf(targetAccId);
 141 |     |     }
 142 |     | 
 143 |     |     /**
 144 |     |      * @notice Receive streams, split and collect funds to self
 145 |     |      * @param targetAccId Target account
 146 |     |      * @dev Extra helper that narrows the search space for the fuzzer
 147 |     |      */
 148 | *   |     function receiveStreamsSplitAndCollectToSelf(uint8 targetAccId) public {
 149 | *   |         receiveStreamsAllCycles(targetAccId);
 150 | *   |         splitAndCollectToSelf(targetAccId);
 151 |     |     }
 152 |     | }
 153 |     | 

/opt/scfuzzbench/work/target/src/echidna/EchidnaBasicTests.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | 
   3 |     | import "./base/EchidnaBase.sol";
   4 |     | import "./EchidnaBasicHelpers.sol";
   5 |     | 
   6 |     | /**
   7 |     |  * @title Mixin containing basic tests
   8 |     |  * @author Rappie <rappie@perimetersec.io>
   9 |     |  */
  10 |     | contract EchidnaBasicTests is EchidnaBase, EchidnaBasicHelpers {
  11 |     |     /**
  12 |     |      * @notice Giving an amount `<=` token balance should never revert
  13 |     |      * @param fromAccId Account id of the giver
  14 |     |      * @param toAccId Account id of the receiver
  15 |     |      * @param amount Amount to give
  16 |     |      */
  17 | *   |     function testGiveShouldNotRevert(
  18 |     |         uint8 fromAccId,
  19 |     |         uint8 toAccId,
  20 |     |         uint128 amount
  21 | *   |     ) public {
  22 | *   |         address from = getAccount(fromAccId);
  23 | *   |         address to = getAccount(toAccId);
  24 |     | 
  25 | *   |         uint256 toDripsAccId = getDripsAccountId(to);
  26 |     | 
  27 | *r  |         require(amount <= token.balanceOf(from));
  28 |     | 
  29 | *   |         hevm.prank(from);
  30 | *   |         try driver.give(toDripsAccId, token, amount) {} catch {
  31 |     |             assert(false);
  32 |     |         }
  33 |     |     }
  34 |     | 
  35 |     |     /**
  36 |     |      * @notice Test internal accounting after receiving streams
  37 |     |      * @param targetAccId Account id of the receiver
  38 |     |      * @param maxCycles Maximum number of cycles to receive
  39 |     |      */
  40 | *   |     function testReceiveStreams(uint8 targetAccId, uint32 maxCycles) public {
  41 | *   |         address target = getAccount(targetAccId);
  42 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  43 |     | 
  44 | *   |         uint128 splittableBefore = drips.splittable(targetDripsAccId, token);
  45 | *   |         uint128 receivedAmt = receiveStreams(targetAccId, maxCycles);
  46 | *   |         uint128 splittableAfter = drips.splittable(targetDripsAccId, token);
  47 |     | 
  48 | *   |         assert(splittableAfter == splittableBefore + receivedAmt);
  49 |     | 
  50 | *   |         if (receivedAmt > 0) {
  51 | *   |             assert(splittableAfter > splittableBefore);
  52 |     |         } else {
  53 | *   |             assert(splittableAfter == splittableBefore);
  54 |     |         }
  55 |     |     }
  56 |     | 
  57 |     |     /**
  58 |     |      * @notice Receiving streams should never revert
  59 |     |      * @param targetAccId Account id of the receiver
  60 |     |      */
  61 | *   |     function testReceiveStreamsShouldNotRevert(uint8 targetAccId) public {
  62 | *   |         address target = getAccount(targetAccId);
  63 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  64 |     | 
  65 | *   |         try
  66 | *   |             drips.receiveStreams(targetDripsAccId, token, type(uint32).max)
  67 |     |         {} catch {
  68 |     |             assert(false);
  69 |     |         }
  70 |     |     }
  71 |     | 
  72 |     |     /**
  73 |     |      * @notice If there is a receivable amount, there should be at least one
  74 |     |      * receivable cycle
  75 |     |      * @param targetAccId Account id of the receiver
  76 |     |      * @param maxCycles Maximum number of cycles to receive
  77 |     |      */
  78 | *   |     function testReceiveStreamsViewConsistency(
  79 |     |         uint8 targetAccId,
  80 |     |         uint32 maxCycles
  81 | *   |     ) public {
  82 | *   |         address target = getAccount(targetAccId);
  83 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  84 |     | 
  85 | *r  |         require(maxCycles > 0);
  86 |     | 
  87 | *   |         uint128 receivable = drips.receiveStreamsResult(
  88 | *   |             targetDripsAccId,
  89 | *   |             token,
  90 | *   |             maxCycles
  91 |     |         );
  92 | *   |         uint32 receivableCycles = drips.receivableStreamsCycles(
  93 | *   |             targetDripsAccId,
  94 | *   |             token
  95 |     |         );
  96 |     | 
  97 | *   |         if (receivable > 0) assert(receivableCycles > 0);
  98 |     | 
  99 |     |         // this does not hold because you can have cycles with 0 amount receivable
 100 |     |         // if (receivableCycles > 0) assert(receivable > 0);
 101 |     |     }
 102 |     | 
 103 |     |     /**
 104 |     |      * @notice `drips.receiveStreamsResult` should match actual received amount
 105 |     |      * @param targetAccId Account id of the receiver
 106 |     |      * @param maxCycles Maximum number of cycles to receive
 107 |     |      */
 108 | *   |     function testReceiveStreamsViewVsActual(uint8 targetAccId, uint32 maxCycles)
 109 |     |         public
 110 | *   |     {
 111 | *   |         address target = getAccount(targetAccId);
 112 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
 113 |     | 
 114 | *   |         uint128 receivable = drips.receiveStreamsResult(
 115 | *   |             targetDripsAccId,
 116 | *   |             token,
 117 | *   |             maxCycles
 118 |     |         );
 119 |     | 
 120 | *   |         uint128 received = drips.receiveStreams(
 121 | *   |             targetDripsAccId,
 122 | *   |             token,
 123 | *   |             maxCycles
 124 |     |         );
 125 |     | 
 126 | *   |         assert(receivable == received);
 127 |     |     }
 128 |     | 
 129 |     |     /**
 130 |     |      * @notice Test internal accounting after collecting
 131 |     |      * @param fromAccId Account id of the collector
 132 |     |      * @param toAccId Account id of the receiving account
 133 |     |      */
 134 | *   |     function testCollect(uint8 fromAccId, uint8 toAccId) public {
 135 | *   |         address from = getAccount(fromAccId);
 136 | *   |         address to = getAccount(toAccId);
 137 |     | 
 138 | *   |         uint256 fromDripsAccId = getDripsAccountId(from);
 139 |     | 
 140 | *   |         uint128 colBalBefore = drips.collectable(fromDripsAccId, token);
 141 | *   |         uint256 tokenBalBefore = token.balanceOf(to);
 142 |     | 
 143 | *   |         uint128 collected = collect(fromAccId, toAccId);
 144 |     | 
 145 | *   |         uint128 colBalAfter = drips.collectable(fromDripsAccId, token);
 146 | *   |         uint256 tokenBalAfter = token.balanceOf(to);
 147 |     | 
 148 | *   |         assert(colBalAfter == colBalBefore - collected);
 149 | *   |         assert(tokenBalAfter == tokenBalBefore + collected);
 150 |     |     }
 151 |     | 
 152 |     |     /**
 153 |     |      * @notice Collecting should never revert
 154 |     |      * @param fromAccId Account id of the collector
 155 |     |      * @param toAccId Account id of the receiving account
 156 |     |      */
 157 | *   |     function testCollectShouldNotRevert(uint8 fromAccId, uint8 toAccId) public {
 158 | *   |         address from = getAccount(fromAccId);
 159 | *   |         address to = getAccount(toAccId);
 160 |     | 
 161 | *   |         hevm.prank(from);
 162 | *   |         try driver.collect(token, to) {} catch {
 163 |     |             assert(false);
 164 |     |         }
 165 |     |     }
 166 |     | }
 167 |     | 

/opt/scfuzzbench/work/target/src/echidna/EchidnaInvariantTests.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | 
   3 |     | import "./EchidnaBasicHelpers.sol";
   4 |     | import "./EchidnaSplitsHelpers.sol";
   5 |     | import "./EchidnaStreamsHelpers.sol";
   6 |     | import "./EchidnaSqueezeHelpers.sol";
   7 |     | 
   8 |     | /**
   9 |     |  * @title Mixin containing invariant tests
  10 |     |  * @author Rappie <rappie@perimetersec.io>
  11 |     |  */
  12 |     | contract EchidnaInvariantTests is
  13 |     |     EchidnaBasicHelpers,
  14 |     |     EchidnaSplitsHelpers,
  15 |     |     EchidnaStreamsHelpers,
  16 |     |     EchidnaSqueezeHelpers
  17 |     | {
  18 |     |     /**
  19 |     |      * @notice Withdrawing any amount directly from Drips should fail
  20 |     |      * @param amount Amount to withdraw
  21 |     |      */
  22 | *   |     function invariantWithdrawShouldAlwaysFail(uint256 amount) public {
  23 | *r  |         require(amount > 0, "withdraw amount must be > 0");
  24 |     | 
  25 | *   |         try drips.withdraw(token, address(this), amount) {
  26 |     |             assert(false);
  27 |     |         } catch {}
  28 |     |     }
  29 |     | 
  30 |     |     /**
  31 |     |      * @notice `amtPerSec` should never be lower than `drips.minAmtPerSec()`
  32 |     |      * @param targetAccId Account id of the receiver
  33 |     |      * @param index Index of the receiver
  34 |     |      */
  35 | *   |     function invariantAmtPerSecVsMinAmtPerSec(uint8 targetAccId, uint256 index)
  36 |     |         public
  37 | *   |     {
  38 | *   |         address target = getAccount(targetAccId);
  39 |     | 
  40 | *   |         StreamReceiver[] memory receivers = getStreamReceivers(target);
  41 | *r  |         require(receivers.length > 0, "no receivers");
  42 |     | 
  43 | *   |         index = index % receivers.length;
  44 | *   |         uint160 amtPerSec = receivers[index].config.amtPerSec();
  45 |     | 
  46 | *   |         assert(amtPerSec >= drips.minAmtPerSec());
  47 |     |     }
  48 |     | 
  49 |     |     /**
  50 |     |      * @notice The total of all internal balances should match token balance
  51 |     |      * of the Drips contract
  52 |     |      */
  53 | *   |     function invariantAccountingVsTokenBalance() public {
  54 | *   |         uint256 tokenBalance = token.balanceOf(address(drips));
  55 | *   |         uint256 dripsBalancesTotal = getDripsBalancesTotalForAllUsers();
  56 |     | 
  57 | *   |         assert(tokenBalance == dripsBalancesTotal);
  58 |     |     }
  59 |     | 
  60 |     |     /**
  61 |     |      * @notice Check internal and external balances after withdrawing all funds
  62 |     |      * from the system
  63 |     |      */
  64 | *   |     function invariantWithdrawAllTokens() external heavy {
  65 |     |         // remove all splits to prevent tokens from getting stuck in case
  66 |     |         // there are splits to self
  67 | *   |         removeAllSplits(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER0]);
  68 | *   |         removeAllSplits(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER1]);
  69 | *   |         removeAllSplits(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER2]);
  70 | *   |         removeAllSplits(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER3]);
  71 |     | 
  72 | *   |         squeezeAllSenders(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER0]);
  73 | *   |         squeezeAllSenders(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER1]);
  74 | *   |         squeezeAllSenders(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER2]);
  75 | *   |         squeezeAllSenders(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER3]);
  76 |     | 
  77 | *   |         receiveStreamsSplitAndCollectToSelf(
  78 | *   |             ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER0]
  79 |     |         );
  80 | *   |         receiveStreamsSplitAndCollectToSelf(
  81 | *   |             ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER1]
  82 |     |         );
  83 | *   |         receiveStreamsSplitAndCollectToSelf(
  84 | *   |             ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER2]
  85 |     |         );
  86 | *   |         receiveStreamsSplitAndCollectToSelf(
  87 | *   |             ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER3]
  88 |     |         );
  89 |     | 
  90 | *   |         setStreamBalanceWithdrawAll(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER0]);
  91 | *   |         setStreamBalanceWithdrawAll(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER1]);
  92 | *   |         setStreamBalanceWithdrawAll(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER2]);
  93 | *   |         setStreamBalanceWithdrawAll(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER3]);
  94 |     | 
  95 | *   |         uint256 dripsBalance = token.balanceOf(address(drips));
  96 | *   |         uint256 user0Balance = token.balanceOf(ADDRESS_USER0);
  97 | *   |         uint256 user1Balance = token.balanceOf(ADDRESS_USER1);
  98 | *   |         uint256 user2Balance = token.balanceOf(ADDRESS_USER2);
  99 | *   |         uint256 user3Balance = token.balanceOf(ADDRESS_USER3);
 100 |     | 
 101 | *   |         uint256 totalUserBalance = user0Balance +
 102 | *   |             user1Balance +
 103 | *   |             user2Balance +
 104 | *   |             user3Balance;
 105 |     | 
 106 | *   |         assert(dripsBalance == 0);
 107 | *   |         assert(totalUserBalance == STARTING_BALANCE * 4);
 108 |     |     }
 109 |     | 
 110 |     |     /**
 111 |     |      * @notice Withdrawing all funds from the system should never revert
 112 |     |      */
 113 | *   |     function invariantWithdrawAllTokensShouldNotRevert() public heavy {
 114 | *   |         try
 115 | *   |             EchidnaInvariantTests(address(this)).invariantWithdrawAllTokens()
 116 |     |         {} catch {
 117 |     |             assert(false);
 118 |     |         }
 119 |     |     }
 120 |     | 
 121 |     |     /**
 122 |     |      * @notice The sum of all `amtDelta`s for an account should be zero
 123 |     |      * @param targetAccId Target account to perform the test on
 124 |     |      */
 125 | *   |     function invariantSumAmtDeltaIsZero(uint8 targetAccId) public heavy {
 126 | *   |         address target = getAccount(targetAccId);
 127 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
 128 |     | 
 129 | *   |         uint32 maxEnd = getMaxEndForAllUsers();
 130 |     | 
 131 | *   |         uint32 firstCycle = getCycleFromTimestamp(STARTING_TIMESTAMP);
 132 | *   |         uint32 lastCycle = getCycleFromTimestamp(maxEnd);
 133 |     | 
 134 | *r  |         require(maxEnd > 0, "no cycles");
 135 | *r  |         require(firstCycle != lastCycle, "only one cycle");
 136 |     | 
 137 |     |         // limit amount of cycles for gas & memory savings
 138 | *r  |         require(lastCycle - firstCycle < 1000, "too many cycles");
 139 |     | 
 140 | *   |         int256 sumAmtDelta = 0;
 141 |     | 
 142 | *   |         for (uint32 cycle = firstCycle; cycle <= lastCycle; cycle++) {
 143 | *   |             (int128 thisCycle, int128 nextCycle) = drips.getAmtDeltaForCycle(
 144 | *   |                 targetDripsAccId,
 145 | *   |                 token,
 146 | *   |                 cycle
 147 |     |             );
 148 |     | 
 149 | *   |             sumAmtDelta += int256(thisCycle);
 150 | *   |             sumAmtDelta += int256(nextCycle);
 151 |     |         }
 152 |     | 
 153 | *   |         assert(sumAmtDelta == 0);
 154 |     |     }
 155 |     | }
 156 |     | 

/opt/scfuzzbench/work/target/src/echidna/EchidnaSplitsHelpers.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | 
   3 |     | import "./base/EchidnaBase.sol";
   4 |     | 
   5 |     | /**
   6 |     |  * @title Mixin containing helpers for splitting
   7 |     |  * @author Rappie <rappie@perimetersec.io>
   8 |     |  */
   9 |     | contract EchidnaSplitsHelpers is EchidnaBase {
  10 |     |     /**
  11 |     |      * @notice Internal helper function to set splits receivers
  12 |     |      * @param senderAccId Account id of the sender
  13 |     |      * @param unsortedReceivers Receivers list to set
  14 |     |      * @dev This function also sorts the receivers list
  15 |     |      */
  16 | *   |     function _setSplits(
  17 |     |         uint8 senderAccId,
  18 |     |         SplitsReceiver[] memory unsortedReceivers
  19 | *   |     ) internal {
  20 | *   |         address sender = getAccount(senderAccId);
  21 |     | 
  22 | *   |         SplitsReceiver[] memory newReceivers = bubbleSortSplitsReceivers(
  23 | *   |             unsortedReceivers
  24 |     |         );
  25 |     | 
  26 | *   |         updateSplitsReceivers(sender, newReceivers);
  27 |     | 
  28 | *   |         hevm.prank(sender);
  29 | *r  |         driver.setSplits(newReceivers);
  30 |     |     }
  31 |     | 
  32 |     |     /**
  33 |     |      * @notice Set splits, overwriting the current receivers list
  34 |     |      * @param senderAccId Account id of the sender
  35 |     |      * @param receiverAccId Account id of the receiver in the receivers list
  36 |     |      * @param weight Weight of the receiver
  37 |     |      */
  38 | *   |     function setSplits(
  39 |     |         uint8 senderAccId,
  40 |     |         uint8 receiverAccId,
  41 |     |         uint32 weight
  42 | *   |     ) public {
  43 | *   |         address sender = getAccount(senderAccId);
  44 | *   |         address receiver = getAccount(receiverAccId);
  45 | *   |         uint256 receiverDripsAccId = getDripsAccountId(receiver);
  46 |     | 
  47 | *   |         SplitsReceiver[] memory receivers = new SplitsReceiver[](1);
  48 | *   |         receivers[0] = SplitsReceiver({
  49 | *   |             accountId: receiverDripsAccId,
  50 | *   |             weight: weight
  51 |     |         });
  52 | *   |         updateSplitsReceivers(sender, receivers);
  53 |     | 
  54 | *   |         _setSplits(senderAccId, receivers);
  55 |     |     }
  56 |     | 
  57 |     |     /**
  58 |     |      * @notice Set splits, overwriting the current receivers list
  59 |     |      * @param senderAccId Account id of the sender
  60 |     |      * @param receiverAccId Account id of the receiver in the receivers list
  61 |     |      * @param weight Weight of the receiver
  62 |     |      * @dev This function clamps the weight between the minimum and maximum
  63 |     |      * allowed values
  64 |     |      */
  65 | *   |     function setSplitsWithClamping(
  66 |     |         uint8 senderAccId,
  67 |     |         uint8 receiverAccId,
  68 |     |         uint32 weight
  69 |     |     ) public {
  70 | *   |         weight = clampSplitWeight(weight, 0); // there are no existing weights
  71 | *   |         setSplits(senderAccId, receiverAccId, weight);
  72 |     |     }
  73 |     | 
  74 |     |     /**
  75 |     |      * @notice Add a splits receiver to the existing list of receivers
  76 |     |      * @param senderAccId Account id of the sender
  77 |     |      * @param receiverAccId Account id of the receiver to add
  78 |     |      * @param weight Weight of the receiver
  79 |     |      */
  80 | *   |     function addSplitsReceiver(
  81 |     |         uint8 senderAccId,
  82 |     |         uint8 receiverAccId,
  83 |     |         uint32 weight
  84 | *   |     ) public {
  85 | *   |         address sender = getAccount(senderAccId);
  86 | *   |         address receiver = getAccount(receiverAccId);
  87 | *   |         uint256 senderDripsAccId = getDripsAccountId(sender);
  88 | *   |         uint256 receiverDripsAccId = getDripsAccountId(receiver);
  89 |     | 
  90 | *   |         SplitsReceiver[] memory oldReceivers = getSplitsReceivers(sender);
  91 |     | 
  92 | *   |         SplitsReceiver memory addedReceiver = SplitsReceiver({
  93 | *   |             accountId: receiverDripsAccId,
  94 | *   |             weight: weight
  95 |     |         });
  96 |     | 
  97 | *   |         SplitsReceiver[] memory newReceivers = new SplitsReceiver[](
  98 | *   |             oldReceivers.length + 1
  99 |     |         );
 100 | *   |         for (uint256 i = 0; i < oldReceivers.length; i++) {
 101 | *   |             newReceivers[i] = oldReceivers[i];
 102 |     |         }
 103 | *   |         newReceivers[newReceivers.length - 1] = addedReceiver;
 104 |     | 
 105 | *   |         _setSplits(senderAccId, newReceivers);
 106 |     |     }
 107 |     | 
 108 |     |     /**
 109 |     |      * @notice Add a splits receiver to the existing list of receivers
 110 |     |      * @param senderAccId Account id of the sender
 111 |     |      * @param receiverAccId Account id of the receiver to add
 112 |     |      * @param weight Weight of the receiver
 113 |     |      * @dev This function clamps the weight between the minimum and maximum
 114 |     |      * allowed values
 115 |     |      */
 116 | *   |     function addSplitsReceiverWithClamping(
 117 |     |         uint8 senderAccId,
 118 |     |         uint8 receiverAccId,
 119 |     |         uint32 weight
 120 | *   |     ) public {
 121 | *   |         address sender = getAccount(senderAccId);
 122 |     | 
 123 |     |         // sum all the existing weights
 124 | *   |         uint32 existingWeights;
 125 | *   |         SplitsReceiver[] memory receivers = getSplitsReceivers(sender);
 126 | *   |         for (uint256 i = 0; i < receivers.length; i++) {
 127 | *   |             existingWeights += receivers[i].weight;
 128 |     |         }
 129 |     | 
 130 |     |         // we can't add a receiver if it makes the total weight go over the
 131 |     |         // maximum allowed
 132 | *   |         if (existingWeights >= drips.TOTAL_SPLITS_WEIGHT()) return;
 133 |     | 
 134 | *   |         weight = clampSplitWeight(weight, existingWeights);
 135 |     | 
 136 | *   |         addSplitsReceiver(senderAccId, receiverAccId, weight);
 137 |     |     }
 138 |     | 
 139 |     |     /**
 140 |     |      * @notice Remove any existing splits
 141 |     |      * @param targetAccId Target account id
 142 |     |      */
 143 | *   |     function removeAllSplits(uint8 targetAccId) public {
 144 | *   |         SplitsReceiver[] memory receivers = new SplitsReceiver[](0);
 145 | *   |         _setSplits(targetAccId, receivers);
 146 |     |     }
 147 |     | 
 148 |     |     /**
 149 |     |      * @notice Clamp the weight between the minimum and maximum allowed values
 150 |     |      * @param weight Weight to clamp
 151 |     |      * @param existingWeights Sum of all the existing weights
 152 |     |      * @return Clamped weight
 153 |     |      */
 154 | *   |     function clampSplitWeight(uint32 weight, uint32 existingWeights)
 155 |     |         public
 156 |     |         view
 157 | *   |         returns (uint32)
 158 |     |     {
 159 | *   |         return (weight % (drips.TOTAL_SPLITS_WEIGHT() - existingWeights)) + 1;
 160 |     |     }
 161 |     | }
 162 |     | 

/opt/scfuzzbench/work/target/src/echidna/EchidnaSplitsTests.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | 
   3 |     | import "./base/EchidnaBase.sol";
   4 |     | import "./EchidnaBasicHelpers.sol";
   5 |     | import "./EchidnaSplitsHelpers.sol";
   6 |     | 
   7 |     | /**
   8 |     |  * @title Mixin containing tests for splitting
   9 |     |  * @author Rappie <rappie@perimetersec.io>
  10 |     |  */
  11 |     | contract EchidnaSplitsTests is
  12 |     |     EchidnaBase,
  13 |     |     EchidnaBasicHelpers,
  14 |     |     EchidnaSplitsHelpers
  15 |     | {
  16 |     |     /**
  17 |     |      * @notice Test internal accounting for splittable amount after splitting
  18 |     |      * @param targetAccId Account id execute split on
  19 |     |      */
  20 | *   |     function testSplittableAfterSplit(uint8 targetAccId) public {
  21 | *   |         address target = getAccount(targetAccId);
  22 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  23 |     | 
  24 | *   |         uint128 splittableBefore = drips.splittable(targetDripsAccId, token);
  25 |     | 
  26 |     |         // check if we are splitting to ourselves
  27 | *   |         uint32 splitToSelfWeight;
  28 | *   |         SplitsReceiver[] memory receivers = getSplitsReceivers(target);
  29 | *   |         for (uint256 i = 0; i < receivers.length; i++) {
  30 | *   |             if (receivers[i].accountId == targetDripsAccId) {
  31 | *   |                 splitToSelfWeight += receivers[i].weight;
  32 |     |             }
  33 |     |         }
  34 |     | 
  35 |     |         // calculate amount to split to self
  36 | *   |         uint128 splitToSelfAmount = uint128(
  37 | *   |             (splittableBefore * splitToSelfWeight) / drips.TOTAL_SPLITS_WEIGHT()
  38 |     |         );
  39 |     | 
  40 | *   |         (uint128 collectableAmt, uint128 splitAmt) = split(targetAccId);
  41 |     | 
  42 | *   |         uint128 splittableAfter = drips.splittable(targetDripsAccId, token);
  43 |     | 
  44 |     |         // sanity check
  45 | *   |         assert((splitAmt + collectableAmt) <= splittableBefore);
  46 |     | 
  47 | *   |         if (splitToSelfWeight == 0) {
  48 |     |             // if we're not splitting to ourselves, things are simple
  49 | *   |             assert(
  50 | *   |                 splittableAfter == splittableBefore - splitAmt - collectableAmt
  51 |     |             );
  52 | *   |         } else {
  53 |     |             // if we ARE splitting to ourselves, there are rounding errors
  54 |     |             // to take into account.
  55 |     | 
  56 |     |             // calculate expected amount after the split
  57 | *   |             uint128 expectedSplittableAfter = splittableBefore -
  58 | *   |                 splitAmt -
  59 | *   |                 collectableAmt +
  60 | *   |                 splitToSelfAmount;
  61 |     | 
  62 |     |             // calculate difference between expected and actual
  63 | *   |             int256 difference = int256(uint256(splittableAfter)) -
  64 | *   |                 int256(uint256(expectedSplittableAfter));
  65 |     | 
  66 |     |             // check if difference is within tolerance
  67 | *   |             assert(
  68 | *   |                 difference >= -int256(SPLIT_ROUNDING_TOLERANCE) &&
  69 | *   |                     difference <= int256(SPLIT_ROUNDING_TOLERANCE)
  70 |     |             );
  71 |     |         }
  72 |     |     }
  73 |     | 
  74 |     |     /**
  75 |     |      * @notice Test internal accounting for collectable amount after splitting
  76 |     |      * @param targetAccId Account id execute split on
  77 |     |      */
  78 | *   |     function testCollectableAfterSplit(uint8 targetAccId) public {
  79 | *   |         address target = getAccount(targetAccId);
  80 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  81 |     | 
  82 | *   |         uint128 colBalBefore = drips.collectable(targetDripsAccId, token);
  83 | *   |         (uint128 collectableAmt, ) = split(targetAccId);
  84 | *   |         uint128 colBalAfter = drips.collectable(targetDripsAccId, token);
  85 |     | 
  86 | *   |         assert(colBalAfter == colBalBefore + collectableAmt);
  87 |     |     }
  88 |     | 
  89 |     |     /**
  90 |     |      * @notice After splitting, all receivers should have their splittable
  91 |     |      * amount increased by the amount they were supposed to receive
  92 |     |      * @param targetAccId Account id execute split on
  93 |     |      */
  94 | *   |     function testReceiversReceivedSplit(uint8 targetAccId) public {
  95 | *   |         address target = getAccount(targetAccId);
  96 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  97 |     | 
  98 | *   |         uint128 amountToBeSplit = drips.splittable(targetDripsAccId, token);
  99 | *   |         SplitsReceiver[] memory receivers = getSplitsReceivers(target);
 100 |     | 
 101 |     |         // storage for all receivers
 102 | *   |         uint128[] memory splittableBefore = new uint128[](receivers.length);
 103 | *   |         uint128[] memory splittableAfter = new uint128[](receivers.length);
 104 | *   |         uint32[] memory weights = new uint32[](receivers.length);
 105 | *   |         uint128[] memory amounts = new uint128[](receivers.length);
 106 |     | 
 107 | *   |         for (uint256 i = 0; i < receivers.length; i++) {
 108 |     |             // store splittable before
 109 | *   |             splittableBefore[i] = drips.splittable(
 110 | *   |                 receivers[i].accountId,
 111 | *   |                 token
 112 |     |             );
 113 |     | 
 114 |     |             // calculate amount the receiver should get
 115 | *   |             weights[i] = receivers[i].weight;
 116 | *   |             amounts[i] = uint128(
 117 | *   |                 (amountToBeSplit * weights[i]) / drips.TOTAL_SPLITS_WEIGHT()
 118 |     |             );
 119 |     |         }
 120 |     | 
 121 |     |         // split
 122 | *   |         (uint128 collectableAmt, uint128 splitAmt) = split(targetAccId);
 123 |     | 
 124 |     |         // store splittable after
 125 | *   |         for (uint256 i = 0; i < receivers.length; i++) {
 126 | *   |             splittableAfter[i] = drips.splittable(
 127 | *   |                 receivers[i].accountId,
 128 | *   |                 token
 129 |     |             );
 130 |     |         }
 131 |     | 
 132 | *   |         for (uint256 i = 0; i < receivers.length; i++) {
 133 |     |             // calculate expected amount after the split
 134 | *   |             uint128 expectedAfter;
 135 | *   |             if (receivers[i].accountId != targetDripsAccId) {
 136 |     |                 // splitting so someone else is trivial
 137 | *   |                 expectedAfter = splittableBefore[i] + amounts[i];
 138 |     |             } else {
 139 |     |                 // splitting to self needs to take into account that the splittable
 140 |     |                 // amount before contains the actual amount that was split to all
 141 |     |                 // the receivers. we should end up with only the amount that was
 142 |     |                 // split to ourselves
 143 | *   |                 expectedAfter =
 144 | *   |                     splittableBefore[i] -
 145 | *   |                     amountToBeSplit +
 146 | *   |                     amounts[i];
 147 |     |             }
 148 |     | 
 149 |     |             // calculate difference between expected and actual
 150 | *   |             int256 difference = int256(uint256(splittableAfter[i])) -
 151 | *   |                 int256(uint256(expectedAfter));
 152 |     | 
 153 |     |             // check if difference is within tolerance
 154 | *   |             assert(
 155 | *   |                 difference >= -int256(SPLIT_ROUNDING_TOLERANCE) &&
 156 | *   |                     difference <= int256(SPLIT_ROUNDING_TOLERANCE)
 157 |     |             );
 158 |     |         }
 159 |     |     }
 160 |     | 
 161 |     |     /**
 162 |     |      * @notice `drips.splitResult` should match actual split amount
 163 |     |      * @param targetAccId Account id execute split on
 164 |     |      */
 165 | *   |     function testSplitViewVsActual(uint8 targetAccId) public {
 166 | *   |         address target = getAccount(targetAccId);
 167 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
 168 |     | 
 169 | *   |         uint128 splittable = drips.splittable(targetDripsAccId, token);
 170 |     | 
 171 | *   |         (uint128 collectableAmtView, uint128 splitAmtView) = drips.splitResult(
 172 | *   |             targetDripsAccId,
 173 | *   |             getSplitsReceivers(target),
 174 | *   |             splittable
 175 |     |         );
 176 |     | 
 177 | *   |         (uint128 collectableAmtActual, uint128 splitAmtActual) = split(
 178 | *   |             targetAccId
 179 |     |         );
 180 |     | 
 181 | *   |         assert(collectableAmtView == collectableAmtActual);
 182 | *   |         assert(splitAmtView == splitAmtActual);
 183 |     |     }
 184 |     | 
 185 |     |     /**
 186 |     |      * @notice Splitting should never revert
 187 |     |      * @param targetAccId Account id execute split on
 188 |     |      */
 189 | *   |     function testSplitShouldNotRevert(uint8 targetAccId) public {
 190 | *   |         address target = getAccount(targetAccId);
 191 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
 192 |     | 
 193 | *   |         try EchidnaBasicHelpers(address(this)).split(targetAccId) {} catch {
 194 |     |             assert(false);
 195 |     |         }
 196 |     |     }
 197 |     | 
 198 |     |     /**
 199 |     |      * @notice Setting splits with sane defaults should not revert
 200 |     |      * @param senderAccId Account id of the sender
 201 |     |      * @param receiverAccId Account id of the receiver in the receivers list
 202 |     |      * @param weight Weight of the receiver
 203 |     |      */
 204 | *   |     function testSetSplitsShouldNotRevert(
 205 |     |         uint8 senderAccId,
 206 |     |         uint8 receiverAccId,
 207 |     |         uint32 weight
 208 |     |     ) public {
 209 | *   |         try
 210 | *   |             EchidnaSplitsHelpers(address(this)).setSplitsWithClamping(
 211 | *   |                 senderAccId,
 212 | *   |                 receiverAccId,
 213 | *   |                 weight
 214 |     |             )
 215 |     |         {} catch {
 216 |     |             assert(false);
 217 |     |         }
 218 |     |     }
 219 |     | 
 220 |     |     /**
 221 |     |      * @notice Adding splits with sane defaults should not revert
 222 |     |      * @param senderAccId Account id of the sender
 223 |     |      * @param receiverAccId Account id of the receiver in the receivers list
 224 |     |      * @param weight Weight of the receiver
 225 |     |      */
 226 | *   |     function testAddSplitsShouldNotRevert(
 227 |     |         uint8 senderAccId,
 228 |     |         uint8 receiverAccId,
 229 |     |         uint32 weight
 230 |     |     ) public {
 231 | *   |         try
 232 | *   |             EchidnaSplitsHelpers(address(this)).addSplitsReceiverWithClamping(
 233 | *   |                 senderAccId,
 234 | *   |                 receiverAccId,
 235 | *   |                 weight
 236 |     |             )
 237 | *   |         {} catch (bytes memory reason) {
 238 | *   |             bytes4 errorSelector = bytes4(reason);
 239 | *   |             if (errorSelector == EchidnaStorage.DuplicateError.selector) {
 240 |     |                 // ignore this case, it means we tried to add a duplicate stream
 241 |     |             } else {
 242 |     |                 assert(false);
 243 |     |             }
 244 |     |         }
 245 |     |     }
 246 |     | }
 247 |     | 

/opt/scfuzzbench/work/target/src/echidna/EchidnaSqueezeHelpers.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | 
   3 |     | import "./base/EchidnaBase.sol";
   4 |     | import "./EchidnaBasicHelpers.sol";
   5 |     | 
   6 |     | /**
   7 |     |  * @title Mixin containing helpers for squeezing
   8 |     |  * @author Rappie <rappie@perimetersec.io>
   9 |     |  */
  10 |     | contract EchidnaSqueezeHelpers is EchidnaBase, EchidnaBasicHelpers {
  11 |     |     /**
  12 |     |      * @notice Internal helper function to squeeze streams
  13 |     |      * @param receiverAccId Account id of the receiver
  14 |     |      * @param senderAccId Account id of the sender
  15 |     |      * @param historyHash Hash of the streams history
  16 |     |      * @param history Streams history array
  17 |     |      * @return Amount squeezed
  18 |     |      */
  19 | *   |     function _squeeze(
  20 |     |         uint8 receiverAccId,
  21 |     |         uint8 senderAccId,
  22 |     |         bytes32 historyHash,
  23 |     |         StreamsHistory[] memory history
  24 | *   |     ) internal returns (uint128) {
  25 | *   |         address receiver = getAccount(receiverAccId);
  26 | *   |         address sender = getAccount(senderAccId);
  27 | *   |         uint256 receiverDripsAccId = getDripsAccountId(receiver);
  28 | *   |         uint256 senderDripsAccId = getDripsAccountId(sender);
  29 |     | 
  30 | *   |         uint128 amount = drips.squeezeStreams(
  31 | *   |             receiverDripsAccId,
  32 | *   |             token,
  33 | *   |             senderDripsAccId,
  34 | *   |             historyHash,
  35 | *   |             history
  36 |     |         );
  37 |     | 
  38 | *   |         return amount;
  39 |     |     }
  40 |     | 
  41 |     |     /**
  42 |     |      * @notice Squeeze streams with default history (all StreamHistory entries)
  43 |     |      * @param receiverAccId Account id of the receiver
  44 |     |      * @param senderAccId Account id of the sender
  45 |     |      * @return Amount squeezed
  46 |     |      */
  47 | *   |     function squeezeWithDefaultHistory(uint8 receiverAccId, uint8 senderAccId)
  48 |     |         public
  49 | *   |         returns (uint128)
  50 |     |     {
  51 | *   |         return
  52 | *   |             _squeeze(
  53 | *   |                 receiverAccId,
  54 | *   |                 senderAccId,
  55 | *   |                 bytes32(0),
  56 | *   |                 getStreamsHistory(getAccount(senderAccId))
  57 |     |             );
  58 |     |     }
  59 |     | 
  60 |     |     /**
  61 |     |      * @notice Squeeze streams with a fuzzed history
  62 |     |      * @param receiverAccId Account id of the receiver
  63 |     |      * @param senderAccId Account id of the sender
  64 |     |      * @param hashIndex Index of the history hash to use
  65 |     |      * @param receiversRandomSeed Random seed used for fuzzing the history
  66 |     |      * @return Amount squeezed
  67 |     |      * @dev This function will use the seed to make random changes to the history.
  68 |     |      * These include changing the starting point of the history, and hashing
  69 |     |      * certain history entries to leave them out of the squeeze.
  70 |     |      */
  71 | *   |     function squeezeWithFuzzedHistory(
  72 |     |         uint8 receiverAccId,
  73 |     |         uint8 senderAccId,
  74 |     |         uint256 hashIndex,
  75 |     |         bytes32 receiversRandomSeed
  76 | *   |     ) public returns (uint128) {
  77 | *   |         address receiver = getAccount(receiverAccId);
  78 | *   |         address sender = getAccount(senderAccId);
  79 | *   |         uint256 receiverDripsAccId = getDripsAccountId(receiver);
  80 | *   |         uint256 senderDripsAccId = getDripsAccountId(sender);
  81 |     | 
  82 | *   |         (
  83 | *   |             bytes32 historyHash,
  84 | *   |             StreamsHistory[] memory history
  85 | *   |         ) = getFuzzedStreamsHistory(
  86 | *   |                 senderAccId,
  87 | *   |                 hashIndex,
  88 | *   |                 receiversRandomSeed
  89 |     |             );
  90 |     | 
  91 | *   |         return _squeeze(receiverAccId, senderAccId, historyHash, history);
  92 |     |     }
  93 |     | 
  94 |     |     /**
  95 |     |      * @notice Squeeze streams sent to self
  96 |     |      * @param targetAccId Account id of the sender
  97 |     |      */
  98 | *   |     function squeezeToSelf(uint8 targetAccId) public {
  99 | *   |         squeezeWithDefaultHistory(targetAccId, targetAccId);
 100 |     |     }
 101 |     | 
 102 |     |     /**
 103 |     |      * @notice Squeeze streams from all possible senders to target
 104 |     |      * @param targetAccId Account id of the receiver
 105 |     |      * @dev This can be used to test extracting all value from the system
 106 |     |      */
 107 | *   |     function squeezeAllSenders(uint8 targetAccId) public {
 108 | *   |         squeezeWithDefaultHistory(
 109 | *   |             targetAccId,
 110 | *   |             ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER0]
 111 |     |         );
 112 | *   |         squeezeWithDefaultHistory(
 113 | *   |             targetAccId,
 114 | *   |             ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER1]
 115 |     |         );
 116 | *   |         squeezeWithDefaultHistory(
 117 | *   |             targetAccId,
 118 | *   |             ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER2]
 119 |     |         );
 120 | *   |         squeezeWithDefaultHistory(
 121 | *   |             targetAccId,
 122 | *   |             ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER3]
 123 |     |         );
 124 |     |     }
 125 |     | 
 126 |     |     /**
 127 |     |      * @notice Squeeze all senders, receive streams, split and collect funds to self
 128 |     |      * @param targetAccId Target account
 129 |     |      * @dev Extra helper that narrows the search space for the fuzzer
 130 |     |      */
 131 | *   |     function squeezeAllAndReceiveAndSplitAndCollectToSelf(uint8 targetAccId)
 132 |     |         public
 133 |     |     {
 134 | *   |         squeezeAllSenders(targetAccId);
 135 | *   |         receiveStreamsSplitAndCollectToSelf(targetAccId);
 136 |     |     }
 137 |     | 
 138 |     |     /**
 139 |     |      * @notice Helper to create a fuzzed version of a sender's streams history
 140 |     |      * @param targetAccId Account id of the sender
 141 |     |      * @param hashIndex Index of the history entry to be used as the starting point
 142 |     |      * @param receiversRandomSeed Random seed used to determine which history entries
 143 |     |      * to leave out of the squeeze (by hashing them)
 144 |     |      * @return Hash of the history, and the fuzzed streams history array
 145 |     |      */
 146 | *   |     function getFuzzedStreamsHistory(
 147 |     |         uint8 targetAccId,
 148 |     |         uint256 hashIndex,
 149 |     |         bytes32 receiversRandomSeed
 150 | *   |     ) internal returns (bytes32, StreamsHistory[] memory) {
 151 | *   |         address target = getAccount(targetAccId);
 152 |     | 
 153 |     |         // get the history structs and hashes
 154 | *   |         StreamsHistory[] memory historyStructs = getStreamsHistory(target);
 155 | *   |         bytes32[] memory historyHashes = getStreamsHistoryHashes(target);
 156 |     | 
 157 |     |         // having a hashed history requires at least 2 history entries
 158 | *r  |         require(historyStructs.length >= 2, "need at least 2 history entries");
 159 |     | 
 160 |     |         // hashIndex must be within bounds and cant be the last entry
 161 | *   |         hashIndex = hashIndex % (historyHashes.length - 1);
 162 |     | 
 163 |     |         // get the history hash at the index
 164 | *   |         bytes32 historyHash = historyHashes[hashIndex];
 165 |     | 
 166 |     |         // create a history array with all entries after the hashIndex
 167 | *   |         StreamsHistory[] memory history = new StreamsHistory[](
 168 | *   |             historyStructs.length - 1 - hashIndex
 169 |     |         );
 170 | *   |         for (uint256 i = hashIndex + 1; i < historyStructs.length; i++) {
 171 | *   |             history[i - hashIndex - 1] = historyStructs[i];
 172 |     |         }
 173 |     | 
 174 |     |         // hash receivers based on 'receiversRandomSeed'
 175 | *   |         for (uint256 i = 0; i < history.length; i++) {
 176 | *   |             receiversRandomSeed = keccak256(bytes.concat(receiversRandomSeed));
 177 | *   |             bool hashBool = (uint256(receiversRandomSeed) % 2) == 0
 178 | *   |                 ? false
 179 | *   |                 : true;
 180 |     | 
 181 | *   |             if (hashBool) {
 182 | *   |                 history[i].streamsHash = drips.hashStreams(
 183 | *   |                     history[i].receivers
 184 |     |                 );
 185 | *   |                 history[i].receivers = new StreamReceiver[](0);
 186 |     |             }
 187 |     |         }
 188 |     | 
 189 | *   |         return (historyHash, history);
 190 |     |     }
 191 |     | }
 192 |     | 

/opt/scfuzzbench/work/target/src/echidna/EchidnaSqueezeTests.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | 
   3 |     | import "./EchidnaBasicHelpers.sol";
   4 |     | import "./EchidnaSplitsHelpers.sol";
   5 |     | import "./EchidnaStreamsHelpers.sol";
   6 |     | import "./EchidnaSqueezeHelpers.sol";
   7 |     | 
   8 |     | /**
   9 |     |  * @title Mixin containing tests for squeezing
  10 |     |  * @author Rappie <rappie@perimetersec.io>
  11 |     |  */
  12 |     | contract EchidnaSqueezeTests is
  13 |     |     EchidnaBasicHelpers,
  14 |     |     EchidnaSplitsHelpers,
  15 |     |     EchidnaStreamsHelpers,
  16 |     |     EchidnaSqueezeHelpers
  17 |     | {
  18 |     |     /**
  19 |     |      * @notice Test internal accounting after squeezing
  20 |     |      * @param receiverAccId Account id of the receiver
  21 |     |      * @param senderAccId Account id of the sender
  22 |     |      */
  23 | *   |     function testSqueeze(uint8 receiverAccId, uint8 senderAccId) public {
  24 | *   |         address receiver = getAccount(receiverAccId);
  25 | *   |         address sender = getAccount(senderAccId);
  26 |     | 
  27 | *   |         uint256 receiverDripsAccId = getDripsAccountId(receiver);
  28 |     | 
  29 | *   |         uint128 squeezableBefore = getSqueezableAmount(sender, receiver);
  30 | *   |         uint128 splittableBefore = drips.splittable(receiverDripsAccId, token);
  31 |     | 
  32 | *   |         uint128 squeezedAmt = squeezeWithDefaultHistory(
  33 | *   |             receiverAccId,
  34 | *   |             senderAccId
  35 |     |         );
  36 |     | 
  37 | *   |         uint128 squeezableAfter = getSqueezableAmount(sender, receiver);
  38 | *   |         uint128 splittableAfter = drips.splittable(receiverDripsAccId, token);
  39 |     | 
  40 | *   |         assert(squeezableAfter == squeezableBefore - squeezedAmt);
  41 | *   |         assert(splittableAfter == splittableBefore + squeezedAmt);
  42 |     | 
  43 | *   |         if (squeezedAmt > 0) {
  44 | *   |             assert(squeezableAfter < squeezableBefore);
  45 | *   |             assert(splittableAfter > splittableBefore);
  46 |     |         } else {
  47 | *   |             assert(squeezableAfter == squeezableBefore);
  48 | *   |             assert(splittableAfter == splittableBefore);
  49 |     |         }
  50 |     |     }
  51 |     | 
  52 |     |     /**
  53 |     |      * @notice `drips.squeezeStreamsResult` should match actual squeezed amount
  54 |     |      * @param receiverAccId Account id of the receiver
  55 |     |      * @param senderAccId Account id of the sender
  56 |     |      */
  57 | *   |     function testSqueezeViewVsActual(uint8 receiverAccId, uint8 senderAccId)
  58 |     |         public
  59 | *   |     {
  60 | *   |         address receiver = getAccount(receiverAccId);
  61 | *   |         address sender = getAccount(senderAccId);
  62 |     | 
  63 | *   |         uint128 squeezable = getSqueezableAmount(sender, receiver);
  64 | *   |         uint128 squeezed = squeezeWithDefaultHistory(
  65 | *   |             receiverAccId,
  66 | *   |             senderAccId
  67 |     |         );
  68 |     | 
  69 | *   |         assert(squeezable == squeezed);
  70 |     |     }
  71 |     | 
  72 |     |     /**
  73 |     |      * @notice Squeezable amount should be equal to receivable amount in the future
  74 |     |      * @param targetAccId Account id of the receiver
  75 |     |      */
  76 | *   |     function testSqueezableVsReceived(uint8 targetAccId) public heavy {
  77 | *   |         address target = getAccount(targetAccId);
  78 |     | 
  79 |     |         // store the current squeezable and receivable amount
  80 | *   |         uint128 squeezable = getTotalSqueezableAmountForUser(target);
  81 | *   |         uint128 receivableBefore = getReceivableAmountForUser(target);
  82 |     | 
  83 |     |         // remove all streaming balance from the system, so that warping to
  84 |     |         // the future will not increase the receivable/squeezable amount
  85 | *   |         setStreamBalanceWithdrawAll(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER0]);
  86 | *   |         setStreamBalanceWithdrawAll(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER1]);
  87 | *   |         setStreamBalanceWithdrawAll(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER2]);
  88 | *   |         setStreamBalanceWithdrawAll(ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER3]);
  89 |     | 
  90 |     |         // warp to the point in time where the streams are receivable
  91 | *   |         hevm.warp(getCurrentCycleEnd() + 1);
  92 |     | 
  93 | *   |         uint128 receivableAfter = getReceivableAmountForUser(target);
  94 |     | 
  95 |     |         // sanity check
  96 | *   |         assert(receivableAfter >= receivableBefore);
  97 |     | 
  98 | *   |         uint128 receiveableDelta = receivableAfter - receivableBefore;
  99 |     | 
 100 |     |         // squeezable before should match receivable now
 101 | *   |         assert(squeezable == receiveableDelta);
 102 |     |     }
 103 |     | 
 104 |     |     /**
 105 |     |      * @notice Squeezing with a fully hashed history should do nothing
 106 |     |      * @param receiverAccId Account id of the receiver
 107 |     |      * @param senderAccId Account id of the sender
 108 |     |      */
 109 | *   |     function testSqueezeWithFullyHashedHistory(
 110 |     |         uint8 receiverAccId,
 111 |     |         uint8 senderAccId
 112 | *   |     ) public {
 113 | *   |         address receiver = getAccount(receiverAccId);
 114 | *   |         address sender = getAccount(senderAccId);
 115 |     | 
 116 | *   |         uint128 squeezableBefore = getSqueezableAmount(sender, receiver);
 117 |     | 
 118 | *   |         StreamsHistory[] memory history = getStreamsHistory(sender);
 119 | *   |         for (uint256 i = 0; i < history.length; i++) {
 120 | *   |             history[i].streamsHash = drips.hashStreams(history[i].receivers);
 121 | *   |             history[i].receivers = new StreamReceiver[](0);
 122 |     |         }
 123 |     | 
 124 | *   |         uint128 squeezedAmt = _squeeze(
 125 | *   |             receiverAccId,
 126 | *   |             senderAccId,
 127 | *   |             bytes32(0),
 128 | *   |             history
 129 |     |         );
 130 |     | 
 131 | *   |         uint128 squeezableAfter = getSqueezableAmount(sender, receiver);
 132 |     | 
 133 | *   |         assert(squeezedAmt == 0);
 134 | *   |         assert(squeezableAfter == squeezableBefore);
 135 |     |     }
 136 |     | 
 137 |     |     /**
 138 |     |      * @notice Squeezing the same part(s) of history should only work the first time
 139 |     |      * @param receiverAccId Account id of the receiver
 140 |     |      * @param senderAccId Account id of the sender
 141 |     |      * @param hashIndex Index of the history entry to squeeze
 142 |     |      * @param receiversRandomSeed Random seed used to determine which history entries
 143 |     |      * to leave out of the squeeze (by hashing them)
 144 |     |      */
 145 | *   |     function testSqueezeTwice(
 146 |     |         uint8 receiverAccId,
 147 |     |         uint8 senderAccId,
 148 |     |         uint256 hashIndex,
 149 |     |         bytes32 receiversRandomSeed
 150 | *   |     ) external {
 151 | *   |         address receiver = getAccount(receiverAccId);
 152 | *   |         address sender = getAccount(senderAccId);
 153 |     | 
 154 | *   |         uint128 amount0 = squeezeWithFuzzedHistory(
 155 | *   |             receiverAccId,
 156 | *   |             senderAccId,
 157 | *   |             hashIndex,
 158 | *   |             receiversRandomSeed
 159 |     |         );
 160 |     | 
 161 | *   |         uint128 amount1 = squeezeWithFuzzedHistory(
 162 | *   |             receiverAccId,
 163 | *   |             senderAccId,
 164 | *   |             hashIndex,
 165 | *   |             receiversRandomSeed
 166 |     |         );
 167 |     | 
 168 | *   |         assert(amount1 == 0);
 169 |     |     }
 170 |     | 
 171 |     |     /**
 172 |     |      * @notice Already streamed (and therefore squeezable) balance should not be
 173 |     |      * affected changing the stream receivers
 174 |     |      * @param receiverAccId Account id of the receiver
 175 |     |      * @param senderAccId Account id of the sender
 176 |     |      * @param amountPerSec Amount per second to stream
 177 |     |      * @param startTime Start time for the stream
 178 |     |      * @param duration Duration for the stream
 179 |     |      * @param balanceDelta Amount to update stream balance with
 180 |     |      */
 181 | *   |     function testSqueezableAmountCantBeUndone(
 182 |     |         uint8 receiverAccId,
 183 |     |         uint8 senderAccId,
 184 |     |         uint160 amountPerSec,
 185 |     |         uint32 startTime,
 186 |     |         uint32 duration,
 187 |     |         int128 balanceDelta
 188 | *   |     ) external {
 189 | *   |         address receiver = getAccount(receiverAccId);
 190 | *   |         address sender = getAccount(senderAccId);
 191 |     | 
 192 | *   |         uint128 squeezableBefore = getSqueezableAmount(sender, receiver);
 193 |     | 
 194 | *   |         setStreams(
 195 | *   |             receiverAccId,
 196 | *   |             senderAccId,
 197 | *   |             amountPerSec,
 198 | *   |             startTime,
 199 | *   |             duration,
 200 | *   |             balanceDelta
 201 |     |         );
 202 |     | 
 203 | *   |         uint128 squeezableAfter = getSqueezableAmount(sender, receiver);
 204 |     | 
 205 | *   |         assert(squeezableAfter == squeezableBefore);
 206 |     |     }
 207 |     | 
 208 |     |     /**
 209 |     |      * @notice Already streamed (and therefore squeezable) balance should not be
 210 |     |      * affected by withdrawing all streaming balance
 211 |     |      * @param receiverAccId Account id of the receiver
 212 |     |      * @param senderAccId Account id of the sender
 213 |     |      */
 214 | *   |     function testSqueezableAmountCantBeWithdrawn(
 215 |     |         uint8 receiverAccId,
 216 |     |         uint8 senderAccId
 217 | *   |     ) external {
 218 | *   |         address receiver = getAccount(receiverAccId);
 219 | *   |         address sender = getAccount(senderAccId);
 220 |     | 
 221 | *   |         uint128 squeezableBefore = getSqueezableAmount(sender, receiver);
 222 |     | 
 223 | *   |         setStreamBalanceWithdrawAll(senderAccId);
 224 |     | 
 225 | *   |         uint128 squeezableAfter = getSqueezableAmount(sender, receiver);
 226 |     | 
 227 | *   |         assert(squeezableAfter == squeezableBefore);
 228 |     |     }
 229 |     | 
 230 |     |     /**
 231 |     |      * @notice Squeezing with default history (all history entries) should
 232 |     |      * not revert
 233 |     |      * @param receiverAccId Account id of the receiver
 234 |     |      * @param senderAccId Account id of the sender
 235 |     |      */
 236 | *   |     function testSqueezeWithDefaultHistoryShouldNotRevert(
 237 |     |         uint8 receiverAccId,
 238 |     |         uint8 senderAccId
 239 |     |     ) public {
 240 | *   |         try
 241 | *   |             EchidnaSqueezeHelpers(address(this)).squeezeWithDefaultHistory(
 242 | *   |                 receiverAccId,
 243 | *   |                 senderAccId
 244 |     |             )
 245 |     |         {} catch {
 246 |     |             assert(false);
 247 |     |         }
 248 |     |     }
 249 |     | 
 250 |     |     /**
 251 |     |      * @notice Squeezing with fuzzed history should not revert
 252 |     |      * @param receiverAccId Account id of the receiver
 253 |     |      * @param senderAccId Account id of the sender
 254 |     |      * @param hashIndex Index of the history entry to squeeze
 255 |     |      * @param receiversRandomSeed Random seed used to determine which history entries
 256 |     |      * to leave out of the squeeze (by hashing them)
 257 |     |      */
 258 | *   |     function testSqueezeWithFuzzedHistoryShouldNotRevert(
 259 |     |         uint8 receiverAccId,
 260 |     |         uint8 senderAccId,
 261 |     |         uint256 hashIndex,
 262 |     |         bytes32 receiversRandomSeed
 263 | *   |     ) public {
 264 | *   |         address sender = getAccount(senderAccId);
 265 | *r  |         require(
 266 | *   |             getStreamsHistory(sender).length >= 2,
 267 |     |             "need at least 2 history entries"
 268 |     |         );
 269 |     | 
 270 | *   |         try
 271 | *   |             EchidnaSqueezeHelpers(address(this)).squeezeWithFuzzedHistory(
 272 | *   |                 receiverAccId,
 273 | *   |                 senderAccId,
 274 | *   |                 hashIndex,
 275 | *   |                 receiversRandomSeed
 276 |     |             )
 277 |     |         {} catch {
 278 |     |             assert(false);
 279 |     |         }
 280 |     |     }
 281 |     | 
 282 |     | }
 283 |     | 

/opt/scfuzzbench/work/target/src/echidna/EchidnaStreamsHelpers.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | 
   3 |     | import "./base/EchidnaBase.sol";
   4 |     | 
   5 |     | /**
   6 |     |  * @title Mixin containing helpers for streams
   7 |     |  * @author Rappie <rappie@perimetersec.io>
   8 |     |  */
   9 |     | contract EchidnaStreamsHelpers is EchidnaBase {
  10 |     |     // Internal variables to store maxEndHint1 and maxEndHint2. These are used
  11 |     |     // as hints to the Drips contract to speed up the setStreams call.
  12 |     |     //
  13 |     |     // Instead of fuzzing these directly, we use the `setMaxEndHints` helper
  14 |     |     // function to set these values. This makes fuzzing these toggleable and
  15 |     |     // also makes debugging easier because the values don't have to be passed
  16 |     |     // as arguments to all functions calling `setStreams`.
  17 |     |     //
  18 |     |     uint32 internal maxEndHint1;
  19 |     |     uint32 internal maxEndHint2;
  20 |     | 
  21 |     |     /**
  22 |     |      * @notice Internal helper function to set streams receivers
  23 |     |      * @param from Account to set streams for
  24 |     |      * @param currReceivers Current stream receivers (Drips needs this)
  25 |     |      * @param balanceDelta Balance delta to set
  26 |     |      * @param unsortedNewReceivers New receivers list to set
  27 |     |      * @return Real balance delta
  28 |     |      * @dev This function also sorts the receivers list
  29 |     |      */
  30 | *   |     function _setStreams(
  31 |     |         address from,
  32 |     |         StreamReceiver[] memory currReceivers,
  33 |     |         int128 balanceDelta,
  34 |     |         StreamReceiver[] memory unsortedNewReceivers
  35 | *   |     ) internal returns (int128) {
  36 | *   |         StreamReceiver[] memory newReceivers = bubbleSortStreamReceivers(
  37 | *   |             unsortedNewReceivers
  38 |     |         );
  39 |     | 
  40 | *   |         hevm.prank(from);
  41 | *r  |         int128 realBalanceDelta = driver.setStreams(
  42 | *   |             token,
  43 | *   |             currReceivers,
  44 | *   |             balanceDelta,
  45 | *   |             newReceivers,
  46 | *   |             maxEndHint1,
  47 | *   |             maxEndHint2,
  48 | *   |             from
  49 |     |         );
  50 |     | 
  51 | *   |         updateStreamReceivers(from, newReceivers);
  52 |     | 
  53 | *   |         return realBalanceDelta;
  54 |     |     }
  55 |     | 
  56 |     |     /**
  57 |     |      * @notice Set streams, overwriting the current receivers list
  58 |     |      * @param fromAccId Account id of the sender
  59 |     |      * @param toAccId Account id of the receiver in the receivers list
  60 |     |      * @param amountPerSec Amount per second to stream
  61 |     |      * @param startTime Start time of the stream
  62 |     |      * @param duration Duration of the stream
  63 |     |      * @param balanceDelta Balance delta to set
  64 |     |      * @return Real balance delta
  65 |     |      */
  66 | *   |     function setStreams(
  67 |     |         uint8 fromAccId,
  68 |     |         uint8 toAccId,
  69 |     |         uint160 amountPerSec,
  70 |     |         uint32 startTime,
  71 |     |         uint32 duration,
  72 |     |         int128 balanceDelta
  73 | *   |     ) public returns (int128) {
  74 | *   |         address from = getAccount(fromAccId);
  75 | *   |         address to = getAccount(toAccId);
  76 |     | 
  77 | *   |         StreamReceiver[] memory receivers = new StreamReceiver[](1);
  78 | *   |         receivers[0] = StreamReceiver(
  79 | *   |             getDripsAccountId(to),
  80 | *   |             StreamConfigImpl.create(
  81 | *   |                 0, // streamId is arbitrary and can be ignored
  82 | *   |                 amountPerSec,
  83 | *   |                 startTime,
  84 | *   |                 duration
  85 |     |             )
  86 |     |         );
  87 |     | 
  88 | *   |         int128 realBalanceDelta = _setStreams(
  89 | *   |             from,
  90 | *   |             getStreamReceivers(from),
  91 | *   |             balanceDelta,
  92 | *   |             receivers
  93 |     |         );
  94 |     | 
  95 | *   |         return realBalanceDelta;
  96 |     |     }
  97 |     | 
  98 |     |     /**
  99 |     |      * @notice Set streams, overwriting the current receivers list
 100 |     |      * @param fromAccId Account id of the sender
 101 |     |      * @param toAccId Account id of the receiver in the receivers list
 102 |     |      * @param amountPerSec Amount per second to stream
 103 |     |      * @param startTime Start time of the stream
 104 |     |      * @param duration Duration of the stream
 105 |     |      * @param balanceDelta Balance delta to set
 106 |     |      * @return Real balance delta
 107 |     |      * @dev This function clamps the amountPerSec, startTime, duration and
 108 |     |      * balanceDelta between the minimum and maximum allowed values
 109 |     |      */
 110 | *   |     function setStreamsWithClamping(
 111 |     |         uint8 fromAccId,
 112 |     |         uint8 toAccId,
 113 |     |         uint160 amountPerSec,
 114 |     |         uint32 startTime,
 115 |     |         uint32 duration,
 116 |     |         int128 balanceDelta
 117 | *   |     ) public returns (int128) {
 118 | *   |         address from = getAccount(fromAccId);
 119 | *   |         address to = getAccount(toAccId);
 120 |     | 
 121 | *   |         amountPerSec = clampAmountPerSec(amountPerSec);
 122 | *   |         startTime = clampStartTime(startTime);
 123 | *   |         duration = clampDuration(duration);
 124 | *   |         balanceDelta = clampBalanceDelta(balanceDelta, from);
 125 |     | 
 126 | *   |         setStreams(
 127 | *   |             fromAccId,
 128 | *   |             toAccId,
 129 | *   |             amountPerSec,
 130 | *   |             startTime,
 131 | *   |             duration,
 132 | *   |             balanceDelta
 133 |     |         );
 134 |     |     }
 135 |     | 
 136 |     |     /**
 137 |     |      * @notice Add a stream receiver to the existing list of receivers
 138 |     |      * @param fromAccId Account id of the sender
 139 |     |      * @param toAccId Account id of the receiver to add
 140 |     |      * @param amountPerSec Amount per second to stream
 141 |     |      * @param startTime Start time of the stream
 142 |     |      * @param duration Duration of the stream
 143 |     |      * @param balanceDelta Balance delta to set
 144 |     |      * @return Real balance delta
 145 |     |      */
 146 | *   |     function addStream(
 147 |     |         uint8 fromAccId,
 148 |     |         uint8 toAccId,
 149 |     |         uint160 amountPerSec,
 150 |     |         uint32 startTime,
 151 |     |         uint32 duration,
 152 |     |         int128 balanceDelta
 153 | *   |     ) public returns (int128) {
 154 | *   |         address from = getAccount(fromAccId);
 155 | *   |         address to = getAccount(toAccId);
 156 |     | 
 157 | *   |         StreamReceiver[] memory oldReceivers = getStreamReceivers(from);
 158 |     | 
 159 | *   |         StreamReceiver memory addedReceiver = StreamReceiver(
 160 | *   |             getDripsAccountId(to),
 161 | *   |             StreamConfigImpl.create(
 162 | *   |                 0, // streamId is arbitrary and can be ignored
 163 | *   |                 amountPerSec,
 164 | *   |                 startTime,
 165 | *   |                 duration
 166 |     |             )
 167 |     |         );
 168 |     | 
 169 | *   |         StreamReceiver[] memory newReceivers = new StreamReceiver[](
 170 | *   |             oldReceivers.length + 1
 171 |     |         );
 172 | *   |         for (uint256 i = 0; i < oldReceivers.length; i++) {
 173 | *   |             newReceivers[i] = oldReceivers[i];
 174 |     |         }
 175 | *   |         newReceivers[newReceivers.length - 1] = addedReceiver;
 176 |     | 
 177 | *   |         int128 realBalanceDelta = _setStreams(
 178 | *   |             from,
 179 | *   |             oldReceivers,
 180 | *   |             balanceDelta,
 181 | *   |             newReceivers
 182 |     |         );
 183 |     | 
 184 | *   |         return realBalanceDelta;
 185 |     |     }
 186 |     | 
 187 |     |     /**
 188 |     |      * @notice Add a stream receiver to the existing list of receivers
 189 |     |      * @param fromAccId Account id of the sender
 190 |     |      * @param toAccId Account id of the receiver to add
 191 |     |      * @param amountPerSec Amount per second to stream
 192 |     |      * @param startTime Start time of the stream
 193 |     |      * @param duration Duration of the stream
 194 |     |      * @param balanceDelta Balance delta to set
 195 |     |      * @dev This function clamps the amountPerSec, startTime, duration and
 196 |     |      * balanceDelta between the minimum and maximum allowed values
 197 |     |      */
 198 | *   |     function addStreamWithClamping(
 199 |     |         uint8 fromAccId,
 200 |     |         uint8 toAccId,
 201 |     |         uint160 amountPerSec,
 202 |     |         uint32 startTime,
 203 |     |         uint32 duration,
 204 |     |         int128 balanceDelta
 205 | *   |     ) public returns (int128) {
 206 | *   |         address from = getAccount(fromAccId);
 207 |     | 
 208 | *   |         amountPerSec = clampAmountPerSec(amountPerSec);
 209 | *   |         startTime = clampStartTime(startTime);
 210 | *   |         duration = clampDuration(duration);
 211 | *   |         balanceDelta = clampBalanceDelta(balanceDelta, from);
 212 |     | 
 213 | *   |         return
 214 | *   |             addStream(
 215 | *   |                 fromAccId,
 216 | *   |                 toAccId,
 217 | *   |                 amountPerSec,
 218 | *   |                 startTime,
 219 | *   |                 duration,
 220 | *   |                 balanceDelta
 221 |     |             );
 222 |     |     }
 223 |     | 
 224 |     |     /**
 225 |     |      * @notice Add a stream receiver to the existing list of receivers, making sure
 226 |     |      * it is immediately squeezable in a transaction after this call
 227 |     |      * @param fromAccId Account id of the sender
 228 |     |      * @param toAccId Account id of the receiver to add
 229 |     |      * @param amountPerSec Amount per second to stream
 230 |     |      * @dev This is meant as a helper to quickly seed the corpus with situations
 231 |     |      * where there is something to squeeze in the next transaction
 232 |     |      */
 233 | *   |     function addStreamImmediatelySqueezable(
 234 |     |         uint8 fromAccId,
 235 |     |         uint8 toAccId,
 236 |     |         uint160 amountPerSec
 237 | *   |     ) public {
 238 | *   |         address receiver = getAccount(toAccId);
 239 | *   |         address sender = getAccount(fromAccId);
 240 |     | 
 241 |     |         // calculate amount per second so there will be something to squeeze
 242 |     |         // this cycle
 243 | *   |         uint160 minAmtPerSec = drips.minAmtPerSec() * SECONDS_PER_CYCLE;
 244 | *   |         amountPerSec =
 245 | *   |             minAmtPerSec +
 246 | *   |             (amountPerSec % (MAX_AMOUNT_PER_SEC - minAmtPerSec + 1));
 247 |     | 
 248 |     |         // deposit 100 times the amount of 'amountPerSec' so chances are high
 249 |     |         // that there is enough balance to stream this cycle
 250 | *   |         int128 balanceDelta = (int128(uint128(amountPerSec)) * 100) / 1e9;
 251 | *   |         if (uint128(balanceDelta) > token.balanceOf(sender)) {
 252 | *   |             balanceDelta = int128(uint128(token.balanceOf(sender)));
 253 |     |         }
 254 |     | 
 255 |     |         // add the stream
 256 | *   |         addStream(fromAccId, toAccId, amountPerSec, 0, 0, balanceDelta);
 257 |     | 
 258 |     |         // warp 1 second forward so there is something to squeeze
 259 | *   |         hevm.warp(block.timestamp + 1);
 260 |     |     }
 261 |     | 
 262 |     |     /**
 263 |     |      * @notice Remove a stream receiver from the existing list of receivers
 264 |     |      * @param targetAccId Account id of the receiver to remove
 265 |     |      * @param indexSeed Random seed used to determine which receiver to remove
 266 |     |      */
 267 | *   |     function removeStream(uint8 targetAccId, uint256 indexSeed) public {
 268 | *   |         address target = getAccount(targetAccId);
 269 |     | 
 270 | *   |         StreamReceiver[] memory oldReceivers = getStreamReceivers(target);
 271 |     | 
 272 | *   |         uint256 index = indexSeed % oldReceivers.length;
 273 |     | 
 274 | *   |         StreamReceiver[] memory newReceivers = new StreamReceiver[](
 275 | *   |             oldReceivers.length - 1
 276 |     |         );
 277 | *   |         uint256 j = 0;
 278 | *   |         for (uint256 i = 0; i < oldReceivers.length; i++) {
 279 | *   |             if (i != index) {
 280 | *   |                 newReceivers[j] = oldReceivers[i];
 281 | *   |                 j++;
 282 |     |             }
 283 |     |         }
 284 |     | 
 285 | *   |         _setStreams(target, oldReceivers, 0, newReceivers);
 286 |     |     }
 287 |     | 
 288 |     |     /**
 289 |     |      * @notice Update stream balance by calling `setStreams` with the same
 290 |     |      * receivers list
 291 |     |      * @param targetAccId Account id of the sender
 292 |     |      * @param balanceDelta Balance delta to set
 293 |     |      * @return Real balance delta
 294 |     |      */
 295 | *   |     function setStreamBalance(uint8 targetAccId, int128 balanceDelta)
 296 |     |         public
 297 | *   |         returns (int128)
 298 |     |     {
 299 | *   |         address target = getAccount(targetAccId);
 300 |     | 
 301 | *   |         int128 realBalanceDelta = _setStreams(
 302 | *   |             target,
 303 | *   |             getStreamReceivers(target),
 304 | *   |             balanceDelta,
 305 | *   |             getStreamReceivers(target)
 306 |     |         );
 307 |     | 
 308 | *   |         return realBalanceDelta;
 309 |     |     }
 310 |     | 
 311 |     |     /**
 312 |     |      * @notice Update stream balance by calling `setStreams` with the same
 313 |     |      * receivers list
 314 |     |      * @param targetAccId Account id of the sender
 315 |     |      * @param balanceDelta Balance delta to set
 316 |     |      * @dev This function clamps the balanceDelta between the minimum and
 317 |     |      * maximum allowed values
 318 |     |      */
 319 | *   |     function setStreamBalanceWithClamping(
 320 |     |         uint8 targetAccId,
 321 |     |         int128 balanceDelta
 322 | *   |     ) public {
 323 | *   |         address target = getAccount(targetAccId);
 324 | *   |         balanceDelta = clampBalanceDelta(balanceDelta, target);
 325 | *   |         setStreamBalance(targetAccId, balanceDelta);
 326 |     |     }
 327 |     | 
 328 |     |     /**
 329 |     |      * @notice Withdraw all stream balance by calling `setStreams` with the same
 330 |     |      * receivers list and using min int128 as balance delta
 331 |     |      * @param targetAccId Account id of the sender
 332 |     |      * @return Real balance delta
 333 |     |      */
 334 | *   |     function setStreamBalanceWithdrawAll(uint8 targetAccId)
 335 |     |         public
 336 | *   |         returns (int128)
 337 | *   |     {
 338 | *   |         address target = getAccount(targetAccId);
 339 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
 340 |     | 
 341 | *   |         int128 realBalanceDelta = _setStreams(
 342 | *   |             target,
 343 | *   |             getStreamReceivers(target),
 344 | *   |             type(int128).min,
 345 | *   |             getStreamReceivers(target)
 346 |     |         );
 347 |     |     }
 348 |     | 
 349 |     |     /**
 350 |     |      * @notice Helper function to update the values used as maxEnd hints
 351 |     |      * @param _maxEndHint1 New value for maxEndHint1
 352 |     |      * @param _maxEndHint2 New value for maxEndHint2
 353 |     |      * @dev Can be toggled on/off with TOGGLE_MAXENDHINTS_ENABLED
 354 |     |      */
 355 | *   |     function setMaxEndHints(uint32 _maxEndHint1, uint32 _maxEndHint2) public {
 356 | *   |         require(TOGGLE_MAXENDHINTS_ENABLED);
 357 | *   |         maxEndHint1 = _maxEndHint1;
 358 | *   |         maxEndHint2 = _maxEndHint2;
 359 |     |     }
 360 |     | 
 361 |     |     /**
 362 |     |      * @notice Clamp the amountPerSec between the minimum and maximum allowed values
 363 |     |      * @param amountPerSec Amount per second to clamp
 364 |     |      * @return Clamped amountPerSec
 365 |     |      */
 366 | *   |     function clampAmountPerSec(uint160 amountPerSec)
 367 |     |         internal
 368 | *   |         returns (uint160)
 369 |     |     {
 370 | *   |         return
 371 | *   |             drips.minAmtPerSec() +
 372 | *   |             (amountPerSec % (MAX_AMOUNT_PER_SEC - drips.minAmtPerSec() + 1));
 373 |     |     }
 374 |     | 
 375 |     |     /**
 376 |     |      * @notice Clamp the startTime between the minimum and maximum allowed values
 377 |     |      * @param startTime Start time to clamp
 378 |     |      * @return Clamped startTime
 379 |     |      */
 380 | *   |     function clampStartTime(uint32 startTime) internal returns (uint32) {
 381 | *   |         if (startTime == 0) return 0;
 382 |     | 
 383 |     |         // We want to make sure that the start time does not go below 1
 384 | *   |         uint32 minStartTime;
 385 | *   |         if (CYCLE_FUZZING_BUFFER_SECONDS >= block.timestamp) {
 386 |     |             minStartTime = 1;
 387 |     |         } else {
 388 | *   |             minStartTime =
 389 | *   |                 uint32(block.timestamp) -
 390 |     |                 CYCLE_FUZZING_BUFFER_SECONDS;
 391 |     |         }
 392 |     | 
 393 | *   |         uint32 maxStartTime = uint32(block.timestamp) +
 394 |     |             CYCLE_FUZZING_BUFFER_SECONDS;
 395 |     | 
 396 | *   |         return minStartTime + (startTime % (maxStartTime - minStartTime + 1));
 397 |     |     }
 398 |     | 
 399 |     |     /**
 400 |     |      * @notice Clamp the duration between the minimum and maximum allowed values
 401 |     |      * @param duration Duration to clamp
 402 |     |      * @return Clamped duration
 403 |     |      */
 404 | *   |     function clampDuration(uint32 duration) internal returns (uint32) {
 405 | *   |         if (duration == 0) return 0;
 406 |     | 
 407 | *   |         return duration % (MAX_STREAM_DURATION + 1);
 408 |     |     }
 409 |     | 
 410 |     |     /**
 411 |     |      * @notice Clamp the balanceDelta between the minimum and maximum allowed values
 412 |     |      * @param balanceDelta Balance delta to clamp
 413 |     |      * @param from Account performing the setStreams action
 414 |     |      * @return Clamped balanceDelta
 415 |     |      */
 416 | *   |     function clampBalanceDelta(int128 balanceDelta, address from)
 417 |     |         internal
 418 | *   |         returns (int128)
 419 |     |     {
 420 | *   |         if (balanceDelta > 0) {
 421 | *   |             balanceDelta =
 422 | *   |                 balanceDelta %
 423 | *   |                 (int128(uint128(token.balanceOf(from))) + 1);
 424 |     |         } else {
 425 | *   |             balanceDelta = balanceDelta % int128(uint128(STARTING_BALANCE));
 426 |     |         }
 427 | *   |         return balanceDelta;
 428 |     |     }
 429 |     | }
 430 |     | 

/opt/scfuzzbench/work/target/src/echidna/EchidnaStreamsTests.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | 
   3 |     | import "./base/EchidnaBase.sol";
   4 |     | import "./EchidnaStreamsHelpers.sol";
   5 |     | 
   6 |     | /**
   7 |     |  * @title Mixin containing tests for streams
   8 |     |  * @author Rappie <rappie@perimetersec.io>
   9 |     |  */
  10 |     | contract EchidnaStreamsTests is EchidnaBase, EchidnaStreamsHelpers {
  11 |     |     /**
  12 |     |      * @notice Test internal accounting after updating stream balance
  13 |     |      * @param targetAccId Account id of the sender
  14 |     |      * @param balanceDelta Amount to update stream balance with
  15 |     |      */
  16 | *   |     function testSetStreamBalance(uint8 targetAccId, int128 balanceDelta)
  17 |     |         public
  18 | *   |     {
  19 | *   |         address target = getAccount(targetAccId);
  20 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  21 |     | 
  22 | *   |         uint256 tokenBalanceBefore = token.balanceOf(target);
  23 | *   |         uint128 streamBalanceBefore = drips.balanceAt(
  24 | *   |             targetDripsAccId,
  25 | *   |             token,
  26 | *   |             getStreamReceivers(target),
  27 | *   |             uint32(block.timestamp)
  28 |     |         );
  29 |     | 
  30 | *   |         int128 realBalanceDelta = setStreamBalance(targetAccId, balanceDelta);
  31 |     | 
  32 | *   |         uint256 tokenBalanceAfter = token.balanceOf(target);
  33 | *   |         uint128 streamBalanceAfter = drips.balanceAt(
  34 | *   |             targetDripsAccId,
  35 | *   |             token,
  36 | *   |             getStreamReceivers(target),
  37 | *   |             uint32(block.timestamp)
  38 |     |         );
  39 |     | 
  40 | *   |         if (balanceDelta >= 0) {
  41 | *   |             assert(realBalanceDelta == balanceDelta);
  42 |     |         } else {
  43 | *   |             assert(realBalanceDelta <= 0);
  44 | *   |             assert(realBalanceDelta >= balanceDelta);
  45 |     |         }
  46 |     | 
  47 | *   |         assert(
  48 | *   |             int256(tokenBalanceAfter) ==
  49 | *   |                 int256(tokenBalanceBefore) - realBalanceDelta
  50 |     |         );
  51 | *   |         assert(
  52 | *   |             int128(streamBalanceAfter) ==
  53 | *   |                 int128(streamBalanceBefore) + realBalanceDelta
  54 |     |         );
  55 |     |     }
  56 |     | 
  57 |     |     /**
  58 |     |      * @notice Check balances before and after adding a stream, warping to the
  59 |     |      * future, and receiving the stream.
  60 |     |      * @param fromAccId Account id of the sender
  61 |     |      * @param toAccId Account id to be added as receiver
  62 |     |      * @param amtPerSecAdded Amount per second for the stream to be added
  63 |     |      * @dev This test is resource heavy because it contains lots of logic and
  64 |     |      * warping to the future.
  65 |     |      */
  66 | *   |     function testBalanceAtInFuture(
  67 |     |         uint8 fromAccId,
  68 |     |         uint8 toAccId,
  69 |     |         uint160 amtPerSecAdded
  70 | *   |     ) public heavy {
  71 | *   |         address from = getAccount(fromAccId);
  72 | *   |         address to = getAccount(toAccId);
  73 | *   |         uint256 fromDripsAccId = getDripsAccountId(from);
  74 | *   |         uint256 toDripsAccId = getDripsAccountId(to);
  75 |     | 
  76 | *   |         amtPerSecAdded = clampAmountPerSec(amtPerSecAdded);
  77 |     | 
  78 |     |         // the timestamps we are comparing
  79 | *   |         uint256 currentTimestamp = block.timestamp;
  80 | *   |         uint256 futureTimestamp = getCurrentCycleEnd() + 1;
  81 |     | 
  82 |     |         // retrieve initial balances
  83 | *   |         uint128 balanceInitial = getStreamBalanceForUser(
  84 | *   |             from,
  85 | *   |             uint32(block.timestamp)
  86 |     |         );
  87 | *   |         uint128 receivableInitial = getReceivableAmountForAllUsers();
  88 |     | 
  89 |     |         // look at balances in the future if we wouldnt do anything
  90 | *   |         hevm.warp(futureTimestamp);
  91 | *   |         uint128 balanceBaseline = getStreamBalanceForUser(
  92 | *   |             from,
  93 | *   |             uint32(block.timestamp)
  94 |     |         );
  95 | *   |         uint128 receivableBaseline = getReceivableAmountForAllUsers();
  96 | *   |         hevm.warp(currentTimestamp);
  97 |     | 
  98 |     |         // add a stream
  99 |     |         // make sure we add enough balance to complete the cycle
 100 | *   |         uint128 balanceAdded = uint128(amtPerSecAdded) * SECONDS_PER_CYCLE;
 101 | *   |         balanceAdded = uint128(clampBalanceDelta(int128(balanceAdded), from));
 102 | *r  |         require(balanceAdded / amtPerSecAdded >= SECONDS_PER_CYCLE);
 103 | *   |         addStream(
 104 | *   |             fromAccId,
 105 | *   |             toAccId,
 106 | *   |             amtPerSecAdded,
 107 | *   |             0,
 108 | *   |             0,
 109 | *   |             int128(balanceAdded)
 110 |     |         );
 111 |     | 
 112 |     |         // retrieve balances after adding stream
 113 | *   |         uint128 balanceBefore = getStreamBalanceForUser(
 114 | *   |             from,
 115 | *   |             uint32(block.timestamp)
 116 |     |         );
 117 | *   |         uint128 receivableBefore = getReceivableAmountForAllUsers();
 118 |     | 
 119 |     |         // jump to future
 120 | *   |         hevm.warp(futureTimestamp);
 121 |     | 
 122 |     |         // retrieve balances in the future after adding the stream
 123 | *   |         uint128 balanceAfter = getStreamBalanceForUser(
 124 | *   |             from,
 125 | *   |             uint32(block.timestamp)
 126 |     |         );
 127 | *   |         uint128 receivableAfter = getReceivableAmountForAllUsers();
 128 |     | 
 129 |     |         // sanity checks
 130 | *   |         assert(balanceInitial >= balanceBaseline);
 131 | *   |         assert(balanceBefore >= balanceAfter);
 132 | *   |         assert(receivableAfter >= receivableBaseline);
 133 |     | 
 134 |     |         // the amount that would have been streamed if we do nothing
 135 | *   |         uint128 baselineBalanceStreamed = balanceInitial - balanceBaseline;
 136 |     | 
 137 |     |         // calculate expected balance change including the effect of the
 138 |     |         // added stream
 139 | *   |         uint128 expectedBalanceChange = balanceBefore -
 140 | *   |             balanceAfter -
 141 | *   |             baselineBalanceStreamed;
 142 | *   |         uint128 expectedReceivedChange = receivableAfter - receivableBaseline;
 143 |     | 
 144 | *   |         assert(expectedBalanceChange == expectedReceivedChange);
 145 |     |     }
 146 |     | 
 147 |     |     /**
 148 |     |      * @notice Setting streams with sane defaults should not revert
 149 |     |      * @param fromAccId Account id of the sender
 150 |     |      * @param toAccId Account id of the receiver
 151 |     |      * @param amountPerSec Amount per second for the stream
 152 |     |      * @param startTime Start time for the stream
 153 |     |      * @param duration Duration for the stream
 154 |     |      * @param balanceDelta Amount to update stream balance with
 155 |     |      */
 156 | *   |     function testSetStreamsShouldNotRevert(
 157 |     |         uint8 fromAccId,
 158 |     |         uint8 toAccId,
 159 |     |         uint160 amountPerSec,
 160 |     |         uint32 startTime,
 161 |     |         uint32 duration,
 162 |     |         int128 balanceDelta
 163 |     |     ) public {
 164 | *   |         try
 165 | *   |             EchidnaStreamsHelpers(address(this)).setStreamsWithClamping(
 166 | *   |                 fromAccId,
 167 | *   |                 toAccId,
 168 | *   |                 amountPerSec,
 169 | *   |                 startTime,
 170 | *   |                 duration,
 171 | *   |                 balanceDelta
 172 |     |             )
 173 |     |         {} catch {
 174 |     |             assert(false);
 175 |     |         }
 176 |     |     }
 177 |     | 
 178 |     |     /**
 179 |     |      * @notice Adding streams with sane defaults should not revert
 180 |     |      * @param fromAccId Account id of the sender
 181 |     |      * @param toAccId Account id of the receiver
 182 |     |      * @param amountPerSec Amount per second for the stream
 183 |     |      * @param startTime Start time for the stream
 184 |     |      * @param duration Duration for the stream
 185 |     |      * @param balanceDelta Amount to update stream balance with
 186 |     |      */
 187 | *   |     function testAddStreamShouldNotRevert(
 188 |     |         uint8 fromAccId,
 189 |     |         uint8 toAccId,
 190 |     |         uint160 amountPerSec,
 191 |     |         uint32 startTime,
 192 |     |         uint32 duration,
 193 |     |         int128 balanceDelta
 194 |     |     ) public {
 195 | *   |         try
 196 | *   |             EchidnaStreamsHelpers(address(this)).addStreamWithClamping(
 197 | *   |                 fromAccId,
 198 | *   |                 toAccId,
 199 | *   |                 amountPerSec,
 200 | *   |                 startTime,
 201 | *   |                 duration,
 202 | *   |                 balanceDelta
 203 |     |             )
 204 |     |         {} catch (bytes memory reason) {
 205 |     |             bytes4 errorSelector = bytes4(reason);
 206 |     |             if (errorSelector == EchidnaStorage.DuplicateError.selector) {
 207 |     |                 // ignore this case, it means we tried to add a duplicate stream
 208 |     |             } else {
 209 |     |                 assert(false);
 210 |     |             }
 211 |     |         }
 212 |     |     }
 213 |     | 
 214 |     |     /*
 215 |     |      * @notice Removing streams should not revert
 216 |     |      * @param targetAccId Account id of the sender
 217 |     |      * @param indexSeed Random seed used to determine which receiver to remove
 218 |     |      */
 219 | *   |     function testRemoveStreamShouldNotRevert(
 220 |     |         uint8 targetAccId,
 221 |     |         uint256 indexSeed
 222 | *   |     ) public {
 223 | *   |         address target = getAccount(targetAccId);
 224 | *r  |         require(getStreamReceivers(target).length > 0);
 225 |     | 
 226 | *   |         try
 227 | *   |             EchidnaStreamsHelpers(address(this)).removeStream(
 228 | *   |                 targetAccId,
 229 | *   |                 indexSeed
 230 |     |             )
 231 |     |         {} catch {
 232 |     |             assert(false);
 233 |     |         }
 234 |     |     }
 235 |     | 
 236 |     |     /**
 237 |     |      * @notice Updating stream balance with sane defaults should not revert
 238 |     |      * @param targetAccId Account id of the sender
 239 |     |      * @param balanceDelta Amount to update stream balance with
 240 |     |      */
 241 | *   |     function testSetStreamBalanceShouldNotRevert(
 242 |     |         uint8 targetAccId,
 243 |     |         int128 balanceDelta
 244 |     |     ) public {
 245 | *   |         try
 246 | *   |             EchidnaStreamsHelpers(address(this)).setStreamBalanceWithClamping(
 247 | *   |                 targetAccId,
 248 | *   |                 balanceDelta
 249 |     |             )
 250 |     |         {} catch {
 251 |     |             assert(false);
 252 |     |         }
 253 |     |     }
 254 |     | 
 255 |     |     /**
 256 |     |      * @notice Withdrawing all stream balance should not revert
 257 |     |      * @param targetAccId Account id of the sender
 258 |     |      */
 259 | *   |     function testSetStreamBalanceWithdrawAllShouldNotRevert(uint8 targetAccId)
 260 |     |         public
 261 |     |     {
 262 | *   |         try
 263 | *   |             EchidnaStreamsHelpers(address(this)).setStreamBalanceWithdrawAll(
 264 | *   |                 targetAccId
 265 |     |             )
 266 |     |         {} catch {
 267 |     |             assert(false);
 268 |     |         }
 269 |     |     }
 270 |     | }
 271 |     | 

/opt/scfuzzbench/work/target/src/echidna/base/EchidnaAccounting.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | 
   3 |     | import "./EchidnaStorage.sol";
   4 |     | 
   5 |     | /**
   6 |     |  * @title Mixin for handling accounting related functions
   7 |     |  * @author Rappie <rappie@perimetersec.io>
   8 |     |  */
   9 |     | contract EchidnaAccounting is EchidnaStorage {
  10 |     |     /**
  11 |     |      * @notice Get the total amount of drips balances for all users
  12 |     |      * @return Total drips balances for all users
  13 |     |      * @dev This is the total amount of drips balances for all users, including
  14 |     |      * the current stream balance, the receivable amount, the collectable
  15 |     |      * amount, the splittable amount, and the squeezable amount.
  16 |     |      */
  17 | *   |     function getDripsBalancesTotalForAllUsers() internal returns (uint256) {
  18 | *   |         uint256 user0Total = getDripsBalancesTotalForUser(ADDRESS_USER0);
  19 | *   |         uint256 user1Total = getDripsBalancesTotalForUser(ADDRESS_USER1);
  20 | *   |         uint256 user2Total = getDripsBalancesTotalForUser(ADDRESS_USER2);
  21 | *   |         uint256 user3Total = getDripsBalancesTotalForUser(ADDRESS_USER3);
  22 |     | 
  23 | *   |         return user0Total + user1Total + user2Total + user3Total;
  24 |     |     }
  25 |     | 
  26 |     |     /**
  27 |     |      * @notice Get the total amount of drips balances for a user
  28 |     |      * @param target The user to query
  29 |     |      * @return Total drips balances for the target user
  30 |     |      * @dev This is the total amount of drips balances for a user, including
  31 |     |      * the current stream balance, the receivable amount, the collectable
  32 |     |      * amount, the splittable amount, and the squeezable amount.
  33 |     |      */
  34 | *   |     function getDripsBalancesTotalForUser(address target)
  35 |     |         internal
  36 | *   |         returns (uint256)
  37 |     |     {
  38 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  39 |     | 
  40 | *   |         uint128 balance = getCurrentStreamBalanceForUser(target);
  41 | *   |         uint128 squeezable = getTotalSqueezableAmountForUser(target);
  42 | *   |         uint128 receivable = getReceivableAmountForUser(target);
  43 | *   |         uint128 collectable = drips.collectable(targetDripsAccId, token);
  44 | *   |         uint128 splittable = drips.splittable(targetDripsAccId, token);
  45 |     | 
  46 | *   |         return balance + squeezable + receivable + collectable + splittable;
  47 |     |     }
  48 |     | 
  49 |     |     /**
  50 |     |      * @notice Get the streamable balance for a user
  51 |     |      * @param target The user to query
  52 |     |      * @param timestamp The point in time to get 'balanceAt' from
  53 |     |      * @return Streamable balance for the target user
  54 |     |      * @dev This is the streamable balance for a user, which is the current
  55 |     |      * stream balance minus the receivable amount.
  56 |     |      */
  57 | *   |     function getStreamBalanceForUser(address target, uint32 timestamp)
  58 |     |         internal
  59 | *   |         returns (uint128)
  60 |     |     {
  61 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
  62 |     | 
  63 | *   |         uint128 balance;
  64 | *   |         try
  65 | *   |             drips.balanceAt(
  66 | *   |                 targetDripsAccId,
  67 | *   |                 token,
  68 | *   |                 getStreamReceivers(target),
  69 | *   |                 timestamp
  70 |     |             )
  71 | *   |         returns (uint128 _balance) {
  72 | *   |             balance = _balance;
  73 |     |         } catch {
  74 |     |             // this should not happen, so put an assert here to be sure
  75 |     |             assert(false);
  76 |     |         }
  77 |     | 
  78 | *   |         return balance;
  79 |     |     }
  80 |     | 
  81 |     |     /**
  82 |     |      * @notice Get the current stream balance for a user
  83 |     |      * @param target The user to query
  84 |     |      * @return Current stream balance for the target user
  85 |     |      */
  86 | *   |     function getCurrentStreamBalanceForUser(address target)
  87 |     |         internal
  88 | *   |         returns (uint128)
  89 |     |     {
  90 | *   |         return getStreamBalanceForUser(target, uint32(block.timestamp));
  91 |     |     }
  92 |     | 
  93 |     |     /**
  94 |     |      * @notice Get the receivable amount for all users
  95 |     |      * @return Receivable amount for all users
  96 |     |      * @dev This is the receivable amount for all users, which means the amount
  97 |     |      * that has already been streamed to the users but not yet collected.
  98 |     |      */
  99 | *   |     function getReceivableAmountForAllUsers() internal returns (uint128) {
 100 | *   |         uint128 receivable;
 101 | *   |         receivable += getReceivableAmountForUser(ADDRESS_USER0);
 102 | *   |         receivable += getReceivableAmountForUser(ADDRESS_USER1);
 103 | *   |         receivable += getReceivableAmountForUser(ADDRESS_USER2);
 104 | *   |         receivable += getReceivableAmountForUser(ADDRESS_USER3);
 105 | *   |         return receivable;
 106 |     |     }
 107 |     | 
 108 |     |     /**
 109 |     |      * @notice Get the receivable amount for a user
 110 |     |      * @param target The user to query
 111 |     |      * @return Receivable amount for the target user
 112 |     |      * @dev This is the receivable amount for a user, which means the amount
 113 |     |      * that has already been streamed to the user but not yet collected.
 114 |     |      */
 115 | *   |     function getReceivableAmountForUser(address target)
 116 |     |         internal
 117 | *   |         returns (uint128)
 118 |     |     {
 119 | *   |         uint128 receivable = drips.receiveStreamsResult(
 120 | *   |             getDripsAccountId(target),
 121 | *   |             token,
 122 | *   |             type(uint32).max
 123 |     |         );
 124 | *   |         return receivable;
 125 |     |     }
 126 |     | 
 127 |     |     /**
 128 |     |      * @notice Get the squeezable amount for all users
 129 |     |      * @param target The user to query
 130 |     |      * @return Squeezable amount for all users
 131 |     |      * @dev This is the squeezable amount for a user, which means the amount
 132 |     |      * that has already been streamed in the current cycle that is not yet
 133 |     |      * receivable.
 134 |     |      */
 135 | *   |     function getTotalSqueezableAmountForUser(address target)
 136 |     |         internal
 137 | *   |         returns (uint128)
 138 |     |     {
 139 | *   |         uint128 amount = 0;
 140 | *   |         amount += getSqueezableAmount(ADDRESS_USER0, target);
 141 | *   |         amount += getSqueezableAmount(ADDRESS_USER1, target);
 142 | *   |         amount += getSqueezableAmount(ADDRESS_USER2, target);
 143 | *   |         amount += getSqueezableAmount(ADDRESS_USER3, target);
 144 |     | 
 145 | *   |         return amount;
 146 |     |     }
 147 |     | 
 148 |     |     /**
 149 |     |      * @notice Get the squeezable amount for a user
 150 |     |      * @param sender The sender of the stream(s)
 151 |     |      * @param receiver The receiver of the stream(s)
 152 |     |      * @return Squeezable amount for the target user
 153 |     |      * @dev This is the squeezable amount for a user, which means the amount
 154 |     |      * that has already been streamed in the current cycle that is not yet
 155 |     |      * receivable.
 156 |     |      */
 157 | *   |     function getSqueezableAmount(address sender, address receiver)
 158 |     |         internal
 159 | *   |         returns (uint128)
 160 |     |     {
 161 | *   |         uint256 senderDripsAccId = getDripsAccountId(sender);
 162 | *   |         uint256 receiverDripsAccId = getDripsAccountId(receiver);
 163 |     | 
 164 | *   |         uint128 amount = drips.squeezeStreamsResult(
 165 | *   |             receiverDripsAccId,
 166 | *   |             token,
 167 | *   |             senderDripsAccId,
 168 | *   |             bytes32(0),
 169 | *   |             getStreamsHistory(sender)
 170 |     |         );
 171 |     | 
 172 | *   |         return amount;
 173 |     |     }
 174 |     | 
 175 |     |     /**
 176 |     |      * @notice Get the 'maxEnd' farthest in the future for all users
 177 |     |      * @return 'maxEnd' fartherst in the future for all users
 178 |     |      * @dev This is the 'maxEnd' farthest in the future for all users, which
 179 |     |      * means the farthest in the future that any stream ends for any user.
 180 |     |      */
 181 | *   |     function getMaxEndForAllUsers() internal returns (uint32) {
 182 | *   |         uint32 maxMaxEnd;
 183 |     | 
 184 | *   |         uint32 maxEndUser0 = getMaxEndForUser(ADDRESS_USER0);
 185 | *   |         if (maxEndUser0 > maxMaxEnd) maxMaxEnd = maxEndUser0;
 186 | *   |         uint32 maxEndUser1 = getMaxEndForUser(ADDRESS_USER1);
 187 | *   |         if (maxEndUser1 > maxMaxEnd) maxMaxEnd = maxEndUser1;
 188 | *   |         uint32 maxEndUser2 = getMaxEndForUser(ADDRESS_USER2);
 189 | *   |         if (maxEndUser2 > maxMaxEnd) maxMaxEnd = maxEndUser2;
 190 | *   |         uint32 maxEndUser3 = getMaxEndForUser(ADDRESS_USER3);
 191 | *   |         if (maxEndUser3 > maxMaxEnd) maxMaxEnd = maxEndUser3;
 192 |     | 
 193 | *   |         return maxMaxEnd;
 194 |     |     }
 195 |     | 
 196 |     |     /**
 197 |     |      * @notice Get the 'maxEnd' for a user
 198 |     |      * @param target The user to query
 199 |     |      * @return The 'maxEnd' for the target user
 200 |     |      */
 201 | *   |     function getMaxEndForUser(address target) internal returns (uint32) {
 202 | *   |         uint256 targetDripsAccId = getDripsAccountId(target);
 203 | *   |         (, , , , uint32 maxEnd) = drips.streamsState(targetDripsAccId, token);
 204 | *   |         return maxEnd;
 205 |     |     }
 206 |     | 
 207 |     |     /**
 208 |     |      * @notice Get the timestamp on which the current cycle started
 209 |     |      * @return Timestamp on which the current cycle started
 210 |     |      */
 211 | *   |     function getCurrentCycleStart() internal returns (uint32) {
 212 | *   |         uint32 currTimestamp = uint32(block.timestamp);
 213 | *   |         return currTimestamp - (currTimestamp % SECONDS_PER_CYCLE);
 214 |     |     }
 215 |     | 
 216 |     |     /**
 217 |     |      * @notice Get the timestamp on which the current cycle ends
 218 |     |      * @return Timestamp on which the current cycle ends
 219 |     |      */
 220 | *   |     function getCurrentCycleEnd() internal returns (uint32) {
 221 | *   |         return getCurrentCycleStart() + SECONDS_PER_CYCLE - 1;
 222 |     |     }
 223 |     | 
 224 |     |     /**
 225 |     |      * @notice Get the cycle number for a given timestamp
 226 |     |      * @param timestamp The timestamp to get the cycle number for
 227 |     |      * @return timestamp Cycle number for the given timestamp
 228 |     |      */
 229 | *   |     function getCycleFromTimestamp(uint256 timestamp)
 230 |     |         internal
 231 | *   |         returns (uint32)
 232 |     |     {
 233 | *   |         return uint32(timestamp / SECONDS_PER_CYCLE + 1);
 234 |     |     }
 235 |     | }
 236 |     | 

/opt/scfuzzbench/work/target/src/echidna/base/EchidnaBase.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | 
  3 |     | import "./EchidnaSetup.sol";
  4 |     | import "./EchidnaStorage.sol";
  5 |     | import "./EchidnaAccounting.sol";
  6 |     | 
  7 |     | /**
  8 |     |  * @title Mixin grouping together all base contracts
  9 |     |  * @author Rappie <rappie@perimetersec.io>
 10 |     |  */
 11 |     | contract EchidnaBase is
 12 |     |     EchidnaSetup,
 13 |     |     EchidnaStorage,
 14 |     |     EchidnaAccounting
 15 |     | {}
 16 |     | 

/opt/scfuzzbench/work/target/src/echidna/base/EchidnaConfig.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | 
  3 |     | import {IERC20, ERC20PresetFixedSupply} from "openzeppelin-contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol";
  4 |     | import {ManagedProxy} from "src/Managed.sol";
  5 |     | import {Drips, SplitsReceiver, StreamReceiver, StreamConfig, StreamConfigImpl, StreamsHistory} from "src/Drips.sol";
  6 |     | import {AddressDriver} from "src/AddressDriver.sol";
  7 |     | 
  8 |     | import {DripsEchidna} from "../tools/DripsEchidna.sol";
  9 |     | import {AddressDriverEchidna} from "../tools/AddressDriverEchidna.sol";
 10 |     | 
 11 |     | import "../tools/Debugger.sol";
 12 |     | 
 13 |     | /**
 14 |     |  * @title Mixin containing the configuration for the fuzzing campaign
 15 |     |  * @author Rappie <rappie@perimetersec.io>
 16 |     |  */
 17 |     | contract EchidnaConfig {
 18 |     |     // Addresses used for the simulated users
 19 | *   |     address internal constant ADDRESS_USER0 = address(0x10000);
 20 | *   |     address internal constant ADDRESS_USER1 = address(0x20000);
 21 | *   |     address internal constant ADDRESS_USER2 = address(0x30000);
 22 | *   |     address internal constant ADDRESS_USER3 = address(0x40000);
 23 |     | 
 24 |     |     // Mappings from address to account id
 25 |     |     mapping(address => uint8) internal ADDRESS_TO_ACCOUNT_ID;
 26 |     |     mapping(address => uint256) internal ADDRESS_TO_DRIPS_ACCOUNT_ID;
 27 |     | 
 28 |     |     // Variable to store the timestamp when fuzzing starts
 29 |     |     uint256 internal STARTING_TIMESTAMP;
 30 |     | 
 31 |     |     // Starting token balance of the simulated users
 32 | *   |     uint256 internal constant STARTING_BALANCE = 1_000_000_000e18;
 33 |     | 
 34 |     |     // Amount of seconds in a Drips cycle
 35 | *   |     uint32 internal constant SECONDS_PER_CYCLE = 10;
 36 |     | 
 37 |     |     // Buffers to be used as fuzzing boundaries
 38 | *   |     uint32 internal constant CYCLE_FUZZING_BUFFER_CYCLES = 10;
 39 |     |     uint32 internal constant CYCLE_FUZZING_BUFFER_SECONDS =
 40 | *   |         CYCLE_FUZZING_BUFFER_CYCLES * SECONDS_PER_CYCLE;
 41 |     | 
 42 |     |     // Maximum amount of streamable funds per second that make sense based
 43 |     |     // on the starting balance of the simulated users
 44 |     |     uint160 internal constant MAX_AMOUNT_PER_SEC =
 45 | *   |         (uint160(STARTING_BALANCE) / uint160(SECONDS_PER_CYCLE)) * 1e9;
 46 |     | 
 47 |     |     // Sensible maximum amount of seconds for a stream
 48 |     |     uint32 internal constant MAX_STREAM_DURATION = CYCLE_FUZZING_BUFFER_SECONDS;
 49 |     | 
 50 |     |     // Due to the inner workings of the splitting algorithm Drips uses,
 51 |     |     // it is unpredictable wether a split will be rounded up or down. To
 52 |     |     // remedy this, allow a tolerance for the expected split amount.
 53 | *   |     uint256 internal constant SPLIT_ROUNDING_TOLERANCE = 1;
 54 |     | 
 55 |     |     // Toggles for certain tests
 56 |     |     bool internal constant TOGGLE_EXPERIMENTAL_TESTS_ENABLED = true;
 57 | *   |     bool internal constant TOGGLE_HEAVY_TESTS_ENABLED = true;
 58 | *   |     bool internal constant TOGGLE_MAXENDHINTS_ENABLED = true;
 59 |     | 
 60 |     |     // Modifier to toggle experimental tests
 61 |     |     modifier experimental() {
 62 |     |         if (!TOGGLE_EXPERIMENTAL_TESTS_ENABLED) return;
 63 |     |         _;
 64 |     |     }
 65 |     | 
 66 |     |     // Modifier to toggle performance heavy tests
 67 |     |     modifier heavy() {
 68 | *   |         if (!TOGGLE_HEAVY_TESTS_ENABLED) return;
 69 |     |         _;
 70 |     |     }
 71 |     | 
 72 |     |     constructor() {
 73 | *   |         ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER0] = 0;
 74 | *   |         ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER1] = 64;
 75 | *   |         ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER2] = 128;
 76 | *   |         ADDRESS_TO_ACCOUNT_ID[ADDRESS_USER3] = 192;
 77 |     |     }
 78 |     | 
 79 |     |     /*
 80 |     |      * @notice Get the address for a certain account id
 81 |     |      * @param rawId The raw account id
 82 |     |      * @return The address for the account id
 83 |     |      * @dev In this case we have 4 users, spread over the range of 256 (8 bits).
 84 |     |      */
 85 | *   |     function getAccount(uint8 rawId) internal pure returns (address) {
 86 | *   |         uint256 id = uint256(rawId) / 64;
 87 |     | 
 88 | *   |         if (id == 0) return ADDRESS_USER0;
 89 | *   |         if (id == 1) return ADDRESS_USER1;
 90 | *   |         if (id == 2) return ADDRESS_USER2;
 91 | *   |         if (id == 3) return ADDRESS_USER3;
 92 |     | 
 93 |     |         require(false, "Unknown account ID");
 94 |     |     }
 95 |     | }
 96 |     | 

/opt/scfuzzbench/work/target/src/echidna/base/EchidnaSetup.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | 
  3 |     | import "../tools/IHevm.sol";
  4 |     | import "./EchidnaConfig.sol";
  5 |     | 
  6 |     | /**
  7 |     |  * @title Mixin containing the deployment and setup
  8 |     |  * @author Rappie <rappie@perimetersec.io>
  9 |     |  */
 10 |     | contract EchidnaSetup is EchidnaConfig {
 11 | *   |     IHevm hevm = IHevm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
 12 |     | 
 13 |     |     ERC20PresetFixedSupply token;
 14 |     |     DripsEchidna drips;
 15 |     |     AddressDriverEchidna driver;
 16 |     | 
 17 | *   |     constructor() EchidnaConfig() {
 18 |     |         // Deploy ERC20 token
 19 | *   |         token = new ERC20PresetFixedSupply(
 20 |     |             "Test Token",
 21 |     |             "TEST",
 22 | *   |             STARTING_BALANCE * 4,
 23 | *   |             address(this)
 24 |     |         );
 25 |     | 
 26 |     |         // Deploy Drips
 27 | *   |         drips = new DripsEchidna(SECONDS_PER_CYCLE);
 28 | *   |         drips.unpause_noModifiers();
 29 |     | 
 30 |     |         // Deploy AddressDriver
 31 | *   |         uint32 driverId = drips.registerDriver(address(this));
 32 | *   |         driver = new AddressDriverEchidna(
 33 | *   |             drips,
 34 | *   |             address(0),
 35 | *   |             driverId
 36 |     |         );
 37 | *   |         driver.unpause_noModifiers();
 38 | *   |         drips.updateDriverAddress(driverId, address(driver));
 39 |     | 
 40 |     |         // Set up token balances
 41 | *   |         token.transfer(ADDRESS_USER0, STARTING_BALANCE);
 42 | *   |         hevm.prank(ADDRESS_USER0);
 43 | *   |         token.approve(address(driver), type(uint256).max);
 44 | *   |         token.transfer(ADDRESS_USER1, STARTING_BALANCE);
 45 | *   |         hevm.prank(ADDRESS_USER1);
 46 | *   |         token.approve(address(driver), type(uint256).max);
 47 | *   |         token.transfer(ADDRESS_USER2, STARTING_BALANCE);
 48 | *   |         hevm.prank(ADDRESS_USER2);
 49 | *   |         token.approve(address(driver), type(uint256).max);
 50 | *   |         token.transfer(ADDRESS_USER3, STARTING_BALANCE);
 51 | *   |         hevm.prank(ADDRESS_USER3);
 52 | *   |         token.approve(address(driver), type(uint256).max);
 53 |     | 
 54 |     |         // Store starting timestamp
 55 | *   |         STARTING_TIMESTAMP = block.timestamp;
 56 |     |     }
 57 |     | }
 58 |     | 

/opt/scfuzzbench/work/target/src/echidna/base/EchidnaStorage.sol
   1 |     | // SPDX-License-Identifier: MIT
   2 |     | import "./EchidnaSetup.sol";
   3 |     | 
   4 |     | /**
   5 |     |  * @title Mixin for storing stream receivers and streams history
   6 |     |  * @author Rappie <rappie@perimetersec.io>
   7 |     |  */
   8 |     | contract EchidnaStorage is EchidnaSetup {
   9 |     |     error DuplicateError();
  10 |     | 
  11 |     |     // Mapping from address to current stream receivers
  12 |     |     mapping(address => StreamReceiver[]) internal userToStreamReceivers;
  13 |     | 
  14 |     |     // Mappings from address to full streams history and hashes
  15 |     |     mapping(address => StreamsHistory[]) internal userToStreamsHistory;
  16 |     |     mapping(address => bytes32[]) internal userToStreamsHistoryHashes;
  17 |     | 
  18 |     |     // Mapping from address to current splits receivers
  19 |     |     mapping(address => SplitsReceiver[]) internal userToSplitsReceivers;
  20 |     | 
  21 |     |     /**
  22 |     |      * @notice Update the stream receivers for a given account.
  23 |     |      * @param sender Account to update
  24 |     |      * @param receivers New stream receivers
  25 |     |      * @dev This function will generate a new hash for the stream receivers,
  26 |     |      * update the stream receivers for the given account, and add a new entry
  27 |     |      * to the streams history and streams history hashes for the given
  28 |     |      * account. This is stored for later use.
  29 |     |      */
  30 | *   |     function updateStreamReceivers(
  31 |     |         address sender,
  32 |     |         StreamReceiver[] memory receivers
  33 | *   |     ) internal {
  34 |     |         // Hash the new stream receivers
  35 | *   |         bytes32 receiversHash = drips.hashStreams(receivers);
  36 |     | 
  37 |     |         // Update the stream receivers for 'sender'
  38 | *   |         delete userToStreamReceivers[sender];
  39 | *   |         for (uint256 i = 0; i < receivers.length; i++) {
  40 | *   |             userToStreamReceivers[sender].push(receivers[i]);
  41 |     |         }
  42 |     | 
  43 |     |         // Add a new entry to the streams history
  44 | *   |         uint256 nextIndex = userToStreamsHistory[sender].length;
  45 | *   |         userToStreamsHistory[sender].push();
  46 | *   |         userToStreamsHistory[sender][nextIndex].streamsHash = bytes32(0);
  47 | *   |         for (uint256 i = 0; i < receivers.length; i++) {
  48 | *   |             userToStreamsHistory[sender][nextIndex].receivers.push(
  49 | *   |                 receivers[i]
  50 |     |             );
  51 |     |         }
  52 | *   |         (, , uint32 updateTime, , uint32 maxEnd) = drips.streamsState(
  53 | *   |             getDripsAccountId(sender),
  54 | *   |             token
  55 |     |         );
  56 | *   |         userToStreamsHistory[sender][nextIndex].updateTime = updateTime;
  57 | *   |         userToStreamsHistory[sender][nextIndex].maxEnd = maxEnd;
  58 |     | 
  59 |     |         // Generate starting hash. If there is no previous history, use 0
  60 | *   |         bytes32 startingHash;
  61 | *   |         if (nextIndex == 0) {
  62 | *   |             startingHash = bytes32(0);
  63 |     |         } else {
  64 | *   |             startingHash = userToStreamsHistoryHashes[sender][nextIndex - 1];
  65 |     |         }
  66 |     | 
  67 |     |         // Add new entry to the streams history hashes
  68 | *   |         bytes32 historyHash = drips.hashStreamsHistory(
  69 | *   |             startingHash,
  70 | *   |             receiversHash,
  71 | *   |             updateTime,
  72 | *   |             maxEnd
  73 |     |         );
  74 | *   |         userToStreamsHistoryHashes[sender].push(historyHash);
  75 |     |     }
  76 |     | 
  77 |     |     /**
  78 |     |      * @notice Update the splits receivers for a given account.
  79 |     |      * @param sender Account to update
  80 |     |      * @param receivers New splits receivers
  81 |     |      */
  82 | *   |     function updateSplitsReceivers(
  83 |     |         address sender,
  84 |     |         SplitsReceiver[] memory receivers
  85 |     |     ) internal {
  86 | *   |         delete userToSplitsReceivers[sender];
  87 | *   |         for (uint256 i = 0; i < receivers.length; i++) {
  88 | *   |             userToSplitsReceivers[sender].push(receivers[i]);
  89 |     |         }
  90 |     |     }
  91 |     | 
  92 |     |     /**
  93 |     |      * @notice Get the stream receivers for a given account.
  94 |     |      * @param sender Account to get stream receivers for
  95 |     |      * @return Stream receivers for the given account
  96 |     |      */
  97 | *   |     function getStreamReceivers(address sender)
  98 |     |         internal
  99 | *   |         returns (StreamReceiver[] memory)
 100 |     |     {
 101 | *   |         return userToStreamReceivers[sender];
 102 |     |     }
 103 |     | 
 104 |     |     /**
 105 |     |      * @notice Get the streams history for a given account.
 106 |     |      * @param sender Account to get streams history for
 107 |     |      * @return Streams history for the given account
 108 |     |      */
 109 | *   |     function getStreamsHistory(address sender)
 110 |     |         internal
 111 | *   |         returns (StreamsHistory[] memory)
 112 |     |     {
 113 | *   |         return userToStreamsHistory[sender];
 114 |     |     }
 115 |     | 
 116 |     |     /**
 117 |     |      * @notice Get the streams history hashes for a given account.
 118 |     |      * @param sender Account to get streams history hashes for
 119 |     |      * @return Streams history hashes for the given account
 120 |     |      */
 121 | *   |     function getStreamsHistoryHashes(address sender)
 122 |     |         internal
 123 | *   |         returns (bytes32[] memory)
 124 |     |     {
 125 | *   |         return userToStreamsHistoryHashes[sender];
 126 |     |     }
 127 |     | 
 128 |     |     /**
 129 |     |      * @notice Get the splits receivers for a given account.
 130 |     |      * @param sender Account to get splits receivers for
 131 |     |      * @return Splits receivers for the given account
 132 |     |      */
 133 | *   |     function getSplitsReceivers(address sender)
 134 |     |         internal
 135 | *   |         returns (SplitsReceiver[] memory)
 136 |     |     {
 137 | *   |         return userToSplitsReceivers[sender];
 138 |     |     }
 139 |     | 
 140 |     |     /**
 141 |     |      * @notice Sort the stream receivers.
 142 |     |      * @param unsorted Unsorted stream receivers
 143 |     |      * @return Sorted stream receivers
 144 |     |      * @dev This function will sort the stream receivers by account ID,
 145 |     |      * then by config, then by stream ID. It will revert if there are
 146 |     |      * duplicate stream receivers.
 147 |     |      */
 148 | *   |     function bubbleSortStreamReceivers(StreamReceiver[] memory unsorted)
 149 |     |         internal
 150 | *   |         returns (StreamReceiver[] memory)
 151 |     |     {
 152 | *   |         uint256 n = unsorted.length;
 153 | *   |         if (n <= 1) return unsorted;
 154 |     | 
 155 | *   |         StreamReceiver[] memory sorted = unsorted;
 156 | *   |         for (uint256 i = 0; i < n - 1; i++) {
 157 | *   |             for (uint256 j = 0; j < n - i - 1; j++) {
 158 | *   |                 if (bubbleSortStreamReceiverGT(sorted[j], sorted[j + 1])) {
 159 | *   |                     StreamReceiver memory temp = sorted[j];
 160 | *   |                     sorted[j] = sorted[j + 1];
 161 | *   |                     sorted[j + 1] = temp;
 162 |     |                 }
 163 |     |             }
 164 |     |         }
 165 | *   |         return sorted;
 166 |     |     }
 167 |     | 
 168 |     |     /**
 169 |     |      * @notice Sort the splits receivers.
 170 |     |      * @param unsorted Unsorted splits receivers
 171 |     |      * @return Sorted splits receivers
 172 |     |      */
 173 | *   |     function bubbleSortSplitsReceivers(SplitsReceiver[] memory unsorted)
 174 |     |         internal
 175 | *   |         returns (SplitsReceiver[] memory)
 176 |     |     {
 177 | *   |         uint256 n = unsorted.length;
 178 | *   |         if (n <= 1) return unsorted;
 179 |     | 
 180 | *   |         SplitsReceiver[] memory sorted = unsorted;
 181 | *   |         for (uint256 i = 0; i < n - 1; i++) {
 182 | *   |             for (uint256 j = 0; j < n - i - 1; j++) {
 183 | *   |                 if (bubbleSortSplitsReceiverGT(sorted[j], sorted[j + 1])) {
 184 | *   |                     SplitsReceiver memory temp = sorted[j];
 185 | *   |                     sorted[j] = sorted[j + 1];
 186 | *   |                     sorted[j + 1] = temp;
 187 |     |                 }
 188 |     |             }
 189 |     |         }
 190 | *   |         return sorted;
 191 |     |     }
 192 |     | 
 193 |     |     /**
 194 |     |      * @notice Compare two stream receivers.
 195 |     |      * @param a First stream receiver
 196 |     |      * @param b Second stream receiver
 197 |     |      * @return True if `a` is greater than `b`, false otherwise
 198 |     |      * @dev This function will compare two stream receivers by account ID,
 199 |     |      * then by config. It will revert if there are duplicate stream receivers.
 200 |     |      */
 201 | *   |     function bubbleSortStreamReceiverGT(
 202 |     |         StreamReceiver memory a,
 203 |     |         StreamReceiver memory b
 204 | *   |     ) internal returns (bool) {
 205 | *   |         if (a.accountId != b.accountId) {
 206 | *   |             return a.accountId > b.accountId;
 207 |     |         }
 208 | *   |         if (StreamConfig.unwrap(a.config) != StreamConfig.unwrap(b.config)) {
 209 | *   |             return
 210 | *   |                 StreamConfig.unwrap(a.config) > StreamConfig.unwrap(b.config);
 211 |     |         }
 212 | *r  |         revert DuplicateError();
 213 |     |     }
 214 |     | 
 215 |     |     /**
 216 |     |      * @notice Compare two splits receivers.
 217 |     |      * @param a First splits receiver
 218 |     |      * @param b Second splits receiver
 219 |     |      * @return True if `a` is greater than `b`, false otherwise
 220 |     |      * @dev This function will compare two splits receivers by account ID.
 221 |     |      * It will revert if there are duplicate splits receivers.
 222 |     |      */
 223 | *   |     function bubbleSortSplitsReceiverGT(
 224 |     |         SplitsReceiver memory a,
 225 |     |         SplitsReceiver memory b
 226 | *   |     ) internal returns (bool) {
 227 | *   |         if (a.accountId != b.accountId) {
 228 | *   |             return a.accountId > b.accountId;
 229 |     |         }
 230 | *r  |         revert DuplicateError();
 231 |     |     }
 232 |     | 
 233 |     |     /**
 234 |     |      * @notice Get the drips account ID for a given address.
 235 |     |      * @param account Address to get drips account ID for
 236 |     |      * @return Drips account ID for the given address
 237 |     |      * @dev Caches the value to increase performance
 238 |     |      */
 239 | *   |     function getDripsAccountId(address account) internal returns (uint256) {
 240 | *   |         if (ADDRESS_TO_DRIPS_ACCOUNT_ID[account] == 0) {
 241 | *   |             ADDRESS_TO_DRIPS_ACCOUNT_ID[account] = driver.calcAccountId(
 242 | *   |                 account
 243 |     |             );
 244 |     |         }
 245 | *   |         return ADDRESS_TO_DRIPS_ACCOUNT_ID[account];
 246 |     |     }
 247 |     | }
 248 |     | 

/opt/scfuzzbench/work/target/src/echidna/tools/AddressDriverEchidna.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | import {AddressDriver} from "src/AddressDriver.sol";
  3 |     | 
  4 |     | import {DripsEchidna} from "./DripsEchidna.sol";
  5 |     | import {ManagedEchidna} from "./ManagedEchidna.sol";
  6 |     | 
  7 |     | /**
  8 |     |  * @title Wrapper around AddressDriver with minor fuzzing helpers
  9 |     |  * @author Rappie <rappie@perimetersec.io>
 10 |     |  */
 11 | *   | contract AddressDriverEchidna is AddressDriver, ManagedEchidna {
 12 | *   |     constructor(
 13 |     |         DripsEchidna drips_,
 14 |     |         address forwarder,
 15 |     |         uint32 driverId_
 16 | *   |     ) AddressDriver(drips_, forwarder, driverId_) {}
 17 |     | }
 18 |     | 

/opt/scfuzzbench/work/target/src/echidna/tools/Debugger.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | 
  3 |     | library Debugger {
  4 |     |     event Debug(string debugString);
  5 |     |     event Debug(string description, string data);
  6 |     |     event Debug(string prefix, string description, string data);
  7 |     |     event Debug(string description, bytes32 data);
  8 |     |     event Debug(string prefix, string description, bytes32 data);
  9 |     |     event Debug(string description, uint256 data);
 10 |     |     event Debug(string prefix, string description, uint256 data);
 11 |     |     event Debug(string description, int256 data);
 12 |     |     event Debug(string prefix, string description, int256 data);
 13 |     |     event Debug(string description, address data);
 14 |     |     event Debug(string prefix, string description, address data);
 15 |     |     event Debug(string description, bool data);
 16 |     |     event Debug(string prefix, string description, bool data);
 17 |     | 
 18 |     |     function log(string memory debugString) internal {
 19 |     |         emit Debug(debugString);
 20 |     |     }
 21 |     | 
 22 |     |     function log(string memory description, string memory data) internal {
 23 |     |         emit Debug(description, data);
 24 |     |     }
 25 |     | 
 26 |     |     function log(
 27 |     |         string memory prefix,
 28 |     |         string memory description,
 29 |     |         string memory data
 30 |     |     ) internal {
 31 |     |         emit Debug(prefix, description, data);
 32 |     |     }
 33 |     | 
 34 |     |     function log(string memory description, bytes32 data) internal {
 35 |     |         emit Debug(description, data);
 36 |     |     }
 37 |     | 
 38 |     |     function log(
 39 |     |         string memory prefix,
 40 |     |         string memory description,
 41 |     |         bytes32 data
 42 |     |     ) internal {
 43 |     |         emit Debug(prefix, description, data);
 44 |     |     }
 45 |     | 
 46 |     |     function log(string memory description, uint256 data) internal {
 47 |     |         emit Debug(description, data);
 48 |     |     }
 49 |     | 
 50 |     |     function log(
 51 |     |         string memory prefix,
 52 |     |         string memory description,
 53 |     |         uint256 data
 54 |     |     ) internal {
 55 |     |         emit Debug(prefix, description, data);
 56 |     |     }
 57 |     | 
 58 |     |     function log(string memory description, int256 data) internal {
 59 |     |         emit Debug(description, data);
 60 |     |     }
 61 |     | 
 62 |     |     function log(
 63 |     |         string memory prefix,
 64 |     |         string memory description,
 65 |     |         int256 data
 66 |     |     ) internal {
 67 |     |         emit Debug(prefix, description, data);
 68 |     |     }
 69 |     | 
 70 |     |     function log(string memory description, address data) internal {
 71 |     |         emit Debug(description, data);
 72 |     |     }
 73 |     | 
 74 |     |     function log(
 75 |     |         string memory prefix,
 76 |     |         string memory description,
 77 |     |         address data
 78 |     |     ) internal {
 79 |     |         emit Debug(prefix, description, data);
 80 |     |     }
 81 |     | 
 82 |     |     function log(string memory description, bool data) internal {
 83 |     |         emit Debug(description, data);
 84 |     |     }
 85 |     | 
 86 |     |     function log(
 87 |     |         string memory prefix,
 88 |     |         string memory description,
 89 |     |         bool data
 90 |     |     ) internal {
 91 |     |         emit Debug(prefix, description, data);
 92 |     |     }
 93 |     | }
 94 |     | 

/opt/scfuzzbench/work/target/src/echidna/tools/DripsEchidna.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | import {IERC20} from "openzeppelin-contracts/token/ERC20/utils/SafeERC20.sol";
  3 |     | import {Drips} from "src/Drips.sol";
  4 |     | 
  5 |     | import {ManagedEchidna} from "./ManagedEchidna.sol";
  6 |     | 
  7 |     | /**
  8 |     |  * @title Wrapper around Drips with minor fuzzing helpers
  9 |     |  * @author Rappie <rappie@perimetersec.io>
 10 |     |  */
 11 | *   | contract DripsEchidna is Drips, ManagedEchidna {
 12 | *   |     constructor(uint32 cycleSecs_) Drips(cycleSecs_) {}
 13 |     | 
 14 |     |     /**
 15 |     |      * @notice Get the amtDelta for a given user and cycle
 16 |     |      * @param accountId The account to get the amtDelta for
 17 |     |      * @param erc20 The ERC20 token
 18 |     |      * @param cycle The cycle to get the amtDelta for
 19 |     |      * @return The amtDelta for this cycle and the next cycle
 20 |     |      */
 21 | *   |     function getAmtDeltaForCycle(
 22 |     |         uint256 accountId,
 23 |     |         IERC20 erc20,
 24 |     |         uint32 cycle
 25 | *   |     ) public view returns (int128, int128) {
 26 |     |         // Manually calculate the storage slot because it is a private variable
 27 |     |         // in Streams
 28 | *   |         StreamsStorage storage streamsStorage;
 29 | *   |         bytes32 slot = _erc1967Slot("eip1967.streams.storage");
 30 |     |         assembly {
 31 | *   |             streamsStorage.slot := slot
 32 |     |         }
 33 |     | 
 34 |     |         // Return the amtDelta for the given cycle
 35 | *   |         StreamsState storage state = streamsStorage.states[erc20][accountId];
 36 | *   |         mapping(uint32 cycle => AmtDelta) storage amtDeltas = state.amtDeltas;
 37 | *   |         return (amtDeltas[cycle].thisCycle, amtDeltas[cycle].nextCycle);
 38 |     |     }
 39 |     | }
 40 |     | 

/opt/scfuzzbench/work/target/src/echidna/tools/IHevm.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | 
  3 |     | // https://github.com/ethereum/hevm/blob/main/doc/src/controlling-the-unit-testing-environment.md#cheat-codes
  4 |     | 
  5 |     | interface IHevm {
  6 |     |     function warp(uint256 x) external;
  7 |     | 
  8 |     |     function roll(uint256 x) external;
  9 |     | 
 10 |     |     function store(
 11 |     |         address c,
 12 |     |         bytes32 loc,
 13 |     |         bytes32 val
 14 |     |     ) external;
 15 |     | 
 16 |     |     function load(address c, bytes32 loc) external returns (bytes32 val);
 17 |     | 
 18 |     |     function sign(uint256 sk, bytes32 digest)
 19 |     |         external
 20 |     |         returns (
 21 |     |             uint8 v,
 22 |     |             bytes32 r,
 23 |     |             bytes32 s
 24 |     |         );
 25 |     | 
 26 |     |     function addr(uint256 sk) external returns (address addr);
 27 |     | 
 28 |     |     function ffi(string[] calldata) external returns (bytes memory);
 29 |     | 
 30 |     |     function prank(address sender) external;
 31 |     | }
 32 |     | 

/opt/scfuzzbench/work/target/src/echidna/tools/ManagedEchidna.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | import {Managed} from "src/Managed.sol";
  3 |     | 
  4 |     | /**
  5 |     |  * @title Wrapper around Managed with minor fuzzing helpers
  6 |     |  * @author Rappie <rappie@perimetersec.io>
  7 |     |  */
  8 |     | contract ManagedEchidna is Managed {
  9 |     |     constructor() Managed() {}
 10 |     | 
 11 |     |     /**
 12 |     |      * @notice Helper function to unpause the contract as any user
 13 |     |      */
 14 | *   |     function unpause_noModifiers() public {
 15 | *   |         _managedStorage().isPaused = false;
 16 | *   |         emit Unpaused(msg.sender);
 17 |     |     }
 18 |     | }
 19 |     | 

/opt/scfuzzbench/work/target/test/recon/CryticTester.sol
 1 |     | // SPDX-License-Identifier: MIT
 2 |     | pragma solidity ^0.8.20;
 3 |     | 
 4 |     | import {Properties} from "./Properties.sol";
 5 |     | 
 6 |     | // echidna test/recon/CryticTester.sol --contract CryticTester --config echidna.yaml
 7 | *r  | contract CryticTester is Properties {}
 8 |     | 

/opt/scfuzzbench/work/target/test/recon/Properties.sol
  1 |     | // SPDX-License-Identifier: MIT
  2 |     | pragma solidity ^0.8.20;
  3 |     | 
  4 |     | import {Echidna} from "src/echidna/Echidna.sol";
  5 |     | 
  6 |     | /// @notice scfuzzbench adaptation layer: canary checks on top of the
  7 |     | /// Perimeter Drips fuzzing suite. Assertion failures are surfaced the same
  8 |     | /// way for Echidna, Medusa, Foundry, and Recon (AssertionFailed event +
  9 |     | /// assert), and dedup to the emitting function name across fuzzers.
 10 |     | abstract contract Properties is Echidna {
 11 |     |     string internal constant ASSERTION_CANARY = "!!! canary assertion";
 12 |     |     string internal constant INVARIANT_CANARY_GLOBAL_INVARIANT_FAILURE = "Canary invariant";
 13 |     | 
 14 |     |     event AssertionFailed(string reason);
 15 |     | 
 16 | *   |     function t(bool b, string memory reason) internal {
 17 | *   |         if (!b) {
 18 | *   |             emit AssertionFailed(reason);
 19 | *   |             assert(false);
 20 |     |         }
 21 |     |     }
 22 |     | 
 23 | *   |     function invariant_canary() public returns (bool) {
 24 | *   |         t(false, INVARIANT_CANARY_GLOBAL_INVARIANT_FAILURE);
 25 |     |         return true;
 26 |     |     }
 27 |     | 
 28 | *   |     function assert_canary_ASSERTION_CANARY(uint256 entropy) public {
 29 | *   |         t(entropy > 0, ASSERTION_CANARY);
 30 |     |     }
 31 |     | }
 32 |     | 

